diff --git a/app/build.gradle b/app/build.gradle index 34889d2e..116370f4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -249,7 +249,7 @@ dependencies { //MarkdownView:https://github.com/tiagohm/MarkdownView implementation 'com.github.tiagohm.MarkdownView:library:0.19.0' - implementation 'com.github.tiagohm.MarkdownView:emoji:0.19.0' + //implementation 'com.github.tiagohm.MarkdownView:emoji:0.19.0' def retrofit2_version = '2.9.0' implementation "com.squareup.retrofit2:retrofit:$retrofit2_version" diff --git a/app/src/androidTest/java/com/idormy/sms/forwarder/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/idormy/sms/forwarder/ExampleInstrumentedTest.kt deleted file mode 100644 index 02b5e3a6..00000000 --- a/app/src/androidTest/java/com/idormy/sms/forwarder/ExampleInstrumentedTest.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2022 xuexiangjys(xuexiangjys@163.com) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package com.idormy.sms.forwarder - -import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.platform.app.InstrumentationRegistry -import org.junit.Assert -import org.junit.Test -import org.junit.runner.RunWith - -/** - * Instrumented test, which will execute on an Android device. - * - * @see [Testing documentation](http://d.android.com/tools/testing) - */ -@RunWith(AndroidJUnit4::class) -class ExampleInstrumentedTest { - @Test - fun useAppContext() { - // Context of the app under test. - val appContext = InstrumentationRegistry.getInstrumentation().targetContext - Assert.assertEquals("com.idormy.sms.forwarder", appContext.packageName) - } -} \ No newline at end of file diff --git a/app/src/main/assets/tips.json b/app/src/main/assets/tips.json index 5a77023d..f0a67e6e 100644 --- a/app/src/main/assets/tips.json +++ b/app/src/main/assets/tips.json @@ -1,17 +1,17 @@ -{ - "Code": 0, - "Data": [ - { - "title": "新用户必读", - "content": "开始设置之前,请您认真地看一遍 Wiki
\n遇到问题,请按照 常见问题 章节进行排查!
\n没找到答案的,再加入QQ互助交流群里提问,请清楚地描述问题,并给出对应的配置截图与相关日志,方便大家直观的判断问题! " - }, - { - "title": "QQ互助交流群", - "content": "QQ互助交流①群
QQ互助交流②群
QQ互助交流③群
QQ互助交流④群
QQ互助交流⑤群" - }, - { - "title": "打赏名单", - "content": "感谢热心网友们对开源项目的喜爱和支持!查看赞助名单!" - } - ] -} +{ + "Code": 0, + "Data": [ + { + "title": "新用户必读", + "content": "开始设置之前,请您认真地看一遍 Wiki
\n遇到问题,请按照 常见问题 章节进行排查!
\n没找到答案的,再加入QQ互助交流群里提问,请清楚地描述问题,并给出对应的配置截图与相关日志,方便大家直观的判断问题! " + }, + { + "title": "互助交流群", + "content": "QQ互助交流①群
QQ互助交流②群
QQ互助交流③群
QQ互助交流④群
QQ互助交流⑤群" + }, + { + "title": "打赏名单", + "content": "感谢热心网友们对开源项目的喜爱和支持!查看赞助名单!" + } + ] +} diff --git a/app/src/main/java/com/idormy/sms/forwarder/App.kt b/app/src/main/java/com/idormy/sms/forwarder/App.kt index eeb84289..43532b0d 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/App.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/App.kt @@ -40,7 +40,6 @@ import java.text.SimpleDateFormat import java.util.* import java.util.concurrent.TimeUnit -@Suppress("PrivatePropertyName") class App : Application(), CactusCallback, Configuration.Provider by Core { val applicationScope = CoroutineScope(SupervisorJob()) diff --git a/app/src/main/java/com/idormy/sms/forwarder/activity/MainActivity.kt b/app/src/main/java/com/idormy/sms/forwarder/activity/MainActivity.kt index 6f148688..d92adfe6 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/activity/MainActivity.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/activity/MainActivity.kt @@ -59,7 +59,6 @@ import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers import java.io.File - @Suppress("DEPRECATION", "PrivatePropertyName") class MainActivity : BaseActivity(), View.OnClickListener, diff --git a/app/src/main/java/com/idormy/sms/forwarder/adapter/LogsPagingAdapter.kt b/app/src/main/java/com/idormy/sms/forwarder/adapter/LogsPagingAdapter.kt index e8c1c78a..4e448663 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/adapter/LogsPagingAdapter.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/adapter/LogsPagingAdapter.kt @@ -12,6 +12,7 @@ import com.idormy.sms.forwarder.database.entity.LogsAndRuleAndSender import com.idormy.sms.forwarder.databinding.AdapterLogsCardViewListItemBinding import com.xuexiang.xutil.data.DateUtils +@Suppress("unused") class LogsPagingAdapter(private val itemClickListener: OnItemClickListener) : PagingDataAdapter(diffCallback) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { diff --git a/app/src/main/java/com/idormy/sms/forwarder/adapter/base/delegate/XDelegateAdapter.kt b/app/src/main/java/com/idormy/sms/forwarder/adapter/base/delegate/XDelegateAdapter.kt index 1b4dfaba..fd726850 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/adapter/base/delegate/XDelegateAdapter.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/adapter/base/delegate/XDelegateAdapter.kt @@ -36,7 +36,7 @@ abstract class XDelegateAdapter : DelegateAdapt } constructor(data: Array?) { - if (data != null && data.isNotEmpty()) { + if (!data.isNullOrEmpty()) { mData.addAll(listOf(*data)) } } @@ -180,7 +180,7 @@ abstract class XDelegateAdapter : DelegateAdapt */ @SuppressLint("NotifyDataSetChanged") fun refresh(array: Array?): XDelegateAdapter<*, *> { - if (array != null && array.isNotEmpty()) { + if (!array.isNullOrEmpty()) { mData.clear() mData.addAll(listOf(*array)) selectPosition = -1 @@ -212,7 +212,7 @@ abstract class XDelegateAdapter : DelegateAdapt */ @SuppressLint("NotifyDataSetChanged") fun loadMore(array: Array?): XDelegateAdapter<*, *> { - if (array != null && array.isNotEmpty()) { + if (!array.isNullOrEmpty()) { mData.addAll(listOf(*array)) notifyDataSetChanged() } diff --git a/app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/AppListAdapterItem.kt b/app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/AppListAdapterItem.kt index eddfba29..63a21a18 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/AppListAdapterItem.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/AppListAdapterItem.kt @@ -1,45 +1,40 @@ -package com.idormy.sms.forwarder.adapter.spinner - -import android.graphics.drawable.Drawable -import com.xuexiang.xui.utils.ResUtils - -@Suppress("unused") -class AppListAdapterItem { - - var name: String = "" - var icon: Drawable? = null - var packageName: String? = null - //var packagePath: String? = null - //var versionName: String? = null - //var versionCode: Int = 0 - //var isSystem: Boolean = false - - - constructor(name: String, icon: Drawable?, packageName: String?) { - this.name = name - this.icon = icon - this.packageName = packageName - } - - constructor(name: String) : this(name, null, null) - constructor(name: String, drawableId: Int, packageName: String) : this(name, ResUtils.getDrawable(drawableId), packageName) - - //注意:自定义实体需要重写对象的toString方法 - override fun toString(): String { - return name - } - - companion object { - fun of(name: String): AppListAdapterItem { - return AppListAdapterItem(name) - } - - fun arrayof(title: Array): Array { - val array = arrayOfNulls(title.size) - for (i in array.indices) { - array[i] = AppListAdapterItem(title[i]) - } - return array - } - } -} +package com.idormy.sms.forwarder.adapter.spinner + +import android.graphics.drawable.Drawable +import com.xuexiang.xui.utils.ResUtils + +@Suppress("unused") +class AppListAdapterItem { + + var name: String = "" + var icon: Drawable? = null + var packageName: String? = null + + constructor(name: String, icon: Drawable?, packageName: String?) { + this.name = name + this.icon = icon + this.packageName = packageName + } + + constructor(name: String) : this(name, null, null) + constructor(name: String, drawableId: Int, packageName: String) : this(name, ResUtils.getDrawable(drawableId), packageName) + + //注意:自定义实体需要重写对象的toString方法 + override fun toString(): String { + return name + } + + companion object { + fun of(name: String): AppListAdapterItem { + return AppListAdapterItem(name) + } + + fun arrayof(title: Array): Array { + val array = arrayOfNulls(title.size) + for (i in array.indices) { + array[i] = AppListAdapterItem(title[i]) + } + return array + } + } +} diff --git a/app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/AppListSpinnerAdapter.kt b/app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/AppListSpinnerAdapter.kt index f3daca6b..e632c9c4 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/AppListSpinnerAdapter.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/AppListSpinnerAdapter.kt @@ -1,157 +1,156 @@ -package com.idormy.sms.forwarder.adapter.spinner - -import android.annotation.SuppressLint -import android.os.Build -import android.text.Html -import android.text.TextUtils -import android.util.Log -import android.util.TypedValue -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import android.widget.TextView -import androidx.annotation.ColorInt -import androidx.annotation.DrawableRes -import com.idormy.sms.forwarder.R -import com.xuexiang.xui.utils.CollectionUtils -import com.xuexiang.xui.widget.spinner.editspinner.BaseEditSpinnerAdapter -import com.xuexiang.xui.widget.spinner.editspinner.EditSpinnerFilter - -@Suppress("unused", "NAME_SHADOWING", "SENSELESS_COMPARISON", "DEPRECATION") -class AppListSpinnerAdapter : BaseEditSpinnerAdapter, EditSpinnerFilter { - /** - * 选项的文字颜色 - */ - private var mTextColor = 0 - - /** - * 选项的文字大小 - */ - private var mTextSize = 0f - - /** - * 背景颜色 - */ - private var mBackgroundSelector = 0 - - /** - * 过滤关键词的选中颜色 - */ - private var mFilterColor = "#F15C58" - private var mIsFilterKey = false - - /** - * 构造方法 - * - * @param data 选项数据 - */ - constructor(data: List?) : super(data) - - /** - * 构造方法 - * - * @param data 选项数据 - */ - constructor(data: Array?) : super(data) - - override fun getEditSpinnerFilter(): EditSpinnerFilter { - return this - } - - override fun getView(position: Int, convertView: View?, parent: ViewGroup): View? { - var convertView = convertView - val holder: ViewHolder - if (convertView == null) { - convertView = LayoutInflater.from(parent.context).inflate(R.layout.item_spinner_with_icon, parent, false) - holder = ViewHolder(convertView, mTextColor, mTextSize, mBackgroundSelector) - convertView.tag = holder - } else { - holder = convertView.tag as ViewHolder - } - val item = CollectionUtils.getListItem(mDataSource, mIndexs[position]) as AppListAdapterItem - holder.iconView.setImageDrawable(item.icon) - //holder.titleView.text = Html.fromHtml(item.toString()) - holder.titleView.text = Html.fromHtml(getItem(position)) - return convertView - } - - override fun onFilter(keyword: String): Boolean { - mDisplayData.clear() - Log.d("AppListSpinnerAdapter", "keyword = $keyword") - Log.d("AppListSpinnerAdapter", "mIndexs.indices = ${mIndexs.indices}") - if (TextUtils.isEmpty(keyword)) { - initDisplayData(mDataSource) - for (i in mIndexs.indices) { - mIndexs[i] = i - } - } else { - try { - for (i in mDataSource.indices) { - if (getDataSourceString(i).contains(keyword, ignoreCase = true)) { - mIndexs[mDisplayData.size] = i - if (mIsFilterKey) { - mDisplayData.add(getDataSourceString(i).replaceFirst(keyword.toRegex(), "$keyword")) - } else { - mDisplayData.add(getDataSourceString(i)) - } - } - } - } catch (e: Exception) { - e.printStackTrace() - } - } - Log.d("AppListSpinnerAdapter", "mDisplayData = $mDisplayData") - notifyDataSetChanged() - return mDisplayData.size > 0 - } - - fun setTextColor(@ColorInt textColor: Int): AppListSpinnerAdapter<*> { - mTextColor = textColor - return this - } - - fun setTextSize(textSize: Float): AppListSpinnerAdapter<*> { - mTextSize = textSize - return this - } - - fun setBackgroundSelector(@DrawableRes backgroundSelector: Int): AppListSpinnerAdapter<*> { - mBackgroundSelector = backgroundSelector - return this - } - - fun setFilterColor(filterColor: String): AppListSpinnerAdapter<*> { - mFilterColor = filterColor - return this - } - - fun setIsFilterKey(isFilterKey: Boolean): AppListSpinnerAdapter<*> { - mIsFilterKey = isFilterKey - return this - } - - @Suppress("DEPRECATION") - @SuppressLint("ObsoleteSdkInt") - private class ViewHolder(convertView: View, @ColorInt textColor: Int, textSize: Float, @DrawableRes backgroundSelector: Int) { - val iconView: ImageView = convertView.findViewById(R.id.iv_icon) - val statusView: ImageView = convertView.findViewById(R.id.iv_status) - val titleView: TextView = convertView.findViewById(R.id.tv_title) - - init { - if (textColor > 0) titleView.setTextColor(textColor) - if (textSize > 0F) titleView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) - if (backgroundSelector != 0) titleView.setBackgroundResource(backgroundSelector) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - val config = convertView.resources.configuration - if (config.layoutDirection == View.LAYOUT_DIRECTION_RTL) { - titleView.textDirection = View.TEXT_DIRECTION_RTL - } - } - } - } - - fun getItemSource(position: Int): T { - return mDataSource[mIndexs[position]] - } -} +package com.idormy.sms.forwarder.adapter.spinner + +import android.annotation.SuppressLint +import android.os.Build +import android.text.Html +import android.text.TextUtils +import android.util.Log +import android.util.TypedValue +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import androidx.annotation.ColorInt +import androidx.annotation.DrawableRes +import com.idormy.sms.forwarder.R +import com.xuexiang.xui.utils.CollectionUtils +import com.xuexiang.xui.widget.spinner.editspinner.BaseEditSpinnerAdapter +import com.xuexiang.xui.widget.spinner.editspinner.EditSpinnerFilter + +@Suppress("unused", "NAME_SHADOWING", "DEPRECATION") +class AppListSpinnerAdapter : BaseEditSpinnerAdapter, EditSpinnerFilter { + /** + * 选项的文字颜色 + */ + private var mTextColor = 0 + + /** + * 选项的文字大小 + */ + private var mTextSize = 0f + + /** + * 背景颜色 + */ + private var mBackgroundSelector = 0 + + /** + * 过滤关键词的选中颜色 + */ + private var mFilterColor = "#F15C58" + private var mIsFilterKey = false + + /** + * 构造方法 + * + * @param data 选项数据 + */ + constructor(data: List?) : super(data) + + /** + * 构造方法 + * + * @param data 选项数据 + */ + constructor(data: Array?) : super(data) + + override fun getEditSpinnerFilter(): EditSpinnerFilter { + return this + } + + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View? { + var convertView = convertView + val holder: ViewHolder + if (convertView == null) { + convertView = LayoutInflater.from(parent.context).inflate(R.layout.item_spinner_with_icon, parent, false) + holder = ViewHolder(convertView, mTextColor, mTextSize, mBackgroundSelector) + convertView.tag = holder + } else { + holder = convertView.tag as ViewHolder + } + val item = CollectionUtils.getListItem(mDataSource, mIndexs[position]) as AppListAdapterItem + holder.iconView.setImageDrawable(item.icon) + //holder.titleView.text = Html.fromHtml(item.toString()) + holder.titleView.text = Html.fromHtml(getItem(position)) + return convertView + } + + override fun onFilter(keyword: String): Boolean { + mDisplayData.clear() + Log.d("AppListSpinnerAdapter", "keyword = $keyword") + Log.d("AppListSpinnerAdapter", "mIndexs.indices = ${mIndexs.indices}") + if (TextUtils.isEmpty(keyword)) { + initDisplayData(mDataSource) + for (i in mIndexs.indices) { + mIndexs[i] = i + } + } else { + try { + for (i in mDataSource.indices) { + if (getDataSourceString(i).contains(keyword, ignoreCase = true)) { + mIndexs[mDisplayData.size] = i + if (mIsFilterKey) { + mDisplayData.add(getDataSourceString(i).replaceFirst(keyword.toRegex(), "$keyword")) + } else { + mDisplayData.add(getDataSourceString(i)) + } + } + } + } catch (e: Exception) { + e.printStackTrace() + } + } + Log.d("AppListSpinnerAdapter", "mDisplayData = $mDisplayData") + notifyDataSetChanged() + return mDisplayData.size > 0 + } + + fun setTextColor(@ColorInt textColor: Int): AppListSpinnerAdapter<*> { + mTextColor = textColor + return this + } + + fun setTextSize(textSize: Float): AppListSpinnerAdapter<*> { + mTextSize = textSize + return this + } + + fun setBackgroundSelector(@DrawableRes backgroundSelector: Int): AppListSpinnerAdapter<*> { + mBackgroundSelector = backgroundSelector + return this + } + + fun setFilterColor(filterColor: String): AppListSpinnerAdapter<*> { + mFilterColor = filterColor + return this + } + + fun setIsFilterKey(isFilterKey: Boolean): AppListSpinnerAdapter<*> { + mIsFilterKey = isFilterKey + return this + } + + @SuppressLint("ObsoleteSdkInt") + private class ViewHolder(convertView: View, @ColorInt textColor: Int, textSize: Float, @DrawableRes backgroundSelector: Int) { + val iconView: ImageView = convertView.findViewById(R.id.iv_icon) + val statusView: ImageView = convertView.findViewById(R.id.iv_status) + val titleView: TextView = convertView.findViewById(R.id.tv_title) + + init { + if (textColor > 0) titleView.setTextColor(textColor) + if (textSize > 0F) titleView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) + if (backgroundSelector != 0) titleView.setBackgroundResource(backgroundSelector) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + val config = convertView.resources.configuration + if (config.layoutDirection == View.LAYOUT_DIRECTION_RTL) { + titleView.textDirection = View.TEXT_DIRECTION_RTL + } + } + } + } + + fun getItemSource(position: Int): T { + return mDataSource[mIndexs[position]] + } +} diff --git a/app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/SenderSpinnerAdapter.kt b/app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/SenderSpinnerAdapter.kt index 2f1477f7..8769118d 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/SenderSpinnerAdapter.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/SenderSpinnerAdapter.kt @@ -1,167 +1,166 @@ -package com.idormy.sms.forwarder.adapter.spinner - -import android.annotation.SuppressLint -import android.os.Build -import android.text.Html -import android.text.TextUtils -import android.util.Log -import android.util.TypedValue -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import android.widget.TextView -import androidx.annotation.ColorInt -import androidx.annotation.DrawableRes -import com.idormy.sms.forwarder.R -import com.idormy.sms.forwarder.utils.STATUS_OFF -import com.xuexiang.xui.utils.CollectionUtils -import com.xuexiang.xui.utils.ResUtils -import com.xuexiang.xui.widget.spinner.editspinner.BaseEditSpinnerAdapter -import com.xuexiang.xui.widget.spinner.editspinner.EditSpinnerFilter - -@Suppress("unused", "NAME_SHADOWING", "SENSELESS_COMPARISON", "DEPRECATION") -class SenderSpinnerAdapter : BaseEditSpinnerAdapter, EditSpinnerFilter { - /** - * 选项的文字颜色 - */ - private var mTextColor = 0 - - /** - * 选项的文字大小 - */ - private var mTextSize = 0f - - /** - * 背景颜色 - */ - private var mBackgroundSelector = 0 - - /** - * 过滤关键词的选中颜色 - */ - private var mFilterColor = "#F15C58" - private var mIsFilterKey = false - - /** - * 构造方法 - * - * @param data 选项数据 - */ - constructor(data: List?) : super(data) - - /** - * 构造方法 - * - * @param data 选项数据 - */ - constructor(data: Array?) : super(data) - - override fun getEditSpinnerFilter(): EditSpinnerFilter { - return this - } - - override fun getView(position: Int, convertView: View?, parent: ViewGroup): View? { - var convertView = convertView - val holder: ViewHolder - if (convertView == null) { - convertView = LayoutInflater.from(parent.context).inflate(R.layout.item_spinner_with_icon, parent, false) - holder = ViewHolder(convertView, mTextColor, mTextSize, mBackgroundSelector) - convertView.tag = holder - } else { - holder = convertView.tag as ViewHolder - } - val item = CollectionUtils.getListItem(mDataSource, mIndexs[position]) as SenderAdapterItem - holder.iconView.setImageDrawable(item.icon) - holder.statusView.setImageDrawable( - ResUtils.getDrawable( - when (item.status) { - STATUS_OFF -> R.drawable.icon_off - else -> R.drawable.icon_on - } - ) - ) - //holder.titleView.text = Html.fromHtml(item.toString()) - holder.titleView.text = Html.fromHtml(getItem(position)) - return convertView - } - - override fun onFilter(keyword: String): Boolean { - mDisplayData.clear() - Log.d("SenderSpinnerAdapter", "keyword = $keyword") - Log.d("SenderSpinnerAdapter", "mIndexs.indices = ${mIndexs.indices}") - if (TextUtils.isEmpty(keyword)) { - initDisplayData(mDataSource) - for (i in mIndexs.indices) { - mIndexs[i] = i - } - } else { - try { - for (i in mDataSource.indices) { - if (getDataSourceString(i).contains(keyword, ignoreCase = true)) { - mIndexs[mDisplayData.size] = i - if (mIsFilterKey) { - mDisplayData.add(getDataSourceString(i).replaceFirst(keyword.toRegex(), "$keyword")) - } else { - mDisplayData.add(getDataSourceString(i)) - } - } - } - } catch (e: Exception) { - e.printStackTrace() - } - } - Log.d("SenderSpinnerAdapter", "mDisplayData = $mDisplayData") - notifyDataSetChanged() - return mDisplayData.size > 0 - } - - fun setTextColor(@ColorInt textColor: Int): SenderSpinnerAdapter<*> { - mTextColor = textColor - return this - } - - fun setTextSize(textSize: Float): SenderSpinnerAdapter<*> { - mTextSize = textSize - return this - } - - fun setBackgroundSelector(@DrawableRes backgroundSelector: Int): SenderSpinnerAdapter<*> { - mBackgroundSelector = backgroundSelector - return this - } - - fun setFilterColor(filterColor: String): SenderSpinnerAdapter<*> { - mFilterColor = filterColor - return this - } - - fun setIsFilterKey(isFilterKey: Boolean): SenderSpinnerAdapter<*> { - mIsFilterKey = isFilterKey - return this - } - - @Suppress("DEPRECATION") - @SuppressLint("ObsoleteSdkInt") - private class ViewHolder(convertView: View, @ColorInt textColor: Int, textSize: Float, @DrawableRes backgroundSelector: Int) { - val iconView: ImageView = convertView.findViewById(R.id.iv_icon) - val statusView: ImageView = convertView.findViewById(R.id.iv_status) - val titleView: TextView = convertView.findViewById(R.id.tv_title) - - init { - if (textColor > 0) titleView.setTextColor(textColor) - if (textSize > 0F) titleView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) - if (backgroundSelector != 0) titleView.setBackgroundResource(backgroundSelector) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - val config = convertView.resources.configuration - if (config.layoutDirection == View.LAYOUT_DIRECTION_RTL) { - titleView.textDirection = View.TEXT_DIRECTION_RTL - } - } - } - } - - fun getItemSource(position: Int): T { - return mDataSource[mIndexs[position]] - } -} +package com.idormy.sms.forwarder.adapter.spinner + +import android.annotation.SuppressLint +import android.os.Build +import android.text.Html +import android.text.TextUtils +import android.util.Log +import android.util.TypedValue +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import androidx.annotation.ColorInt +import androidx.annotation.DrawableRes +import com.idormy.sms.forwarder.R +import com.idormy.sms.forwarder.utils.STATUS_OFF +import com.xuexiang.xui.utils.CollectionUtils +import com.xuexiang.xui.utils.ResUtils +import com.xuexiang.xui.widget.spinner.editspinner.BaseEditSpinnerAdapter +import com.xuexiang.xui.widget.spinner.editspinner.EditSpinnerFilter + +@Suppress("unused", "NAME_SHADOWING", "DEPRECATION") +class SenderSpinnerAdapter : BaseEditSpinnerAdapter, EditSpinnerFilter { + /** + * 选项的文字颜色 + */ + private var mTextColor = 0 + + /** + * 选项的文字大小 + */ + private var mTextSize = 0f + + /** + * 背景颜色 + */ + private var mBackgroundSelector = 0 + + /** + * 过滤关键词的选中颜色 + */ + private var mFilterColor = "#F15C58" + private var mIsFilterKey = false + + /** + * 构造方法 + * + * @param data 选项数据 + */ + constructor(data: List?) : super(data) + + /** + * 构造方法 + * + * @param data 选项数据 + */ + constructor(data: Array?) : super(data) + + override fun getEditSpinnerFilter(): EditSpinnerFilter { + return this + } + + override fun getView(position: Int, convertView: View?, parent: ViewGroup): View? { + var convertView = convertView + val holder: ViewHolder + if (convertView == null) { + convertView = LayoutInflater.from(parent.context).inflate(R.layout.item_spinner_with_icon, parent, false) + holder = ViewHolder(convertView, mTextColor, mTextSize, mBackgroundSelector) + convertView.tag = holder + } else { + holder = convertView.tag as ViewHolder + } + val item = CollectionUtils.getListItem(mDataSource, mIndexs[position]) as SenderAdapterItem + holder.iconView.setImageDrawable(item.icon) + holder.statusView.setImageDrawable( + ResUtils.getDrawable( + when (item.status) { + STATUS_OFF -> R.drawable.icon_off + else -> R.drawable.icon_on + } + ) + ) + //holder.titleView.text = Html.fromHtml(item.toString()) + holder.titleView.text = Html.fromHtml(getItem(position)) + return convertView + } + + override fun onFilter(keyword: String): Boolean { + mDisplayData.clear() + Log.d("SenderSpinnerAdapter", "keyword = $keyword") + Log.d("SenderSpinnerAdapter", "mIndexs.indices = ${mIndexs.indices}") + if (TextUtils.isEmpty(keyword)) { + initDisplayData(mDataSource) + for (i in mIndexs.indices) { + mIndexs[i] = i + } + } else { + try { + for (i in mDataSource.indices) { + if (getDataSourceString(i).contains(keyword, ignoreCase = true)) { + mIndexs[mDisplayData.size] = i + if (mIsFilterKey) { + mDisplayData.add(getDataSourceString(i).replaceFirst(keyword.toRegex(), "$keyword")) + } else { + mDisplayData.add(getDataSourceString(i)) + } + } + } + } catch (e: Exception) { + e.printStackTrace() + } + } + Log.d("SenderSpinnerAdapter", "mDisplayData = $mDisplayData") + notifyDataSetChanged() + return mDisplayData.size > 0 + } + + fun setTextColor(@ColorInt textColor: Int): SenderSpinnerAdapter<*> { + mTextColor = textColor + return this + } + + fun setTextSize(textSize: Float): SenderSpinnerAdapter<*> { + mTextSize = textSize + return this + } + + fun setBackgroundSelector(@DrawableRes backgroundSelector: Int): SenderSpinnerAdapter<*> { + mBackgroundSelector = backgroundSelector + return this + } + + fun setFilterColor(filterColor: String): SenderSpinnerAdapter<*> { + mFilterColor = filterColor + return this + } + + fun setIsFilterKey(isFilterKey: Boolean): SenderSpinnerAdapter<*> { + mIsFilterKey = isFilterKey + return this + } + + @SuppressLint("ObsoleteSdkInt") + private class ViewHolder(convertView: View, @ColorInt textColor: Int, textSize: Float, @DrawableRes backgroundSelector: Int) { + val iconView: ImageView = convertView.findViewById(R.id.iv_icon) + val statusView: ImageView = convertView.findViewById(R.id.iv_status) + val titleView: TextView = convertView.findViewById(R.id.tv_title) + + init { + if (textColor > 0) titleView.setTextColor(textColor) + if (textSize > 0F) titleView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) + if (backgroundSelector != 0) titleView.setBackgroundResource(backgroundSelector) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + val config = convertView.resources.configuration + if (config.layoutDirection == View.LAYOUT_DIRECTION_RTL) { + titleView.textDirection = View.TEXT_DIRECTION_RTL + } + } + } + } + + fun getItemSource(position: Int): T { + return mDataSource[mIndexs[position]] + } +} diff --git a/app/src/main/java/com/idormy/sms/forwarder/core/Core.kt b/app/src/main/java/com/idormy/sms/forwarder/core/Core.kt index 244717c4..5d858e72 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/core/Core.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/core/Core.kt @@ -11,6 +11,7 @@ import com.idormy.sms.forwarder.database.repository.* import com.idormy.sms.forwarder.service.ForegroundService import kotlinx.coroutines.launch +@Suppress("unused") object Core : Configuration.Provider { lateinit var app: Application val frpc: FrpcRepository by lazy { (app as App).frpcRepository } diff --git a/app/src/main/java/com/idormy/sms/forwarder/core/webview/XPageWebViewFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/core/webview/XPageWebViewFragment.kt index 86fd4495..1c0bcde6 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/core/webview/XPageWebViewFragment.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/core/webview/XPageWebViewFragment.kt @@ -1,596 +1,596 @@ -package com.idormy.sms.forwarder.core.webview - -import android.content.ClipData -import android.content.ClipboardManager -import android.content.Context -import android.content.Intent -import android.graphics.Bitmap -import android.graphics.Color -import android.net.Uri -import android.os.Build -import android.text.TextUtils -import android.view.* -import android.webkit.* -import android.widget.FrameLayout -import android.widget.LinearLayout -import android.widget.TextView -import androidx.annotation.RequiresApi -import androidx.appcompat.widget.PopupMenu -import androidx.fragment.app.Fragment -import com.idormy.sms.forwarder.R -import com.idormy.sms.forwarder.core.BaseFragment -import com.idormy.sms.forwarder.databinding.FragmentAgentwebBinding -import com.idormy.sms.forwarder.utils.XToastUtils -import com.just.agentweb.action.PermissionInterceptor -import com.just.agentweb.core.AgentWeb -import com.just.agentweb.core.client.DefaultWebClient -import com.just.agentweb.core.client.MiddlewareWebChromeBase -import com.just.agentweb.core.client.MiddlewareWebClientBase -import com.just.agentweb.core.client.WebListenerManager -import com.just.agentweb.core.web.AbsAgentWebSettings -import com.just.agentweb.core.web.AgentWebConfig -import com.just.agentweb.core.web.IAgentWebSettings -import com.just.agentweb.download.AgentWebDownloader.Extra -import com.just.agentweb.download.DefaultDownloadImpl -import com.just.agentweb.download.DownloadListenerAdapter -import com.just.agentweb.download.DownloadingService -import com.just.agentweb.widget.IWebLayout -import com.xuexiang.xaop.annotation.SingleClick -import com.xuexiang.xpage.annotation.Page -import com.xuexiang.xpage.base.XPageActivity -import com.xuexiang.xpage.base.XPageFragment -import com.xuexiang.xpage.core.PageOption -import com.xuexiang.xui.widget.actionbar.TitleBar -import com.xuexiang.xutil.common.logger.Logger -import com.xuexiang.xutil.net.JsonUtil - -/** - * 使用XPageFragment - * - * @author xuexiang - * @since 2019-05-26 18:15 - */ -@Suppress("DEPRECATION", "unused", "UNUSED_PARAMETER", "NAME_SHADOWING", "OVERRIDE_DEPRECATION") -@Page(params = [AgentWebFragment.KEY_URL]) -class XPageWebViewFragment : BaseFragment(), View.OnClickListener { - private var mAgentWeb: AgentWeb? = null - private var mPopupMenu: PopupMenu? = null - private var mDownloadingService: DownloadingService? = null - override fun viewBindingInflate( - inflater: LayoutInflater, - container: ViewGroup, - ): FragmentAgentwebBinding { - return FragmentAgentwebBinding.inflate(inflater, container, false) - } - - override fun initTitle(): TitleBar? { - return null - } - - /** - * 初始化控件 - */ - override fun initViews() { - mAgentWeb = AgentWeb.with(this) //传入AgentWeb的父控件。 - .setAgentWebParent( - (rootView as LinearLayout), - -1, - LinearLayout.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT - ) - ) //设置进度条颜色与高度,-1为默认值,高度为2,单位为dp。 - .useDefaultIndicator(-1, 3) //设置 IAgentWebSettings。 - .setAgentWebWebSettings(settings) //WebViewClient , 与 WebView 使用一致 ,但是请勿获取WebView调用setWebViewClient(xx)方法了,会覆盖AgentWeb DefaultWebClient,同时相应的中间件也会失效。 - .setWebViewClient(mWebViewClient) //WebChromeClient - .setWebChromeClient(mWebChromeClient) //设置WebChromeClient中间件,支持多个WebChromeClient,AgentWeb 3.0.0 加入。 - .useMiddlewareWebChrome(middlewareWebChrome) //设置WebViewClient中间件,支持多个WebViewClient, AgentWeb 3.0.0 加入。 - .useMiddlewareWebClient(middlewareWebClient) //权限拦截 2.0.0 加入。 - .setPermissionInterceptor(mPermissionInterceptor) //严格模式 Android 4.2.2 以下会放弃注入对象 ,使用AgentWebView没影响。 - .setSecurityType(AgentWeb.SecurityType.STRICT_CHECK) //自定义UI AgentWeb3.0.0 加入。 - .setAgentWebUIController(UIController(requireActivity())) //参数1是错误显示的布局,参数2点击刷新控件ID -1表示点击整个布局都刷新, AgentWeb 3.0.0 加入。 - .setMainFrameErrorView(R.layout.agentweb_error_page, -1) - .setWebLayout(webLayout) //打开其他页面时,弹窗质询用户前往其他应用 AgentWeb 3.0.0 加入。 - .setOpenOtherPageWays(DefaultWebClient.OpenOtherPageWays.DISALLOW) //拦截找不到相关页面的Url AgentWeb 3.0.0 加入。 - .interceptUnkownUrl() //创建AgentWeb。 - .createAgentWeb() - .ready() //设置 WebSettings。 - //WebView载入该url地址的页面并显示。 - .go(url) - if (com.idormy.sms.forwarder.App.isDebug) { - AgentWebConfig.debug() - } - pageNavigator(View.GONE) - // 得到 AgentWeb 最底层的控件 - addBackgroundChild(mAgentWeb!!.webCreator.webParentLayout) - - // AgentWeb 没有把WebView的功能全面覆盖 ,所以某些设置 AgentWeb 没有提供,请从WebView方面入手设置。 - mAgentWeb!!.webCreator.webView.overScrollMode = WebView.OVER_SCROLL_NEVER - } - - private val webLayout: IWebLayout<*, *> - get() = WebLayout(activity) - - private fun addBackgroundChild(frameLayout: FrameLayout) { - val textView = TextView(frameLayout.context) - textView.text = getString(R.string.provided_by_agentweb) - textView.textSize = 16f - textView.setTextColor(Color.parseColor("#727779")) - frameLayout.setBackgroundColor(Color.parseColor("#272b2d")) - val params = FrameLayout.LayoutParams(-2, -2) - params.gravity = Gravity.CENTER_HORIZONTAL - val scale = frameLayout.context.resources.displayMetrics.density - params.topMargin = (15 * scale + 0.5f).toInt() - frameLayout.addView(textView, 0, params) - } - - override fun initListeners() { - binding!!.includeTitle.ivBack.setOnClickListener(this) - binding!!.includeTitle.ivFinish.setOnClickListener(this) - binding!!.includeTitle.ivMore.setOnClickListener(this) - } - - private fun pageNavigator(tag: Int) { - //返回的导航按钮 - binding!!.includeTitle.ivBack.visibility = tag - binding!!.includeTitle.viewLine.visibility = tag - } - - @SingleClick - override fun onClick(view: View) { - val id = view.id - if (id == R.id.iv_back) { - // true表示AgentWeb处理了该事件 - if (!mAgentWeb!!.back()) { - popToBack() - } - } else if (id == R.id.iv_finish) { - popToBack() - } else if (id == R.id.iv_more) { - showPoPup(view) - } - } - //=====================下载============================// - /** - * 更新于 AgentWeb 4.0.0,下载监听 - */ - private var mDownloadListenerAdapter: DownloadListenerAdapter = - object : DownloadListenerAdapter() { - /** - * - * @param url 下载链接 - * @param userAgent UserAgent - * @param contentDisposition ContentDisposition - * @param mimeType 资源的媒体类型 - * @param contentLength 文件长度 - * @param extra 下载配置 , 用户可以通过 Extra 修改下载icon , 关闭进度条 , 是否强制下载。 - * @return true 表示用户处理了该下载事件 , false 交给 AgentWeb 下载 - */ - override fun onStart( - url: String, - userAgent: String, - contentDisposition: String, - mimeType: String, - contentLength: Long, - extra: Extra, - ): Boolean { - Logger.i("onStart:$url") - // 是否开启断点续传 - extra.setOpenBreakPointDownload(true) //下载通知的icon - .setIcon(R.drawable.ic_file_download_black_24dp) // 连接的超时时间 - .setConnectTimeOut(6000) // 以8KB位单位,默认60s ,如果60s内无法从网络流中读满8KB数据,则抛出异常 - .setBlockMaxTime(10 * 60 * 1000) // 下载的超时时间 - .setDownloadTimeOut(Long.MAX_VALUE) // 串行下载更节省资源哦 - .setParallelDownload(false) // false 关闭进度通知 - .setEnableIndicator(true) // 自定义请求头 - .addHeader("Cookie", "xx") // 下载完成自动打开 - .setAutoOpen(true).isForceDownload = true - return false - } - - /** - * - * 不需要暂停或者停止下载该方法可以不必实现 - * @param url - * @param downloadingService 用户可以通过 DownloadingService#shutdownNow 终止下载 - */ - override fun onBindService(url: String, downloadingService: DownloadingService) { - super.onBindService(url, downloadingService) - mDownloadingService = downloadingService - Logger.i("onBindService:$url DownloadingService:$downloadingService") - } - - /** - * 回调onUnbindService方法,让用户释放掉 DownloadingService。 - * @param url - * @param downloadingService - */ - override fun onUnbindService(url: String, downloadingService: DownloadingService) { - super.onUnbindService(url, downloadingService) - mDownloadingService = null - Logger.i("onUnbindService:$url") - } - - /** - * - * @param url 下载链接 - * @param loaded 已经下载的长度 - * @param length 文件的总大小 - * @param usedTime 耗时 ,单位ms - * 注意该方法回调在子线程 ,线程名 AsyncTask #XX 或者 AgentWeb # XX - */ - override fun onProgress(url: String, loaded: Long, length: Long, usedTime: Long) { - val mProgress = (loaded / length.toFloat() * 100).toInt() - Logger.i("onProgress:$mProgress") - super.onProgress(url, loaded, length, usedTime) - } - - /** - * - * @param path 文件的绝对路径 - * @param url 下载地址 - * @param throwable 如果异常,返回给用户异常 - * @return true 表示用户处理了下载完成后续的事件 ,false 默认交给AgentWeb 处理 - */ - override fun onResult(path: String, url: String, throwable: Throwable): Boolean { - //下载成功 - //if (null == throwable) { - //do you work - //} else { //下载失败 - //} - // true 不会发出下载完成的通知 , 或者打开文件 - return false - } - } - /** - * AgentWeb 4.0.0 内部删除了 DownloadListener 监听 ,以及相关API ,将 Download 部分完全抽离出来独立一个库, - * 如果你需要使用 AgentWeb Download 部分 , 请依赖上 compile 'com.just.agentweb:download:4.0.0 , - * 如果你需要监听下载结果,请自定义 AgentWebSetting , New 出 DefaultDownloadImpl,传入DownloadListenerAdapter - * 实现进度或者结果监听,例如下面这个例子,如果你不需要监听进度,或者下载结果,下面 setDownloader 的例子可以忽略。 - * @return WebListenerManager - */ - /** - * 下载服务设置 - * - * @return IAgentWebSettings - */ - val settings: IAgentWebSettings<*> - get() = object : AbsAgentWebSettings() { - private val mAgentWeb: AgentWeb? = null - override fun bindAgentWebSupport(agentWeb: AgentWeb) { - this.mAgentWeb = agentWeb - } - - /** - * AgentWeb 4.0.0 内部删除了 DownloadListener 监听 ,以及相关API ,将 Download 部分完全抽离出来独立一个库, - * 如果你需要使用 AgentWeb Download 部分 , 请依赖上 compile 'com.just.agentweb:download:4.0.0 , - * 如果你需要监听下载结果,请自定义 AgentWebSetting , New 出 DefaultDownloadImpl,传入DownloadListenerAdapter - * 实现进度或者结果监听,例如下面这个例子,如果你不需要监听进度,或者下载结果,下面 setDownloader 的例子可以忽略。 - * @return WebListenerManager - */ - override fun setDownloader( - webView: WebView, - downloadListener: DownloadListener, - ): WebListenerManager { - return super.setDownloader( - webView, - DefaultDownloadImpl - .create( - activity!!, - webView, - mDownloadListenerAdapter, - mDownloadListenerAdapter, - mAgentWeb.permissionInterceptor - ) - ) - } - } - //===================WebChromeClient 和 WebViewClient===========================// - /** - * 页面空白,请检查scheme是否加上, scheme://host:port/path?query&query 。 - * - * @return mUrl - */ - val url: String - get() { - var target = "" - val bundle = arguments - if (bundle != null) { - target = bundle.getString(AgentWebFragment.KEY_URL).toString() - } - if (TextUtils.isEmpty(target)) { - target = "https://github.com/xuexiangjys" - } - return target - } - - /** - * 和浏览器相关,包括和JS的交互 - */ - private var mWebChromeClient: WebChromeClient = object : WebChromeClient() { - override fun onProgressChanged(view: WebView, newProgress: Int) { - super.onProgressChanged(view, newProgress) - //网页加载进度 - } - - override fun onReceivedTitle(view: WebView, title: String) { - var title = title - super.onReceivedTitle(view, title) - if (!TextUtils.isEmpty(title)) { - if (title.length > 10) { - title = title.substring(0, 10) + "..." - } - binding!!.includeTitle.toolbarTitle.text = title - } - } - } - - /** - * 和网页url加载相关,统计加载时间 - */ - @Suppress("DEPRECATION") - private var mWebViewClient: WebViewClient = object : WebViewClient() { - private val mTimer = HashMap() - override fun onReceivedError( - view: WebView, - request: WebResourceRequest, - error: WebResourceError, - ) { - super.onReceivedError(view, request, error) - } - - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean { - return shouldOverrideUrlLoading(view, request.url.toString() + "") - } - - override fun shouldInterceptRequest( - view: WebView, - request: WebResourceRequest, - ): WebResourceResponse? { - return super.shouldInterceptRequest(view, request) - } - - override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean { - //intent:// scheme的处理 如果返回false , 则交给 DefaultWebClient 处理 , 默认会打开该Activity , 如果Activity不存在则跳到应用市场上去. true 表示拦截 - //例如优酷视频播放 ,intent://play?...package=com.youku.phone;end; - //优酷想唤起自己应用播放该视频 , 下面拦截地址返回 true 则会在应用内 H5 播放 ,禁止优酷唤起播放该视频, 如果返回 false , DefaultWebClient 会根据intent 协议处理 该地址 , 首先匹配该应用存不存在 ,如果存在 , 唤起该应用播放 , 如果不存在 , 则跳到应用市场下载该应用 . - return url.startsWith("intent://") && url.contains("com.youku.phone") - } - - override fun onPageStarted(view: WebView, url: String, favicon: Bitmap) { - mTimer[url] = System.currentTimeMillis() - //if (url == url) { - // pageNavigator(View.GONE) - //} else { - pageNavigator(View.VISIBLE) - //} - } - - override fun onPageFinished(view: WebView, url: String) { - super.onPageFinished(view, url) - if (mTimer[url] != null) { - val overTime = System.currentTimeMillis() - val startTime = mTimer[url] - //统计页面的使用时长 - Logger.i(" page mUrl:" + url + " used time:" + (overTime - startTime!!)) - } - } - - override fun onReceivedHttpError( - view: WebView, - request: WebResourceRequest, - errorResponse: WebResourceResponse, - ) { - super.onReceivedHttpError(view, request, errorResponse) - } - - override fun onReceivedError( - view: WebView, - errorCode: Int, - description: String, - failingUrl: String, - ) { - super.onReceivedError(view, errorCode, description, failingUrl) - } - } - //=====================菜单========================// - /** - * 显示更多菜单 - * - * @param view 菜单依附在该View下面 - */ - private fun showPoPup(view: View) { - if (mPopupMenu == null) { - mPopupMenu = PopupMenu(requireContext(), view) - mPopupMenu!!.inflate(R.menu.menu_toolbar_web) - mPopupMenu!!.setOnMenuItemClickListener(mOnMenuItemClickListener) - } - mPopupMenu!!.show() - } - - /** - * 菜单事件 - */ - private val mOnMenuItemClickListener = PopupMenu.OnMenuItemClickListener { item -> - when (item.itemId) { - R.id.refresh -> { - if (mAgentWeb != null) { - mAgentWeb!!.urlLoader.reload() // 刷新 - } - return@OnMenuItemClickListener true - } - R.id.copy -> { - if (mAgentWeb != null) { - mAgentWeb!!.webCreator.webView.url?.let { toCopy(context, it) } - } - return@OnMenuItemClickListener true - } - R.id.default_browser -> { - if (mAgentWeb != null) { - mAgentWeb!!.webCreator.webView.url?.let { openBrowser(it) } - } - return@OnMenuItemClickListener true - } - R.id.share -> { - if (mAgentWeb != null) { - mAgentWeb!!.webCreator.webView.url?.let { shareWebUrl(it) } - } - return@OnMenuItemClickListener true - } - else -> false - } - } - - /** - * 打开浏览器 - * - * @param targetUrl 外部浏览器打开的地址 - */ - private fun openBrowser(targetUrl: String) { - if (TextUtils.isEmpty(targetUrl) || targetUrl.startsWith("file://")) { - XToastUtils.toast(targetUrl + getString(R.string.cannot_open_with_browser)) - return - } - val intent = Intent() - intent.action = "android.intent.action.VIEW" - val uri = Uri.parse(targetUrl) - intent.data = uri - startActivity(intent) - } - - /** - * 分享网页链接 - * - * @param url 网页链接 - */ - private fun shareWebUrl(url: String) { - val shareIntent = Intent() - shareIntent.action = Intent.ACTION_SEND - shareIntent.putExtra(Intent.EXTRA_TEXT, url) - shareIntent.type = "text/plain" - //设置分享列表的标题,并且每次都显示分享列表 - startActivity(Intent.createChooser(shareIntent, getString(R.string.share_to))) - } - - /** - * 复制字符串 - * - * @param context - * @param text - */ - private fun toCopy(context: Context?, text: String) { - val manager = - requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager - manager.setPrimaryClip(ClipData.newPlainText(null, text)) - } - - //===================生命周期管理===========================// - override fun onResume() { - if (mAgentWeb != null) { - mAgentWeb!!.webLifeCycle.onResume() //恢复 - } - super.onResume() - } - - override fun onPause() { - if (mAgentWeb != null) { - mAgentWeb!!.webLifeCycle.onPause() //暂停应用内所有WebView , 调用mWebView.resumeTimers();/mAgentWeb.getWebLifeCycle().onResume(); 恢复。 - } - super.onPause() - } - - override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { - return mAgentWeb != null && mAgentWeb!!.handleKeyEvent(keyCode, event) - } - - override fun onDestroyView() { - if (mAgentWeb != null) { - mAgentWeb!!.destroy() - } - super.onDestroyView() - } - //===================中间键===========================//// 拦截 url,不执行 DefaultWebClient#shouldOverrideUrlLoading - // 执行 DefaultWebClient#shouldOverrideUrlLoading - // do you work - /** - * MiddlewareWebClientBase 是 AgentWeb 3.0.0 提供一个强大的功能, - * 如果用户需要使用 AgentWeb 提供的功能, 不想重写 WebClientView方 - * 法覆盖AgentWeb提供的功能,那么 MiddlewareWebClientBase 是一个 - * 不错的选择 。 - */ - private val middlewareWebClient: MiddlewareWebClientBase - get() = object : MiddlewareWebViewClient() { - override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean { - // 拦截 url,不执行 DefaultWebClient#shouldOverrideUrlLoading - if (url.startsWith("agentweb")) { - return true - } - // 执行 DefaultWebClient#shouldOverrideUrlLoading - return super.shouldOverrideUrlLoading(view, url) - // do you work - } - - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - override fun shouldOverrideUrlLoading( - view: WebView, - request: WebResourceRequest, - ): Boolean { - return super.shouldOverrideUrlLoading(view, request) - } - } - private val middlewareWebChrome: MiddlewareWebChromeBase - get() = object : MiddlewareChromeClient() {} - - /** - * 权限申请拦截器 - */ - private var mPermissionInterceptor = PermissionInterceptor { url, permissions, action -> - - /** - * PermissionInterceptor 能达到 url1 允许授权, url2 拒绝授权的效果。 - * @param url - * @param permissions - * @param action - * @return true 该Url对应页面请求权限进行拦截 ,false 表示不拦截。 - */ - /** - * PermissionInterceptor 能达到 url1 允许授权, url2 拒绝授权的效果。 - * @param url - * @param permissions - * @param action - * @return true 该Url对应页面请求权限进行拦截 ,false 表示不拦截。 - */ - Logger.i("mUrl:" + url + " permission:" + JsonUtil.toJson(permissions) + " action:" + action) - false - } - - companion object { - /** - * 打开网页 - * - * @param xPageActivity - * @param url - * @return - */ - fun openUrl(xPageActivity: XPageActivity?, url: String?): Fragment { - return PageOption.to(XPageWebViewFragment::class.java) - .putString(AgentWebFragment.KEY_URL, url) - .open(xPageActivity!!) - } - - /** - * 打开网页 - * - * @param fragment - * @param url - * @return - */ - fun openUrl(fragment: XPageFragment?, url: String?): Fragment { - return PageOption.to(XPageWebViewFragment::class.java) - .setNewActivity(true) - .putString(AgentWebFragment.KEY_URL, url) - .open(fragment!!) - } - } +package com.idormy.sms.forwarder.core.webview + +import android.content.ClipData +import android.content.ClipboardManager +import android.content.Context +import android.content.Intent +import android.graphics.Bitmap +import android.graphics.Color +import android.net.Uri +import android.os.Build +import android.text.TextUtils +import android.view.* +import android.webkit.* +import android.widget.FrameLayout +import android.widget.LinearLayout +import android.widget.TextView +import androidx.annotation.RequiresApi +import androidx.appcompat.widget.PopupMenu +import androidx.fragment.app.Fragment +import com.idormy.sms.forwarder.R +import com.idormy.sms.forwarder.core.BaseFragment +import com.idormy.sms.forwarder.databinding.FragmentAgentwebBinding +import com.idormy.sms.forwarder.utils.XToastUtils +import com.just.agentweb.action.PermissionInterceptor +import com.just.agentweb.core.AgentWeb +import com.just.agentweb.core.client.DefaultWebClient +import com.just.agentweb.core.client.MiddlewareWebChromeBase +import com.just.agentweb.core.client.MiddlewareWebClientBase +import com.just.agentweb.core.client.WebListenerManager +import com.just.agentweb.core.web.AbsAgentWebSettings +import com.just.agentweb.core.web.AgentWebConfig +import com.just.agentweb.core.web.IAgentWebSettings +import com.just.agentweb.download.AgentWebDownloader.Extra +import com.just.agentweb.download.DefaultDownloadImpl +import com.just.agentweb.download.DownloadListenerAdapter +import com.just.agentweb.download.DownloadingService +import com.just.agentweb.widget.IWebLayout +import com.xuexiang.xaop.annotation.SingleClick +import com.xuexiang.xpage.annotation.Page +import com.xuexiang.xpage.base.XPageActivity +import com.xuexiang.xpage.base.XPageFragment +import com.xuexiang.xpage.core.PageOption +import com.xuexiang.xui.widget.actionbar.TitleBar +import com.xuexiang.xutil.common.logger.Logger +import com.xuexiang.xutil.net.JsonUtil + +/** + * 使用XPageFragment + * + * @author xuexiang + * @since 2019-05-26 18:15 + */ +@Suppress("DEPRECATION", "unused", "UNUSED_PARAMETER", "NAME_SHADOWING", "OVERRIDE_DEPRECATION") +@Page(params = [AgentWebFragment.KEY_URL]) +class XPageWebViewFragment : BaseFragment(), View.OnClickListener { + private var mAgentWeb: AgentWeb? = null + private var mPopupMenu: PopupMenu? = null + private var mDownloadingService: DownloadingService? = null + override fun viewBindingInflate( + inflater: LayoutInflater, + container: ViewGroup, + ): FragmentAgentwebBinding { + return FragmentAgentwebBinding.inflate(inflater, container, false) + } + + override fun initTitle(): TitleBar? { + return null + } + + /** + * 初始化控件 + */ + override fun initViews() { + mAgentWeb = AgentWeb.with(this) //传入AgentWeb的父控件。 + .setAgentWebParent( + (rootView as LinearLayout), + -1, + LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + ) + ) //设置进度条颜色与高度,-1为默认值,高度为2,单位为dp。 + .useDefaultIndicator(-1, 3) //设置 IAgentWebSettings。 + .setAgentWebWebSettings(settings) //WebViewClient , 与 WebView 使用一致 ,但是请勿获取WebView调用setWebViewClient(xx)方法了,会覆盖AgentWeb DefaultWebClient,同时相应的中间件也会失效。 + .setWebViewClient(mWebViewClient) //WebChromeClient + .setWebChromeClient(mWebChromeClient) //设置WebChromeClient中间件,支持多个WebChromeClient,AgentWeb 3.0.0 加入。 + .useMiddlewareWebChrome(middlewareWebChrome) //设置WebViewClient中间件,支持多个WebViewClient, AgentWeb 3.0.0 加入。 + .useMiddlewareWebClient(middlewareWebClient) //权限拦截 2.0.0 加入。 + .setPermissionInterceptor(mPermissionInterceptor) //严格模式 Android 4.2.2 以下会放弃注入对象 ,使用AgentWebView没影响。 + .setSecurityType(AgentWeb.SecurityType.STRICT_CHECK) //自定义UI AgentWeb3.0.0 加入。 + .setAgentWebUIController(UIController(requireActivity())) //参数1是错误显示的布局,参数2点击刷新控件ID -1表示点击整个布局都刷新, AgentWeb 3.0.0 加入。 + .setMainFrameErrorView(R.layout.agentweb_error_page, -1) + .setWebLayout(webLayout) //打开其他页面时,弹窗质询用户前往其他应用 AgentWeb 3.0.0 加入。 + .setOpenOtherPageWays(DefaultWebClient.OpenOtherPageWays.DISALLOW) //拦截找不到相关页面的Url AgentWeb 3.0.0 加入。 + .interceptUnkownUrl() //创建AgentWeb。 + .createAgentWeb() + .ready() //设置 WebSettings。 + //WebView载入该url地址的页面并显示。 + .go(url) + if (com.idormy.sms.forwarder.App.isDebug) { + AgentWebConfig.debug() + } + pageNavigator(View.GONE) + // 得到 AgentWeb 最底层的控件 + addBackgroundChild(mAgentWeb!!.webCreator.webParentLayout) + + // AgentWeb 没有把WebView的功能全面覆盖 ,所以某些设置 AgentWeb 没有提供,请从WebView方面入手设置。 + mAgentWeb!!.webCreator.webView.overScrollMode = WebView.OVER_SCROLL_NEVER + } + + private val webLayout: IWebLayout<*, *> + get() = WebLayout(activity) + + private fun addBackgroundChild(frameLayout: FrameLayout) { + val textView = TextView(frameLayout.context) + textView.text = getString(R.string.provided_by_agentweb) + textView.textSize = 16f + textView.setTextColor(Color.parseColor("#727779")) + frameLayout.setBackgroundColor(Color.parseColor("#272b2d")) + val params = FrameLayout.LayoutParams(-2, -2) + params.gravity = Gravity.CENTER_HORIZONTAL + val scale = frameLayout.context.resources.displayMetrics.density + params.topMargin = (15 * scale + 0.5f).toInt() + frameLayout.addView(textView, 0, params) + } + + override fun initListeners() { + binding!!.includeTitle.ivBack.setOnClickListener(this) + binding!!.includeTitle.ivFinish.setOnClickListener(this) + binding!!.includeTitle.ivMore.setOnClickListener(this) + } + + private fun pageNavigator(tag: Int) { + //返回的导航按钮 + binding!!.includeTitle.ivBack.visibility = tag + binding!!.includeTitle.viewLine.visibility = tag + } + + @SingleClick + override fun onClick(view: View) { + val id = view.id + if (id == R.id.iv_back) { + // true表示AgentWeb处理了该事件 + if (!mAgentWeb!!.back()) { + popToBack() + } + } else if (id == R.id.iv_finish) { + popToBack() + } else if (id == R.id.iv_more) { + showPoPup(view) + } + } + //=====================下载============================// + /** + * 更新于 AgentWeb 4.0.0,下载监听 + */ + private var mDownloadListenerAdapter: DownloadListenerAdapter = + object : DownloadListenerAdapter() { + /** + * + * @param url 下载链接 + * @param userAgent UserAgent + * @param contentDisposition ContentDisposition + * @param mimeType 资源的媒体类型 + * @param contentLength 文件长度 + * @param extra 下载配置 , 用户可以通过 Extra 修改下载icon , 关闭进度条 , 是否强制下载。 + * @return true 表示用户处理了该下载事件 , false 交给 AgentWeb 下载 + */ + override fun onStart( + url: String, + userAgent: String, + contentDisposition: String, + mimeType: String, + contentLength: Long, + extra: Extra, + ): Boolean { + Logger.i("onStart:$url") + // 是否开启断点续传 + extra.setOpenBreakPointDownload(true) //下载通知的icon + .setIcon(R.drawable.ic_file_download_black_24dp) // 连接的超时时间 + .setConnectTimeOut(6000) // 以8KB位单位,默认60s ,如果60s内无法从网络流中读满8KB数据,则抛出异常 + .setBlockMaxTime(10 * 60 * 1000) // 下载的超时时间 + .setDownloadTimeOut(Long.MAX_VALUE) // 串行下载更节省资源哦 + .setParallelDownload(false) // false 关闭进度通知 + .setEnableIndicator(true) // 自定义请求头 + .addHeader("Cookie", "xx") // 下载完成自动打开 + .setAutoOpen(true).isForceDownload = true + return false + } + + /** + * + * 不需要暂停或者停止下载该方法可以不必实现 + * @param url + * @param downloadingService 用户可以通过 DownloadingService#shutdownNow 终止下载 + */ + override fun onBindService(url: String, downloadingService: DownloadingService) { + super.onBindService(url, downloadingService) + mDownloadingService = downloadingService + Logger.i("onBindService:$url DownloadingService:$downloadingService") + } + + /** + * 回调onUnbindService方法,让用户释放掉 DownloadingService。 + * @param url + * @param downloadingService + */ + override fun onUnbindService(url: String, downloadingService: DownloadingService) { + super.onUnbindService(url, downloadingService) + mDownloadingService = null + Logger.i("onUnbindService:$url") + } + + /** + * + * @param url 下载链接 + * @param loaded 已经下载的长度 + * @param length 文件的总大小 + * @param usedTime 耗时 ,单位ms + * 注意该方法回调在子线程 ,线程名 AsyncTask #XX 或者 AgentWeb # XX + */ + override fun onProgress(url: String, loaded: Long, length: Long, usedTime: Long) { + val mProgress = (loaded / length.toFloat() * 100).toInt() + Logger.i("onProgress:$mProgress") + super.onProgress(url, loaded, length, usedTime) + } + + /** + * + * @param path 文件的绝对路径 + * @param url 下载地址 + * @param throwable 如果异常,返回给用户异常 + * @return true 表示用户处理了下载完成后续的事件 ,false 默认交给AgentWeb 处理 + */ + override fun onResult(path: String, url: String, throwable: Throwable): Boolean { + //下载成功 + //if (null == throwable) { + //do you work + //} else { //下载失败 + //} + // true 不会发出下载完成的通知 , 或者打开文件 + return false + } + } + /** + * AgentWeb 4.0.0 内部删除了 DownloadListener 监听 ,以及相关API ,将 Download 部分完全抽离出来独立一个库, + * 如果你需要使用 AgentWeb Download 部分 , 请依赖上 compile 'com.just.agentweb:download:4.0.0 , + * 如果你需要监听下载结果,请自定义 AgentWebSetting , New 出 DefaultDownloadImpl,传入DownloadListenerAdapter + * 实现进度或者结果监听,例如下面这个例子,如果你不需要监听进度,或者下载结果,下面 setDownloader 的例子可以忽略。 + * @return WebListenerManager + */ + /** + * 下载服务设置 + * + * @return IAgentWebSettings + */ + private val settings: IAgentWebSettings<*> + get() = object : AbsAgentWebSettings() { + private val mAgentWeb: AgentWeb? = null + override fun bindAgentWebSupport(agentWeb: AgentWeb) { + this.mAgentWeb = agentWeb + } + + /** + * AgentWeb 4.0.0 内部删除了 DownloadListener 监听 ,以及相关API ,将 Download 部分完全抽离出来独立一个库, + * 如果你需要使用 AgentWeb Download 部分 , 请依赖上 compile 'com.just.agentweb:download:4.0.0 , + * 如果你需要监听下载结果,请自定义 AgentWebSetting , New 出 DefaultDownloadImpl,传入DownloadListenerAdapter + * 实现进度或者结果监听,例如下面这个例子,如果你不需要监听进度,或者下载结果,下面 setDownloader 的例子可以忽略。 + * @return WebListenerManager + */ + override fun setDownloader( + webView: WebView, + downloadListener: DownloadListener, + ): WebListenerManager { + return super.setDownloader( + webView, + DefaultDownloadImpl + .create( + activity!!, + webView, + mDownloadListenerAdapter, + mDownloadListenerAdapter, + mAgentWeb.permissionInterceptor + ) + ) + } + } + //===================WebChromeClient 和 WebViewClient===========================// + /** + * 页面空白,请检查scheme是否加上, scheme://host:port/path?query&query 。 + * + * @return mUrl + */ + val url: String + get() { + var target = "" + val bundle = arguments + if (bundle != null) { + target = bundle.getString(AgentWebFragment.KEY_URL).toString() + } + if (TextUtils.isEmpty(target)) { + target = "https://github.com/xuexiangjys" + } + return target + } + + /** + * 和浏览器相关,包括和JS的交互 + */ + private var mWebChromeClient: WebChromeClient = object : WebChromeClient() { + override fun onProgressChanged(view: WebView, newProgress: Int) { + super.onProgressChanged(view, newProgress) + //网页加载进度 + } + + override fun onReceivedTitle(view: WebView, title: String) { + var title = title + super.onReceivedTitle(view, title) + if (!TextUtils.isEmpty(title)) { + if (title.length > 10) { + title = title.substring(0, 10) + "..." + } + binding!!.includeTitle.toolbarTitle.text = title + } + } + } + + /** + * 和网页url加载相关,统计加载时间 + */ + @Suppress("DEPRECATION") + private var mWebViewClient: WebViewClient = object : WebViewClient() { + private val mTimer = HashMap() + override fun onReceivedError( + view: WebView, + request: WebResourceRequest, + error: WebResourceError, + ) { + super.onReceivedError(view, request, error) + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean { + return shouldOverrideUrlLoading(view, request.url.toString() + "") + } + + override fun shouldInterceptRequest( + view: WebView, + request: WebResourceRequest, + ): WebResourceResponse? { + return super.shouldInterceptRequest(view, request) + } + + override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean { + //intent:// scheme的处理 如果返回false , 则交给 DefaultWebClient 处理 , 默认会打开该Activity , 如果Activity不存在则跳到应用市场上去. true 表示拦截 + //例如优酷视频播放 ,intent://play?...package=com.youku.phone;end; + //优酷想唤起自己应用播放该视频 , 下面拦截地址返回 true 则会在应用内 H5 播放 ,禁止优酷唤起播放该视频, 如果返回 false , DefaultWebClient 会根据intent 协议处理 该地址 , 首先匹配该应用存不存在 ,如果存在 , 唤起该应用播放 , 如果不存在 , 则跳到应用市场下载该应用 . + return url.startsWith("intent://") && url.contains("com.youku.phone") + } + + override fun onPageStarted(view: WebView, url: String, favicon: Bitmap) { + mTimer[url] = System.currentTimeMillis() + //if (url == url) { + // pageNavigator(View.GONE) + //} else { + pageNavigator(View.VISIBLE) + //} + } + + override fun onPageFinished(view: WebView, url: String) { + super.onPageFinished(view, url) + if (mTimer[url] != null) { + val overTime = System.currentTimeMillis() + val startTime = mTimer[url] + //统计页面的使用时长 + Logger.i(" page mUrl:" + url + " used time:" + (overTime - startTime!!)) + } + } + + override fun onReceivedHttpError( + view: WebView, + request: WebResourceRequest, + errorResponse: WebResourceResponse, + ) { + super.onReceivedHttpError(view, request, errorResponse) + } + + override fun onReceivedError( + view: WebView, + errorCode: Int, + description: String, + failingUrl: String, + ) { + super.onReceivedError(view, errorCode, description, failingUrl) + } + } + //=====================菜单========================// + /** + * 显示更多菜单 + * + * @param view 菜单依附在该View下面 + */ + private fun showPoPup(view: View) { + if (mPopupMenu == null) { + mPopupMenu = PopupMenu(requireContext(), view) + mPopupMenu!!.inflate(R.menu.menu_toolbar_web) + mPopupMenu!!.setOnMenuItemClickListener(mOnMenuItemClickListener) + } + mPopupMenu!!.show() + } + + /** + * 菜单事件 + */ + private val mOnMenuItemClickListener = PopupMenu.OnMenuItemClickListener { item -> + when (item.itemId) { + R.id.refresh -> { + if (mAgentWeb != null) { + mAgentWeb!!.urlLoader.reload() // 刷新 + } + return@OnMenuItemClickListener true + } + R.id.copy -> { + if (mAgentWeb != null) { + mAgentWeb!!.webCreator.webView.url?.let { toCopy(context, it) } + } + return@OnMenuItemClickListener true + } + R.id.default_browser -> { + if (mAgentWeb != null) { + mAgentWeb!!.webCreator.webView.url?.let { openBrowser(it) } + } + return@OnMenuItemClickListener true + } + R.id.share -> { + if (mAgentWeb != null) { + mAgentWeb!!.webCreator.webView.url?.let { shareWebUrl(it) } + } + return@OnMenuItemClickListener true + } + else -> false + } + } + + /** + * 打开浏览器 + * + * @param targetUrl 外部浏览器打开的地址 + */ + private fun openBrowser(targetUrl: String) { + if (TextUtils.isEmpty(targetUrl) || targetUrl.startsWith("file://")) { + XToastUtils.toast(targetUrl + getString(R.string.cannot_open_with_browser)) + return + } + val intent = Intent() + intent.action = "android.intent.action.VIEW" + val uri = Uri.parse(targetUrl) + intent.data = uri + startActivity(intent) + } + + /** + * 分享网页链接 + * + * @param url 网页链接 + */ + private fun shareWebUrl(url: String) { + val shareIntent = Intent() + shareIntent.action = Intent.ACTION_SEND + shareIntent.putExtra(Intent.EXTRA_TEXT, url) + shareIntent.type = "text/plain" + //设置分享列表的标题,并且每次都显示分享列表 + startActivity(Intent.createChooser(shareIntent, getString(R.string.share_to))) + } + + /** + * 复制字符串 + * + * @param context + * @param text + */ + private fun toCopy(context: Context?, text: String) { + val manager = + requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager + manager.setPrimaryClip(ClipData.newPlainText(null, text)) + } + + //===================生命周期管理===========================// + override fun onResume() { + if (mAgentWeb != null) { + mAgentWeb!!.webLifeCycle.onResume() //恢复 + } + super.onResume() + } + + override fun onPause() { + if (mAgentWeb != null) { + mAgentWeb!!.webLifeCycle.onPause() //暂停应用内所有WebView , 调用mWebView.resumeTimers();/mAgentWeb.getWebLifeCycle().onResume(); 恢复。 + } + super.onPause() + } + + override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { + return mAgentWeb != null && mAgentWeb!!.handleKeyEvent(keyCode, event) + } + + override fun onDestroyView() { + if (mAgentWeb != null) { + mAgentWeb!!.destroy() + } + super.onDestroyView() + } + //===================中间键===========================//// 拦截 url,不执行 DefaultWebClient#shouldOverrideUrlLoading + // 执行 DefaultWebClient#shouldOverrideUrlLoading + // do you work + /** + * MiddlewareWebClientBase 是 AgentWeb 3.0.0 提供一个强大的功能, + * 如果用户需要使用 AgentWeb 提供的功能, 不想重写 WebClientView方 + * 法覆盖AgentWeb提供的功能,那么 MiddlewareWebClientBase 是一个 + * 不错的选择 。 + */ + private val middlewareWebClient: MiddlewareWebClientBase + get() = object : MiddlewareWebViewClient() { + override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean { + // 拦截 url,不执行 DefaultWebClient#shouldOverrideUrlLoading + if (url.startsWith("agentweb")) { + return true + } + // 执行 DefaultWebClient#shouldOverrideUrlLoading + return super.shouldOverrideUrlLoading(view, url) + // do you work + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + override fun shouldOverrideUrlLoading( + view: WebView, + request: WebResourceRequest, + ): Boolean { + return super.shouldOverrideUrlLoading(view, request) + } + } + private val middlewareWebChrome: MiddlewareWebChromeBase + get() = object : MiddlewareChromeClient() {} + + /** + * 权限申请拦截器 + */ + private var mPermissionInterceptor = PermissionInterceptor { url, permissions, action -> + + /** + * PermissionInterceptor 能达到 url1 允许授权, url2 拒绝授权的效果。 + * @param url + * @param permissions + * @param action + * @return true 该Url对应页面请求权限进行拦截 ,false 表示不拦截。 + */ + /** + * PermissionInterceptor 能达到 url1 允许授权, url2 拒绝授权的效果。 + * @param url + * @param permissions + * @param action + * @return true 该Url对应页面请求权限进行拦截 ,false 表示不拦截。 + */ + Logger.i("mUrl:" + url + " permission:" + JsonUtil.toJson(permissions) + " action:" + action) + false + } + + companion object { + /** + * 打开网页 + * + * @param xPageActivity + * @param url + * @return + */ + fun openUrl(xPageActivity: XPageActivity?, url: String?): Fragment { + return PageOption.to(XPageWebViewFragment::class.java) + .putString(AgentWebFragment.KEY_URL, url) + .open(xPageActivity!!) + } + + /** + * 打开网页 + * + * @param fragment + * @param url + * @return + */ + fun openUrl(fragment: XPageFragment?, url: String?): Fragment { + return PageOption.to(XPageWebViewFragment::class.java) + .setNewActivity(true) + .putString(AgentWebFragment.KEY_URL, url) + .open(fragment!!) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/idormy/sms/forwarder/database/dao/RuleDao.kt b/app/src/main/java/com/idormy/sms/forwarder/database/dao/RuleDao.kt index 6c91739e..1cf74893 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/database/dao/RuleDao.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/database/dao/RuleDao.kt @@ -3,7 +3,7 @@ package com.idormy.sms.forwarder.database.dao import androidx.paging.PagingSource import androidx.room.* import com.idormy.sms.forwarder.database.entity.Rule -import com.idormy.sms.forwarder.database.entity.RuleAndSender +//import com.idormy.sms.forwarder.database.entity.RuleAndSender import io.reactivex.Completable import io.reactivex.Single @@ -48,9 +48,9 @@ interface RuleDao { @Query("SELECT * FROM Rule where type=:type ORDER BY id DESC") fun pagingSource(type: String): PagingSource - @Transaction - @Query("SELECT * FROM Rule where type=:type and status=:status and (sim_slot='ALL' or sim_slot=:simSlot)") - suspend fun getRuleAndSender(type: String, status: Int, simSlot: String): List + //@Transaction + //@Query("SELECT * FROM Rule where type=:type and status=:status and (sim_slot='ALL' or sim_slot=:simSlot)") + //suspend fun getRuleAndSender(type: String, status: Int, simSlot: String): List @Transaction @Query("SELECT * FROM Rule where type=:type and status=:status and (sim_slot='ALL' or sim_slot=:simSlot)") diff --git a/app/src/main/java/com/idormy/sms/forwarder/database/entity/Logs.kt b/app/src/main/java/com/idormy/sms/forwarder/database/entity/Logs.kt index 99bd964f..e70b9642 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/database/entity/Logs.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/database/entity/Logs.kt @@ -49,16 +49,4 @@ data class Logs( @ColumnInfo(name = "forward_status", defaultValue = "1") var forwardStatus: Int = 1, @ColumnInfo(name = "forward_response", defaultValue = "") var forwardResponse: String = "", @ColumnInfo(name = "time") var time: Date = Date(), -) : Parcelable { - - val statusImageId: Int - get() { - if (forwardStatus == 1) { - return R.drawable.ic_round_warning - } else if (forwardStatus == 2) { - return R.drawable.ic_round_check - } - return R.drawable.ic_round_cancel - } - -} \ No newline at end of file +) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/com/idormy/sms/forwarder/database/entity/Sender.kt b/app/src/main/java/com/idormy/sms/forwarder/database/entity/Sender.kt index 2627bdaf..98bd5191 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/database/entity/Sender.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/database/entity/Sender.kt @@ -20,29 +20,6 @@ data class Sender( @ColumnInfo(name = "status", defaultValue = "1") var status: Int = 1, @ColumnInfo(name = "time") var time: Date = Date(), ) : Parcelable { - companion object { - - fun getImageId(type: Int): Int = when (type) { - TYPE_DINGTALK_GROUP_ROBOT -> R.drawable.icon_dingtalk - TYPE_EMAIL -> R.drawable.icon_email - TYPE_BARK -> R.drawable.icon_bark - TYPE_WEBHOOK -> R.drawable.icon_webhook - TYPE_WEWORK_ROBOT -> R.drawable.icon_wework_robot - TYPE_WEWORK_AGENT -> R.drawable.icon_wework_agent - TYPE_SERVERCHAN -> R.drawable.icon_serverchan - TYPE_TELEGRAM -> R.drawable.icon_telegram - TYPE_FEISHU -> R.drawable.icon_feishu - TYPE_PUSHPLUS -> R.drawable.icon_pushplus - TYPE_GOTIFY -> R.drawable.icon_gotify - TYPE_SMS -> R.drawable.icon_sms - TYPE_DINGTALK_INNER_ROBOT -> R.drawable.icon_dingtalk_inner - TYPE_FEISHU_APP -> R.drawable.icon_feishu_app - TYPE_URL_SCHEME -> R.drawable.icon_url_scheme - TYPE_SOCKET -> R.drawable.icon_socket - else -> R.drawable.icon_sms - } - - } val imageId: Int get() = when (type) { diff --git a/app/src/main/java/com/idormy/sms/forwarder/database/repository/FrpcRepository.kt b/app/src/main/java/com/idormy/sms/forwarder/database/repository/FrpcRepository.kt index 58c4be7e..2a97388f 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/database/repository/FrpcRepository.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/database/repository/FrpcRepository.kt @@ -1,36 +1,36 @@ -package com.idormy.sms.forwarder.database.repository - -import androidx.annotation.WorkerThread -import com.idormy.sms.forwarder.database.dao.FrpcDao -import com.idormy.sms.forwarder.database.entity.Frpc - -class FrpcRepository( - private val frpcDao: FrpcDao, -) { - - var listener: Listener? = null - - @WorkerThread - fun insert(frpc: Frpc) { - frpcDao.insert(frpc) - } - - @WorkerThread - fun delete(uid: String) { - frpcDao.delete(uid) - } - - @WorkerThread - fun get(uid: String) = frpcDao.get(uid) - - @WorkerThread - fun update(frpc: Frpc) = frpcDao.update(frpc) - - //TODO:允许主线程访问,后面再优化 - val all: List = frpcDao.getAll() - - fun deleteAll() { - frpcDao.deleteAll() - } - +package com.idormy.sms.forwarder.database.repository + +import androidx.annotation.WorkerThread +import com.idormy.sms.forwarder.database.dao.FrpcDao +import com.idormy.sms.forwarder.database.entity.Frpc + +class FrpcRepository( + private val frpcDao: FrpcDao, +) { + + //var listener: Listener? = null + + @WorkerThread + fun insert(frpc: Frpc) { + frpcDao.insert(frpc) + } + + @WorkerThread + fun delete(uid: String) { + frpcDao.delete(uid) + } + + @WorkerThread + fun get(uid: String) = frpcDao.get(uid) + + @WorkerThread + fun update(frpc: Frpc) = frpcDao.update(frpc) + + //TODO:允许主线程访问,后面再优化 + val all: List = frpcDao.getAll() + + fun deleteAll() { + frpcDao.deleteAll() + } + } \ No newline at end of file diff --git a/app/src/main/java/com/idormy/sms/forwarder/database/repository/LogsRepository.kt b/app/src/main/java/com/idormy/sms/forwarder/database/repository/LogsRepository.kt index 235d6ce8..41800d34 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/database/repository/LogsRepository.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/database/repository/LogsRepository.kt @@ -11,10 +11,10 @@ class LogsRepository(private val logsDao: LogsDao) { logsDao.delete(id) } - @WorkerThread - fun deleteTimeAgo(time: Long) { - logsDao.deleteTimeAgo(time) - } + //@WorkerThread + //fun deleteTimeAgo(time: Long) { + // logsDao.deleteTimeAgo(time) + //} @WorkerThread suspend fun insert(logs: Logs): Long = logsDao.insert(logs) diff --git a/app/src/main/java/com/idormy/sms/forwarder/database/repository/RuleRepository.kt b/app/src/main/java/com/idormy/sms/forwarder/database/repository/RuleRepository.kt index 9ad0e29d..a0fe270e 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/database/repository/RuleRepository.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/database/repository/RuleRepository.kt @@ -8,7 +8,7 @@ class RuleRepository( private val ruleDao: RuleDao, ) { - var listener: Listener? = null + private var listener: Listener? = null @WorkerThread fun insert(rule: Rule) { @@ -27,7 +27,7 @@ class RuleRepository( @WorkerThread fun getOne(id: Long) = ruleDao.getOne(id) - suspend fun getRuleAndSender(type: String, status: Int, simSlot: String) = ruleDao.getRuleAndSender(type, status, simSlot) + //suspend fun getRuleAndSender(type: String, status: Int, simSlot: String) = ruleDao.getRuleAndSender(type, status, simSlot) fun getRuleList(type: String, status: Int, simSlot: String) = ruleDao.getRuleList(type, status, simSlot) diff --git a/app/src/main/java/com/idormy/sms/forwarder/database/repository/SenderRepository.kt b/app/src/main/java/com/idormy/sms/forwarder/database/repository/SenderRepository.kt index ef8301cf..32d766b8 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/database/repository/SenderRepository.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/database/repository/SenderRepository.kt @@ -7,7 +7,7 @@ import kotlinx.coroutines.flow.Flow class SenderRepository(private val senderDao: SenderDao) { - var listener: Listener? = null + private var listener: Listener? = null @WorkerThread fun insert(sender: Sender) = senderDao.insert(sender) diff --git a/app/src/main/java/com/idormy/sms/forwarder/fragment/ClientFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/fragment/ClientFragment.kt index d4bd6656..ef3422d6 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/fragment/ClientFragment.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/fragment/ClientFragment.kt @@ -38,7 +38,7 @@ import com.xuexiang.xui.widget.dialog.materialdialog.MaterialDialog import com.xuexiang.xutil.XUtil import com.xuexiang.xutil.data.ConvertTools -@Suppress("PrivatePropertyName", "PropertyName") +@Suppress("PropertyName") @Page(name = "主动控制·客户端") class ClientFragment : BaseFragment(), View.OnClickListener, RecyclerViewHolder.OnItemClickListener { diff --git a/app/src/main/java/com/idormy/sms/forwarder/fragment/FrpcEditFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/fragment/FrpcEditFragment.kt index 8e7ceb50..8ed3543a 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/fragment/FrpcEditFragment.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/fragment/FrpcEditFragment.kt @@ -27,7 +27,7 @@ import com.xuexiang.xui.widget.dialog.materialdialog.DialogAction import com.xuexiang.xui.widget.dialog.materialdialog.MaterialDialog import com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText -@Suppress("PrivatePropertyName", "DEPRECATION") +@Suppress("DEPRECATION") @Page(name = "Frp内网穿透·编辑配置") class FrpcEditFragment : BaseFragment() { diff --git a/app/src/main/java/com/idormy/sms/forwarder/fragment/FrpcFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/fragment/FrpcFragment.kt index 66736e63..60d93c26 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/fragment/FrpcFragment.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/fragment/FrpcFragment.kt @@ -38,7 +38,6 @@ import io.reactivex.schedulers.Schedulers import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch - @Suppress("DEPRECATION") @Page(name = "Frp内网穿透") class FrpcFragment : BaseFragment(), FrpcPagingAdapter.OnItemClickListener { diff --git a/app/src/main/java/com/idormy/sms/forwarder/fragment/LogcatFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/fragment/LogcatFragment.kt index 6fc2f37a..4466e083 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/fragment/LogcatFragment.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/fragment/LogcatFragment.kt @@ -1,109 +1,108 @@ -package com.idormy.sms.forwarder.fragment - -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import com.idormy.sms.forwarder.R -import com.idormy.sms.forwarder.core.BaseFragment -import com.idormy.sms.forwarder.databinding.FragmentLogcatBinding -import com.idormy.sms.forwarder.utils.XToastUtils -import com.xuexiang.xaop.annotation.SingleClick -import com.xuexiang.xpage.annotation.Page -import com.xuexiang.xui.utils.ThemeUtils -import com.xuexiang.xui.widget.actionbar.TitleBar -import com.xuexiang.xutil.system.ClipboardUtils -import io.reactivex.Observable -import io.reactivex.ObservableEmitter -import io.reactivex.Observer -import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.disposables.Disposable -import io.reactivex.schedulers.Schedulers -import java.io.BufferedReader -import java.io.InputStreamReader - -@Suppress("PrivatePropertyName") -@Page(name = "Logcat") -class LogcatFragment : BaseFragment() { - - override fun viewBindingInflate( - inflater: LayoutInflater, - container: ViewGroup, - ): FragmentLogcatBinding { - return FragmentLogcatBinding.inflate(inflater, container, false) - } - - override fun initTitle(): TitleBar { - val titleBar = super.initTitle()!!.setImmersive(false) - titleBar!!.setTitle(R.string.menu_logcat) - titleBar.setActionTextColor(ThemeUtils.resolveColor(context, R.attr.colorAccent)) - titleBar.addAction(object : TitleBar.ImageAction(R.drawable.ic_copy) { - @SingleClick - override fun performAction(view: View) { - ClipboardUtils.copyText(binding!!.tvLogcat.text.toString()) - XToastUtils.success(R.string.copySuccess) - } - }) - titleBar.addAction(object : TitleBar.ImageAction(R.drawable.ic_delete) { - @SingleClick - override fun performAction(view: View) { - readLog(true) - binding!!.tvLogcat.text = "" - } - }) - return titleBar - } - - override fun initViews() { - } - - override fun initListeners() { - readLog(false) - } - - private fun readLog(flush: Boolean) { - val lst: HashSet = LinkedHashSet() - lst.add("logcat") - lst.add("-d") - lst.add("-v") - lst.add("time") - lst.add("-s") - lst.add("GoLog,com.idormy.sms.forwarder.ForegroundService,com.idormy.sms.forwarder.server.ServerService") - Observable.create { emitter: ObservableEmitter -> - if (flush) { - val lst2: HashSet = LinkedHashSet() - lst2.add("logcat") - lst2.add("-c") - val process = Runtime.getRuntime().exec(lst2.toTypedArray()) - process.waitFor() - } - val process = Runtime.getRuntime().exec(lst.toTypedArray()) - val `in` = InputStreamReader(process.inputStream) - val bufferedReader = BufferedReader(`in`) - var line: String? - while (bufferedReader.readLine().also { line = it } != null) { - emitter.onNext(line!!) - } - `in`.close() - bufferedReader.close() - emitter.onComplete() - }.subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(object : Observer { - override fun onSubscribe(d: Disposable) {} - - override fun onNext(s: String) { - binding!!.tvLogcat.append(s) - binding!!.tvLogcat.append("\r\n") - binding!!.svLogcat.fullScroll(View.FOCUS_DOWN) - } - - override fun onError(e: Throwable) { - e.printStackTrace() - } - - override fun onComplete() {} - - }) - } - +package com.idormy.sms.forwarder.fragment + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.idormy.sms.forwarder.R +import com.idormy.sms.forwarder.core.BaseFragment +import com.idormy.sms.forwarder.databinding.FragmentLogcatBinding +import com.idormy.sms.forwarder.utils.XToastUtils +import com.xuexiang.xaop.annotation.SingleClick +import com.xuexiang.xpage.annotation.Page +import com.xuexiang.xui.utils.ThemeUtils +import com.xuexiang.xui.widget.actionbar.TitleBar +import com.xuexiang.xutil.system.ClipboardUtils +import io.reactivex.Observable +import io.reactivex.ObservableEmitter +import io.reactivex.Observer +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers +import java.io.BufferedReader +import java.io.InputStreamReader + +@Page(name = "Logcat") +class LogcatFragment : BaseFragment() { + + override fun viewBindingInflate( + inflater: LayoutInflater, + container: ViewGroup, + ): FragmentLogcatBinding { + return FragmentLogcatBinding.inflate(inflater, container, false) + } + + override fun initTitle(): TitleBar { + val titleBar = super.initTitle()!!.setImmersive(false) + titleBar!!.setTitle(R.string.menu_logcat) + titleBar.setActionTextColor(ThemeUtils.resolveColor(context, R.attr.colorAccent)) + titleBar.addAction(object : TitleBar.ImageAction(R.drawable.ic_copy) { + @SingleClick + override fun performAction(view: View) { + ClipboardUtils.copyText(binding!!.tvLogcat.text.toString()) + XToastUtils.success(R.string.copySuccess) + } + }) + titleBar.addAction(object : TitleBar.ImageAction(R.drawable.ic_delete) { + @SingleClick + override fun performAction(view: View) { + readLog(true) + binding!!.tvLogcat.text = "" + } + }) + return titleBar + } + + override fun initViews() { + } + + override fun initListeners() { + readLog(false) + } + + private fun readLog(flush: Boolean) { + val lst: HashSet = LinkedHashSet() + lst.add("logcat") + lst.add("-d") + lst.add("-v") + lst.add("time") + lst.add("-s") + lst.add("GoLog,com.idormy.sms.forwarder.ForegroundService,com.idormy.sms.forwarder.server.ServerService") + Observable.create { emitter: ObservableEmitter -> + if (flush) { + val lst2: HashSet = LinkedHashSet() + lst2.add("logcat") + lst2.add("-c") + val process = Runtime.getRuntime().exec(lst2.toTypedArray()) + process.waitFor() + } + val process = Runtime.getRuntime().exec(lst.toTypedArray()) + val `in` = InputStreamReader(process.inputStream) + val bufferedReader = BufferedReader(`in`) + var line: String? + while (bufferedReader.readLine().also { line = it } != null) { + emitter.onNext(line!!) + } + `in`.close() + bufferedReader.close() + emitter.onComplete() + }.subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(object : Observer { + override fun onSubscribe(d: Disposable) {} + + override fun onNext(s: String) { + binding!!.tvLogcat.append(s) + binding!!.tvLogcat.append("\r\n") + binding!!.svLogcat.fullScroll(View.FOCUS_DOWN) + } + + override fun onError(e: Throwable) { + e.printStackTrace() + } + + override fun onComplete() {} + + }) + } + } \ No newline at end of file diff --git a/app/src/main/java/com/idormy/sms/forwarder/fragment/ServerFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/fragment/ServerFragment.kt index f28199c4..7ee890e6 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/fragment/ServerFragment.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/fragment/ServerFragment.kt @@ -35,8 +35,6 @@ import java.io.File import java.net.InetAddress import java.security.KeyPairGenerator - -@Suppress("PrivatePropertyName") @Page(name = "主动控制·服务端") class ServerFragment : BaseFragment(), View.OnClickListener { diff --git a/app/src/main/java/com/idormy/sms/forwarder/fragment/client/CloneFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/fragment/client/CloneFragment.kt index 5eeb3b4b..ae9a7abc 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/fragment/client/CloneFragment.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/fragment/client/CloneFragment.kt @@ -42,7 +42,6 @@ import com.xuexiang.xutil.file.FileUtils import java.io.File import java.util.* - @Suppress("PropertyName") @Page(name = "一键换新机") class CloneFragment : BaseFragment(), View.OnClickListener { diff --git a/app/src/main/java/com/idormy/sms/forwarder/fragment/client/ContactQueryFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/fragment/client/ContactQueryFragment.kt index cccd5273..13400972 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/fragment/client/ContactQueryFragment.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/fragment/client/ContactQueryFragment.kt @@ -40,7 +40,6 @@ import com.xuexiang.xutil.data.ConvertTools import com.xuexiang.xutil.system.ClipboardUtils import me.samlss.broccoli.Broccoli - @Suppress("PropertyName") @Page(name = "远程查话簿") class ContactQueryFragment : BaseFragment() { diff --git a/app/src/main/java/com/idormy/sms/forwarder/fragment/client/SmsQueryFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/fragment/client/SmsQueryFragment.kt index 51d5b8f1..c8ad2173 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/fragment/client/SmsQueryFragment.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/fragment/client/SmsQueryFragment.kt @@ -41,7 +41,6 @@ import com.xuexiang.xutil.data.ConvertTools import com.xuexiang.xutil.data.DateUtils import me.samlss.broccoli.Broccoli - @Suppress("PropertyName") @Page(name = "远程查短信") class SmsQueryFragment : BaseFragment() { diff --git a/app/src/main/java/com/idormy/sms/forwarder/receiver/SmsReceiver.kt b/app/src/main/java/com/idormy/sms/forwarder/receiver/SmsReceiver.kt index c188826f..55da41a4 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/receiver/SmsReceiver.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/receiver/SmsReceiver.kt @@ -29,7 +29,7 @@ import java.util.* //短信广播 @OptIn(DelicateCoroutinesApi::class) -@Suppress("PrivatePropertyName", "DEPRECATION", "DeferredResultUnused", "SENSELESS_COMPARISON") +@Suppress("PrivatePropertyName", "DeferredResultUnused", "SENSELESS_COMPARISON") class SmsReceiver : BroadcastReceiver() { private var TAG = "SmsReceiver" diff --git a/app/src/main/java/com/idormy/sms/forwarder/server/component/AppMessageConverter.kt b/app/src/main/java/com/idormy/sms/forwarder/server/component/AppMessageConverter.kt index cd58af6d..5edd759b 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/server/component/AppMessageConverter.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/server/component/AppMessageConverter.kt @@ -22,7 +22,6 @@ import java.io.InputStream import java.lang.reflect.Type import java.nio.charset.Charset - @Suppress("PrivatePropertyName") @Converter class AppMessageConverter : MessageConverter { diff --git a/app/src/main/java/com/idormy/sms/forwarder/server/controller/LocationController.kt b/app/src/main/java/com/idormy/sms/forwarder/server/controller/LocationController.kt index dfbeba0b..824ac025 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/server/controller/LocationController.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/server/controller/LocationController.kt @@ -10,7 +10,7 @@ import com.yanzhenjie.andserver.annotation.* import java.util.* @SuppressLint("SimpleDateFormat") -@Suppress("PrivatePropertyName", "DEPRECATION") +@Suppress("PrivatePropertyName") @RestController @RequestMapping(path = ["/location"]) class LocationController { diff --git a/app/src/main/java/com/idormy/sms/forwarder/service/BatteryService.kt b/app/src/main/java/com/idormy/sms/forwarder/service/BatteryService.kt index 325f6686..8da15afc 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/service/BatteryService.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/service/BatteryService.kt @@ -31,7 +31,7 @@ import kotlinx.coroutines.async import java.util.* @OptIn(DelicateCoroutinesApi::class) -@Suppress("DEPRECATION", "DeferredResultUnused") +@Suppress("DeferredResultUnused") class BatteryService : Service() { override fun onBind(intent: Intent): IBinder? { diff --git a/app/src/main/java/com/idormy/sms/forwarder/service/NetworkStateService.kt b/app/src/main/java/com/idormy/sms/forwarder/service/NetworkStateService.kt index e362a2dc..f51dac83 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/service/NetworkStateService.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/service/NetworkStateService.kt @@ -22,7 +22,7 @@ import com.xuexiang.xutil.app.ServiceUtils import com.xuexiang.xutil.net.NetworkUtils import java.util.* -@Suppress("DEPRECATION", "DeferredResultUnused") +@Suppress("DEPRECATION") class NetworkStateService : Service() { override fun onBind(intent: Intent): IBinder? { diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/CertUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/CertUtils.kt deleted file mode 100644 index 89422181..00000000 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/CertUtils.kt +++ /dev/null @@ -1,53 +0,0 @@ -package com.idormy.sms.forwarder.utils - -import android.annotation.SuppressLint -import java.security.KeyStore -import java.security.SecureRandom -import java.security.cert.X509Certificate -import java.util.* -import javax.net.ssl.* - -@Suppress("unused") -@SuppressLint("ALL") -object CertUtils { - - //获取这个SSLSocketFactory - val sSLSocketFactory: SSLSocketFactory - get() = try { - val sslContext = SSLContext.getInstance("SSL") - sslContext.init(null, trustManager, SecureRandom()) - sslContext.socketFactory - } catch (e: Exception) { - throw RuntimeException(e) - } - - //获取TrustManager - private val trustManager: Array - get() = arrayOf( - object : X509TrustManager { - override fun checkClientTrusted(chain: Array, authType: String) {} - override fun checkServerTrusted(chain: Array, authType: String) {} - override fun getAcceptedIssuers(): Array { - return arrayOf() - } - } - ) - - //获取HostnameVerifier - val hostnameVerifier: HostnameVerifier - get() = HostnameVerifier { _: String?, _: SSLSession? -> true } - val x509TrustManager: X509TrustManager? - get() { - var trustManager: X509TrustManager? = null - try { - val trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()) - trustManagerFactory.init(null as KeyStore?) - val trustManagers = trustManagerFactory.trustManagers - check(!(trustManagers.size != 1 || trustManagers[0] !is X509TrustManager)) { "Unexpected default trust managers:" + Arrays.toString(trustManagers) } - trustManager = trustManagers[0] as X509TrustManager - } catch (e: Exception) { - e.printStackTrace() - } - return trustManager - } -} \ No newline at end of file diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/DataProvider.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/DataProvider.kt index 1a0ca8f5..61beb63d 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/DataProvider.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/DataProvider.kt @@ -1,74 +1,73 @@ -package com.idormy.sms.forwarder.utils - -import com.idormy.sms.forwarder.entity.CallInfo -import com.idormy.sms.forwarder.entity.ContactInfo -import com.idormy.sms.forwarder.entity.SmsInfo -import com.xuexiang.xaop.annotation.MemoryCache - -object DataProvider { - - //用于占位的空信息 - @JvmStatic - @get:MemoryCache - val emptySmsInfo: List - get() { - val list: MutableList = ArrayList() - for (i in 0..5) { - list.add(SmsInfo()) - } - return list - } - - //用于占位的空信息 - @JvmStatic - @get:MemoryCache - val emptyCallInfo: List - get() { - val list: MutableList = ArrayList() - for (i in 0..5) { - list.add(CallInfo()) - } - return list - } - - //用于占位的空信息 - @JvmStatic - @get:MemoryCache - val emptyContactInfo: List - get() { - val list: MutableList = ArrayList() - for (i in 0..5) { - list.add(ContactInfo()) - } - return list - } - - //获取时间段 - @JvmStatic - @get:MemoryCache - val timePeriodOption: List - get() { - return getTimePeriod(24, 10) //修改时请注意会不会造成旧版下标越界 - } - - /** - * 获取时间段 - * - * @param interval 时间间隔(分钟) - * @return - */ - @Suppress("UNCHECKED_CAST") - fun getTimePeriod(totalHour: Int, interval: Int): List { - val list: MutableList = ArrayList() - var point: Int - var hour: Int - var min: Int - for (i in 0..totalHour * 60 / interval) { - point = i * interval - hour = point / 60 - min = point - hour * 60 - list.add((if (hour <= 9) "0$hour" else "" + hour) + ":" + if (min <= 9) "0$min" else "" + min) - } - return list - } +package com.idormy.sms.forwarder.utils + +import com.idormy.sms.forwarder.entity.CallInfo +import com.idormy.sms.forwarder.entity.ContactInfo +import com.idormy.sms.forwarder.entity.SmsInfo +import com.xuexiang.xaop.annotation.MemoryCache + +object DataProvider { + + //用于占位的空信息 + @JvmStatic + @get:MemoryCache + val emptySmsInfo: List + get() { + val list: MutableList = ArrayList() + for (i in 0..5) { + list.add(SmsInfo()) + } + return list + } + + //用于占位的空信息 + @JvmStatic + @get:MemoryCache + val emptyCallInfo: List + get() { + val list: MutableList = ArrayList() + for (i in 0..5) { + list.add(CallInfo()) + } + return list + } + + //用于占位的空信息 + @JvmStatic + @get:MemoryCache + val emptyContactInfo: List + get() { + val list: MutableList = ArrayList() + for (i in 0..5) { + list.add(ContactInfo()) + } + return list + } + + //获取时间段 + @JvmStatic + @get:MemoryCache + val timePeriodOption: List + get() { + return getTimePeriod(24, 10) //修改时请注意会不会造成旧版下标越界 + } + + /** + * 获取时间段 + * + * @param interval 时间间隔(分钟) + * @return + */ + private fun getTimePeriod(totalHour: Int, interval: Int): List { + val list: MutableList = ArrayList() + var point: Int + var hour: Int + var min: Int + for (i in 0..totalHour * 60 / interval) { + point = i * interval + hour = point / 60 + min = point - hour * 60 + list.add((if (hour <= 9) "0$hour" else "" + hour) + ":" + if (min <= 9) "0$min" else "" + min) + } + return list + } } \ No newline at end of file diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/HistoryUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/HistoryUtils.kt index bd2b4d93..33de9ce1 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/HistoryUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/HistoryUtils.kt @@ -13,7 +13,7 @@ import kotlin.reflect.KProperty * @author pppscn * @since 2022年5月9日 */ -@Suppress("PropertyName", "UNCHECKED_CAST", "MemberVisibilityCanBePrivate", "unused") +@Suppress("UNCHECKED_CAST", "MemberVisibilityCanBePrivate", "unused") class HistoryUtils(private val name: String, private val default: T) : ReadWriteProperty { companion object { diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/Logger.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/Logger.kt deleted file mode 100644 index 745a6577..00000000 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/Logger.kt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2018 Zhenjie Yan. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.idormy.sms.forwarder.utils - -import android.util.Log - -/** - * Created by Zhenjie Yan on 2018/9/12. - */ -@Suppress("unused") -object Logger { - private const val TAG = "AndServer" - private const val DEBUG = true - fun i(obj: Any?) { - if (DEBUG) { - Log.i(TAG, obj?.toString() ?: "null") - } - } - - fun d(obj: Any?) { - if (DEBUG) { - Log.d(TAG, obj?.toString() ?: "null") - } - } - - fun v(obj: Any?) { - if (DEBUG) { - Log.v(TAG, obj?.toString() ?: "null") - } - } - - fun w(obj: Any?) { - if (DEBUG) { - Log.w(TAG, obj?.toString() ?: "null") - } - } - - fun e(obj: Any?) { - if (DEBUG) { - Log.e(TAG, obj?.toString() ?: "null") - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/NetUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/NetUtils.kt deleted file mode 100644 index cf412385..00000000 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/NetUtils.kt +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright © 2018 Zhenjie Yan. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.idormy.sms.forwarder.utils - -import java.net.InetAddress -import java.net.NetworkInterface -import java.net.SocketException -import java.util.* -import java.util.regex.Pattern - -/** - * Created by Zhenjie Yan on 2018/6/9. - */ -@Suppress("unused") -object NetUtils { - /** - * Ipv4 address check. - */ - private val IPV4_PATTERN = Pattern.compile( - "^(" + "([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}" + - "([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$" - ) - - /** - * Check if valid IPV4 address. - * - * @param input the address string to check for validity. - * @return True if the input parameter is a valid IPv4 address. - */ - private fun isIPv4Address(input: String?): Boolean { - return IPV4_PATTERN.matcher(input.toString()).matches() - } - - /** - * Get local Ip address. - */ - val localIPAddress: InetAddress? - get() { - var enumeration: Enumeration? = null - try { - enumeration = NetworkInterface.getNetworkInterfaces() - } catch (e: SocketException) { - e.printStackTrace() - } - if (enumeration != null) { - while (enumeration.hasMoreElements()) { - val nif = enumeration.nextElement() - val inetAddresses = nif.inetAddresses - if (inetAddresses != null) { - while (inetAddresses.hasMoreElements()) { - val inetAddress = inetAddresses.nextElement() - if (!inetAddress.isLoopbackAddress && isIPv4Address(inetAddress.hostAddress)) { - return inetAddress - } - } - } - } - } - return null - } -} \ No newline at end of file diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/PrefsHelper.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/PrefsHelper.kt deleted file mode 100644 index e2e41db1..00000000 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/PrefsHelper.kt +++ /dev/null @@ -1,67 +0,0 @@ -@file:Suppress("DEPRECATION") - -package com.idormy.sms.forwarder.utils - -import android.content.Context -import android.content.SharedPreferences -import android.preference.PreferenceManager - -/** - * Created by aykutasil on 8.12.2016. - */ - -@Suppress("unused") -class PrefsHelper private constructor() { - - lateinit var preference: SharedPreferences - - val prefEditor: SharedPreferences.Editor - get() = preference.edit() - - constructor(context: Context, prefName: String) : this() { - preference = context.getSharedPreferences(prefName, Context.MODE_PRIVATE) - } - - constructor(context: Context) : this() { - preference = getDefaultPreference(context) - } - - companion object { - - private val DEFAULT_STRING_VALUE: String? = null - private const val DEFAULT_INT_VALUE = 0 - private const val DEFAULT_BOOLEAN_VALUE = false - - fun getDefaultPreference(context: Context): SharedPreferences { - return PreferenceManager.getDefaultSharedPreferences(context) - } - - fun writePrefString(context: Context, key: String, value: String?) { - PrefsHelper(context).prefEditor.putString(key, value).commit() - } - - fun readPrefString(context: Context, key: String): String? { - return PrefsHelper(context).preference.getString(key, DEFAULT_STRING_VALUE) - } - - fun writePrefInt(context: Context, key: String, value: Int) { - PrefsHelper(context).prefEditor.putInt(key, value).commit() - } - - fun readPrefInt(context: Context, key: String): Int { - return PrefsHelper(context).preference.getInt(key, DEFAULT_INT_VALUE) - } - - fun writePrefBool(context: Context, key: String, value: Boolean) { - PrefsHelper(context).prefEditor.putBoolean(key, value).commit() - } - - fun readPrefBool(context: Context, key: String): Boolean { - return PrefsHelper(context).preference.getBoolean(key, DEFAULT_BOOLEAN_VALUE) - } - - fun clearPreference(context: Context) { - PrefsHelper(context).preference.edit().clear().apply() - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/SettingUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/SettingUtils.kt index d9d4f441..c9e2f4b5 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/SettingUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/SettingUtils.kt @@ -7,7 +7,7 @@ class SettingUtils private constructor() { companion object { //是否是第一次启动 - var isFirstOpen: Boolean by SharedPreference(IS_FIRST_OPEN_KEY, true) + //var isFirstOpen: Boolean by SharedPreference(IS_FIRST_OPEN_KEY, true) //是否同意隐私政策 var isAgreePrivacy: Boolean by SharedPreference(IS_AGREE_PRIVACY_KEY, false) diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sdkinit/UMengInit.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sdkinit/UMengInit.kt index 52d90dc7..5a98280d 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/sdkinit/UMengInit.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sdkinit/UMengInit.kt @@ -74,9 +74,6 @@ class UMengInit private constructor() { /** * 获取渠道信息 - * - * @param context - * @return */ private fun getChannel(): String { //context: Context? //return WalleChannelReader.getChannel(context!!, DEFAULT_CHANNEL_ID) diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/BarkUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/BarkUtils.kt index 06f7d875..1c161e40 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/BarkUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/BarkUtils.kt @@ -15,7 +15,6 @@ import com.xuexiang.xhttp2.callback.SimpleCallBack import com.xuexiang.xhttp2.exception.ApiException import java.util.regex.Pattern -@Suppress("PrivatePropertyName", "UNUSED_PARAMETER", "unused") class BarkUtils { companion object { diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/DingtalkGroupRobotUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/DingtalkGroupRobotUtils.kt index debcb5ae..82f8c1cd 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/DingtalkGroupRobotUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/DingtalkGroupRobotUtils.kt @@ -20,7 +20,6 @@ import javax.crypto.Mac import javax.crypto.spec.SecretKeySpec //钉钉群自定义机器人 -@Suppress("PrivatePropertyName", "UNUSED_PARAMETER") class DingtalkGroupRobotUtils private constructor() { companion object { diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/DingtalkInnerRobotUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/DingtalkInnerRobotUtils.kt index 35fe30e2..9708b032 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/DingtalkInnerRobotUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/DingtalkInnerRobotUtils.kt @@ -26,7 +26,6 @@ import java.net.PasswordAuthentication import java.net.Proxy //钉钉企业内机器人 -@Suppress("PrivatePropertyName", "UNUSED_PARAMETER") class DingtalkInnerRobotUtils private constructor() { companion object { diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/EmailUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/EmailUtils.kt index 5b06a80c..b999242c 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/EmailUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/EmailUtils.kt @@ -11,11 +11,10 @@ import com.idormy.sms.forwarder.utils.mail.Mail import com.idormy.sms.forwarder.utils.mail.MailSender import com.xuexiang.xui.utils.ResUtils -@Suppress("PrivatePropertyName", "UNUSED_PARAMETER", "unused") class EmailUtils { companion object { - private val TAG: String = EmailUtils::class.java.simpleName + //private val TAG: String = EmailUtils::class.java.simpleName fun sendMsg( setting: EmailSetting, diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/FeishuAppUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/FeishuAppUtils.kt index 588c15af..6b8bee17 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/FeishuAppUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/FeishuAppUtils.kt @@ -18,7 +18,6 @@ import com.xuexiang.xhttp2.exception.ApiException import com.xuexiang.xui.utils.ResUtils.getString //飞书企业应用 -@Suppress("PrivatePropertyName", "UNUSED_PARAMETER") class FeishuAppUtils private constructor() { companion object { diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/FeishuUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/FeishuUtils.kt index b09a82dd..5c8185cd 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/FeishuUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/FeishuUtils.kt @@ -19,7 +19,6 @@ import java.util.* import javax.crypto.Mac import javax.crypto.spec.SecretKeySpec -@Suppress("PrivatePropertyName", "UNUSED_PARAMETER") class FeishuUtils private constructor() { companion object { diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/GotifyUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/GotifyUtils.kt index 5a1df0f6..406eea79 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/GotifyUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/GotifyUtils.kt @@ -13,7 +13,6 @@ import com.xuexiang.xhttp2.cache.model.CacheMode import com.xuexiang.xhttp2.callback.SimpleCallBack import com.xuexiang.xhttp2.exception.ApiException -@Suppress("PrivatePropertyName", "UNUSED_PARAMETER", "unused") class GotifyUtils { companion object { diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/PushplusUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/PushplusUtils.kt index cd51f139..67d3f98e 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/PushplusUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/PushplusUtils.kt @@ -16,8 +16,6 @@ import com.xuexiang.xhttp2.callback.SimpleCallBack import com.xuexiang.xhttp2.exception.ApiException import com.xuexiang.xui.utils.ResUtils - -@Suppress("PrivatePropertyName", "UNUSED_PARAMETER") class PushplusUtils private constructor() { companion object { diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/ServerchanUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/ServerchanUtils.kt index c2070913..d292e42c 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/ServerchanUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/ServerchanUtils.kt @@ -14,7 +14,6 @@ import com.xuexiang.xhttp2.cache.model.CacheMode import com.xuexiang.xhttp2.callback.SimpleCallBack import com.xuexiang.xhttp2.exception.ApiException -@Suppress("PrivatePropertyName", "UNUSED_PARAMETER", "unused") class ServerchanUtils { companion object { diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/SmsUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/SmsUtils.kt index e5f49164..1223c6c1 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/SmsUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/SmsUtils.kt @@ -16,7 +16,6 @@ import com.xuexiang.xui.utils.ResUtils import com.xuexiang.xutil.XUtil import com.xuexiang.xutil.net.NetworkUtils -@Suppress("PrivatePropertyName", "UNUSED_PARAMETER", "unused") class SmsUtils { companion object { diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/SocketUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/SocketUtils.kt index 26bb5ea0..807bee29 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/SocketUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/SocketUtils.kt @@ -23,7 +23,6 @@ import java.util.* import javax.crypto.Mac import javax.crypto.spec.SecretKeySpec -@Suppress("PrivatePropertyName", "UNUSED_PARAMETER", "unused") class SocketUtils { companion object { diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/TelegramUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/TelegramUtils.kt index a06d2b30..45891adb 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/TelegramUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/TelegramUtils.kt @@ -19,8 +19,6 @@ import okhttp3.Response import okhttp3.Route import java.net.* - -@Suppress("PrivatePropertyName", "UNUSED_PARAMETER", "unused") class TelegramUtils private constructor() { companion object { diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/UrlSchemeUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/UrlSchemeUtils.kt index f45e1af0..baee6f06 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/UrlSchemeUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/UrlSchemeUtils.kt @@ -15,8 +15,6 @@ import java.net.URLEncoder import java.text.SimpleDateFormat import java.util.* - -@Suppress("PrivatePropertyName", "UNUSED_PARAMETER") class UrlSchemeUtils private constructor() { companion object { diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/WebhookUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/WebhookUtils.kt index 73e95520..51db1bba 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/WebhookUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/WebhookUtils.kt @@ -22,7 +22,6 @@ import java.util.* import javax.crypto.Mac import javax.crypto.spec.SecretKeySpec -@Suppress("PrivatePropertyName", "UNUSED_PARAMETER", "unused") class WebhookUtils { companion object { @@ -114,7 +113,7 @@ class WebhookUtils { } Log.d(TAG, "method = GET, Url = $requestUrl") XHttp.get(requestUrl).keepJson(true) - } else if (webParams != null && webParams.isNotEmpty() && webParams.startsWith("{")) { + } else if (!webParams.isNullOrEmpty() && webParams.startsWith("{")) { val bodyMsg = webParams.replace("[from]", from) .replace("[content]", escapeJson(content)) .replace("[msg]", escapeJson(content)) @@ -133,7 +132,7 @@ class WebhookUtils { else -> XHttp.post(requestUrl).keepJson(true).upJson(bodyMsg) } } else { - if (webParams == null || webParams.isEmpty()) { + if (webParams.isNullOrEmpty()) { webParams = "from=[from]&content=[content]×tamp=[timestamp]" if (!TextUtils.isEmpty(sign)) webParams += "&sign=[sign]" } diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/WeworkAgentUtils.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/WeworkAgentUtils.kt index 8219a5ca..ca21e791 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/sender/WeworkAgentUtils.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/sender/WeworkAgentUtils.kt @@ -26,7 +26,6 @@ import java.net.InetSocketAddress import java.net.PasswordAuthentication import java.net.Proxy -@Suppress("PrivatePropertyName", "UNUSED_PARAMETER") class WeworkAgentUtils private constructor() { companion object { diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/service/JsonSerializationService.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/service/JsonSerializationService.kt deleted file mode 100644 index 42fabe2b..00000000 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/service/JsonSerializationService.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.idormy.sms.forwarder.utils.service - -import android.content.Context -import com.xuexiang.xrouter.annotation.Router -import com.xuexiang.xrouter.facade.service.SerializationService -import com.xuexiang.xutil.net.JsonUtil -import java.lang.reflect.Type - -/** - * @author XUE - * @since 2019/3/27 16:39 - */ -@Router(path = "/service/json") -class JsonSerializationService : SerializationService { - /** - * 对象序列化为json - * - * @param instance obj - * @return json string - */ - override fun object2Json(instance: Any): String { - return JsonUtil.toJson(instance) - } - - /** - * json反序列化为对象 - * - * @param input json string - * @param clazz object type - * @return instance of object - */ - override fun parseObject(input: String, clazz: Type): T { - return JsonUtil.fromJson(input, clazz) - } - - /** - * 进程初始化的方法 - * - * @param context 上下文 - */ - override fun init(context: Context) {} -} \ No newline at end of file diff --git a/app/src/main/java/com/idormy/sms/forwarder/utils/tinker/ShareReflectUtil.kt b/app/src/main/java/com/idormy/sms/forwarder/utils/tinker/ShareReflectUtil.kt index a1bc3e17..319982fd 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/utils/tinker/ShareReflectUtil.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/utils/tinker/ShareReflectUtil.kt @@ -1,240 +1,240 @@ -package com.idormy.sms.forwarder.utils.tinker - -import android.annotation.SuppressLint -import android.content.Context -import java.lang.reflect.Constructor -import java.lang.reflect.Field -import java.lang.reflect.Method - -@Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS", "UNCHECKED_CAST", "SENSELESS_COMPARISON", "unused") -object ShareReflectUtil { - /** - * Locates a given field anywhere in the class inheritance hierarchy. - * - * @param instance an object to search the field into. - * @param name field name - * @return a field object - * @throws NoSuchFieldException if the field cannot be located - */ - @Throws(NoSuchFieldException::class) - fun findField(instance: Any, name: String): Field { - var clazz: Class<*>? = instance.javaClass - while (clazz != null) { - try { - val field = clazz.getDeclaredField(name) - if (!field.isAccessible) { - field.isAccessible = true - } - return field - } catch (e: NoSuchFieldException) { - // ignore and search next - } - clazz = clazz.superclass - } - throw NoSuchFieldException("Field " + name + " not found in " + instance.javaClass) - } - - @Throws(NoSuchFieldException::class) - fun findField(originClazz: Class<*>, name: String): Field { - var clazz: Class<*>? = originClazz - while (clazz != null) { - try { - val field = clazz.getDeclaredField(name) - if (!field.isAccessible) { - field.isAccessible = true - } - return field - } catch (e: NoSuchFieldException) { - // ignore and search next - } - clazz = clazz.superclass - } - throw NoSuchFieldException("Field $name not found in $originClazz") - } - - /** - * Locates a given method anywhere in the class inheritance hierarchy. - * - * @param instance an object to search the method into. - * @param name method name - * @param parameterTypes method parameter types - * @return a method object - * @throws NoSuchMethodException if the method cannot be located - */ - @Throws(NoSuchMethodException::class) - fun findMethod(instance: Any, name: String, vararg parameterTypes: Class<*>?): Method { - var clazz: Class<*>? = instance.javaClass - while (clazz != null) { - try { - val method = clazz.getDeclaredMethod(name, *parameterTypes) - if (!method.isAccessible) { - method.isAccessible = true - } - return method - } catch (e: NoSuchMethodException) { - // ignore and search next - } - clazz = clazz.superclass - } - throw NoSuchMethodException( - "Method " - + name - + " with parameters " - + listOf(*parameterTypes) - + " not found in " + instance.javaClass - ) - } - - /** - * Locates a given method anywhere in the class inheritance hierarchy. - * - * @param clazz a class to search the method into. - * @param name method name - * @param parameterTypes method parameter types - * @return a method object - * @throws NoSuchMethodException if the method cannot be located - */ - @Throws(NoSuchMethodException::class) - fun findMethod(clazz: Class<*>?, name: String, vararg parameterTypes: Class<*>?): Method { - var tClazz = clazz - while (tClazz != null) { - try { - val method = tClazz.getDeclaredMethod(name, *parameterTypes) - if (!method.isAccessible) { - method.isAccessible = true - } - return method - } catch (e: NoSuchMethodException) { - // ignore and search next - } - tClazz = tClazz.superclass - } - throw NoSuchMethodException( - "Method " - + name - + " with parameters " - + listOf(*parameterTypes) - + " not found in " + tClazz - ) - } - - /** - * Locates a given constructor anywhere in the class inheritance hierarchy. - * - * @param instance an object to search the constructor into. - * @param parameterTypes constructor parameter types - * @return a constructor object - * @throws NoSuchMethodException if the constructor cannot be located - */ - @Throws(NoSuchMethodException::class) - fun findConstructor(instance: Any, vararg parameterTypes: Class<*>?): Constructor<*> { - var clazz: Class<*>? = instance.javaClass - while (clazz != null) { - try { - val constructor = clazz.getDeclaredConstructor(*parameterTypes) - if (!constructor.isAccessible) { - constructor.isAccessible = true - } - return constructor - } catch (e: NoSuchMethodException) { - // ignore and search next - } - clazz = clazz.superclass - } - throw NoSuchMethodException( - "Constructor" - + " with parameters " - + listOf(*parameterTypes) - + " not found in " + instance.javaClass - ) - } - - /** - * Replace the value of a field containing a non null array, by a new array containing the - * elements of the original array plus the elements of extraElements. - * - * @param instance the instance whose field is to be modified. - * @param fieldName the field to modify. - * @param extraElements elements to append at the end of the array. - */ - @Throws(NoSuchFieldException::class, IllegalArgumentException::class, IllegalAccessException::class) - fun expandFieldArray(instance: Any, fieldName: String, extraElements: Array) { - val jlrField = findField(instance, fieldName) - val original = jlrField[instance] as Array - val combined = java.lang.reflect.Array.newInstance(original.javaClass.componentType, original.size + extraElements.size) as Array - - // NOTE: changed to copy extraElements first, for patch load first - System.arraycopy(extraElements, 0, combined, 0, extraElements.size) - System.arraycopy(original, 0, combined, extraElements.size, original.size) - jlrField[instance] = combined - } - - /** - * Replace the value of a field containing a non null array, by a new array containing the - * elements of the original array plus the elements of extraElements. - * - * @param instance the instance whose field is to be modified. - * @param fieldName the field to modify. - */ - @Throws(NoSuchFieldException::class, IllegalArgumentException::class, IllegalAccessException::class) - fun reduceFieldArray(instance: Any, fieldName: String, reduceSize: Int) { - if (reduceSize <= 0) { - return - } - val jlrField = findField(instance, fieldName) - val original = jlrField[instance] as Array - val finalLength = original.size - reduceSize - if (finalLength <= 0) { - return - } - val combined = java.lang.reflect.Array.newInstance(original.javaClass.componentType, finalLength) as Array - System.arraycopy(original, reduceSize, combined, 0, finalLength) - jlrField[instance] = combined - } - - @SuppressLint("PrivateApi") - fun getActivityThread( - context: Context?, - activityThread: Class<*>?, - ): Any? { - var tActivityThread = activityThread - return try { - if (tActivityThread == null) { - tActivityThread = Class.forName("android.app.ActivityThread") - } - val m = tActivityThread!!.getMethod("currentActivityThread") - m.isAccessible = true - var currentActivityThread = m.invoke(null) - if (currentActivityThread == null && context != null) { - // In older versions of Android (prior to frameworks/base 66a017b63461a22842) - // the currentActivityThread was built on thread locals, so we'll need to try - // even harder - val mLoadedApk = context.javaClass.getField("mLoadedApk") - mLoadedApk.isAccessible = true - val apk = mLoadedApk[context] - val mActivityThreadField = apk.javaClass.getDeclaredField("mActivityThread") - mActivityThreadField.isAccessible = true - currentActivityThread = mActivityThreadField[apk] - } - currentActivityThread - } catch (ignore: Throwable) { - null - } - } - - /** - * Handy method for fetching hidden integer constant value in system classes. - * - * @param clazz - * @param fieldName - * @return - */ - fun getValueOfStaticIntField(clazz: Class<*>, fieldName: String, defVal: Int): Int { - return try { - val field = findField(clazz, fieldName) - field.getInt(null) - } catch (thr: Throwable) { - defVal - } - } +package com.idormy.sms.forwarder.utils.tinker + +import android.annotation.SuppressLint +import android.content.Context +import java.lang.reflect.Constructor +import java.lang.reflect.Field +import java.lang.reflect.Method + +@Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS", "UNCHECKED_CAST", "unused") +object ShareReflectUtil { + /** + * Locates a given field anywhere in the class inheritance hierarchy. + * + * @param instance an object to search the field into. + * @param name field name + * @return a field object + * @throws NoSuchFieldException if the field cannot be located + */ + @Throws(NoSuchFieldException::class) + fun findField(instance: Any, name: String): Field { + var clazz: Class<*>? = instance.javaClass + while (clazz != null) { + try { + val field = clazz.getDeclaredField(name) + if (!field.isAccessible) { + field.isAccessible = true + } + return field + } catch (e: NoSuchFieldException) { + // ignore and search next + } + clazz = clazz.superclass + } + throw NoSuchFieldException("Field " + name + " not found in " + instance.javaClass) + } + + @Throws(NoSuchFieldException::class) + fun findField(originClazz: Class<*>, name: String): Field { + var clazz: Class<*>? = originClazz + while (clazz != null) { + try { + val field = clazz.getDeclaredField(name) + if (!field.isAccessible) { + field.isAccessible = true + } + return field + } catch (e: NoSuchFieldException) { + // ignore and search next + } + clazz = clazz.superclass + } + throw NoSuchFieldException("Field $name not found in $originClazz") + } + + /** + * Locates a given method anywhere in the class inheritance hierarchy. + * + * @param instance an object to search the method into. + * @param name method name + * @param parameterTypes method parameter types + * @return a method object + * @throws NoSuchMethodException if the method cannot be located + */ + @Throws(NoSuchMethodException::class) + fun findMethod(instance: Any, name: String, vararg parameterTypes: Class<*>?): Method { + var clazz: Class<*>? = instance.javaClass + while (clazz != null) { + try { + val method = clazz.getDeclaredMethod(name, *parameterTypes) + if (!method.isAccessible) { + method.isAccessible = true + } + return method + } catch (e: NoSuchMethodException) { + // ignore and search next + } + clazz = clazz.superclass + } + throw NoSuchMethodException( + "Method " + + name + + " with parameters " + + listOf(*parameterTypes) + + " not found in " + instance.javaClass + ) + } + + /** + * Locates a given method anywhere in the class inheritance hierarchy. + * + * @param clazz a class to search the method into. + * @param name method name + * @param parameterTypes method parameter types + * @return a method object + * @throws NoSuchMethodException if the method cannot be located + */ + @Throws(NoSuchMethodException::class) + fun findMethod(clazz: Class<*>?, name: String, vararg parameterTypes: Class<*>?): Method { + var tClazz = clazz + while (tClazz != null) { + try { + val method = tClazz.getDeclaredMethod(name, *parameterTypes) + if (!method.isAccessible) { + method.isAccessible = true + } + return method + } catch (e: NoSuchMethodException) { + // ignore and search next + } + tClazz = tClazz.superclass + } + throw NoSuchMethodException( + "Method " + + name + + " with parameters " + + listOf(*parameterTypes) + + " not found in " + tClazz + ) + } + + /** + * Locates a given constructor anywhere in the class inheritance hierarchy. + * + * @param instance an object to search the constructor into. + * @param parameterTypes constructor parameter types + * @return a constructor object + * @throws NoSuchMethodException if the constructor cannot be located + */ + @Throws(NoSuchMethodException::class) + fun findConstructor(instance: Any, vararg parameterTypes: Class<*>?): Constructor<*> { + var clazz: Class<*>? = instance.javaClass + while (clazz != null) { + try { + val constructor = clazz.getDeclaredConstructor(*parameterTypes) + if (!constructor.isAccessible) { + constructor.isAccessible = true + } + return constructor + } catch (e: NoSuchMethodException) { + // ignore and search next + } + clazz = clazz.superclass + } + throw NoSuchMethodException( + "Constructor" + + " with parameters " + + listOf(*parameterTypes) + + " not found in " + instance.javaClass + ) + } + + /** + * Replace the value of a field containing a non null array, by a new array containing the + * elements of the original array plus the elements of extraElements. + * + * @param instance the instance whose field is to be modified. + * @param fieldName the field to modify. + * @param extraElements elements to append at the end of the array. + */ + @Throws(NoSuchFieldException::class, IllegalArgumentException::class, IllegalAccessException::class) + fun expandFieldArray(instance: Any, fieldName: String, extraElements: Array) { + val jlrField = findField(instance, fieldName) + val original = jlrField[instance] as Array + val combined = java.lang.reflect.Array.newInstance(original.javaClass.componentType, original.size + extraElements.size) as Array + + // NOTE: changed to copy extraElements first, for patch load first + System.arraycopy(extraElements, 0, combined, 0, extraElements.size) + System.arraycopy(original, 0, combined, extraElements.size, original.size) + jlrField[instance] = combined + } + + /** + * Replace the value of a field containing a non null array, by a new array containing the + * elements of the original array plus the elements of extraElements. + * + * @param instance the instance whose field is to be modified. + * @param fieldName the field to modify. + */ + @Throws(NoSuchFieldException::class, IllegalArgumentException::class, IllegalAccessException::class) + fun reduceFieldArray(instance: Any, fieldName: String, reduceSize: Int) { + if (reduceSize <= 0) { + return + } + val jlrField = findField(instance, fieldName) + val original = jlrField[instance] as Array + val finalLength = original.size - reduceSize + if (finalLength <= 0) { + return + } + val combined = java.lang.reflect.Array.newInstance(original.javaClass.componentType, finalLength) as Array + System.arraycopy(original, reduceSize, combined, 0, finalLength) + jlrField[instance] = combined + } + + @SuppressLint("PrivateApi") + fun getActivityThread( + context: Context?, + activityThread: Class<*>?, + ): Any? { + var tActivityThread = activityThread + return try { + if (tActivityThread == null) { + tActivityThread = Class.forName("android.app.ActivityThread") + } + val m = tActivityThread!!.getMethod("currentActivityThread") + m.isAccessible = true + var currentActivityThread = m.invoke(null) + if (currentActivityThread == null && context != null) { + // In older versions of Android (prior to frameworks/base 66a017b63461a22842) + // the currentActivityThread was built on thread locals, so we'll need to try + // even harder + val mLoadedApk = context.javaClass.getField("mLoadedApk") + mLoadedApk.isAccessible = true + val apk = mLoadedApk[context] + val mActivityThreadField = apk.javaClass.getDeclaredField("mActivityThread") + mActivityThreadField.isAccessible = true + currentActivityThread = mActivityThreadField[apk] + } + currentActivityThread + } catch (ignore: Throwable) { + null + } + } + + /** + * Handy method for fetching hidden integer constant value in system classes. + * + * @param clazz + * @param fieldName + * @return + */ + fun getValueOfStaticIntField(clazz: Class<*>, fieldName: String, defVal: Int): Int { + return try { + val field = findField(clazz, fieldName) + field.getInt(null) + } catch (thr: Throwable) { + defVal + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/idormy/sms/forwarder/widget/GuideTipsDialog.kt b/app/src/main/java/com/idormy/sms/forwarder/widget/GuideTipsDialog.kt index e5bff1fa..5c234800 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/widget/GuideTipsDialog.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/widget/GuideTipsDialog.kt @@ -167,7 +167,7 @@ class GuideTipsDialog(context: Context?, tips: List) : ).tips, object : NoTipCallBack>() { @Throws(Throwable::class) override fun onSuccess(response: List?) { - if (response != null && response.isNotEmpty()) { + if (!response.isNullOrEmpty()) { GuideTipsDialog(context, response).show() } } diff --git a/app/src/main/java/com/idormy/sms/forwarder/workers/LoadAppListWorker.kt b/app/src/main/java/com/idormy/sms/forwarder/workers/LoadAppListWorker.kt index 9be13a4d..6ad9dab1 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/workers/LoadAppListWorker.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/workers/LoadAppListWorker.kt @@ -39,7 +39,7 @@ class LoadAppListWorker( LiveEventBus.get(EVENT_LOAD_APP_LIST, String::class.java).post("finish") App.LoadingAppList = false - Log.d("LoadAppListWorker", "LoadAppListWorker finish, App.LoadingAppList=${App.LoadingAppList}") + Log.d("LoadAppListWorker", "LoadAppListWorker finish") return@withContext Result.success() } diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml deleted file mode 100644 index 1f6bb290..00000000 --- a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml deleted file mode 100644 index 0d025f9b..00000000 --- a/app/src/main/res/drawable/ic_launcher_background.xml +++ /dev/null @@ -1,170 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml deleted file mode 100644 index 2b027f9f..00000000 --- a/app/src/main/res/drawable/ic_launcher_foreground.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_login_close.xml b/app/src/main/res/drawable/ic_login_close.xml deleted file mode 100644 index 71703bf6..00000000 --- a/app/src/main/res/drawable/ic_login_close.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_password.xml b/app/src/main/res/drawable/ic_password.xml deleted file mode 100644 index 5b4ce70d..00000000 --- a/app/src/main/res/drawable/ic_password.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - diff --git a/app/src/main/res/drawable/ic_phone.xml b/app/src/main/res/drawable/ic_phone.xml deleted file mode 100644 index 62654143..00000000 --- a/app/src/main/res/drawable/ic_phone.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/test/java/com/idormy/sms/forwarder/ExampleUnitTest.kt b/app/src/test/java/com/idormy/sms/forwarder/ExampleUnitTest.kt deleted file mode 100644 index 43adf5b9..00000000 --- a/app/src/test/java/com/idormy/sms/forwarder/ExampleUnitTest.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2022 xuexiangjys(xuexiangjys@163.com) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package com.idormy.sms.forwarder - -import com.idormy.sms.forwarder.core.http.entity.TipInfo -import com.xuexiang.xhttp2.model.ApiResult -import com.xuexiang.xutil.net.JsonUtil -import org.junit.Assert -import org.junit.Test - -/** - * Example local unit test, which will execute on the development machine (host). - * - * @see [Testing documentation](http://d.android.com/tools/testing) - */ -class ExampleUnitTest { - @Test - fun addition_isCorrect() { - Assert.assertEquals(4, (2 + 2).toLong()) - val info = TipInfo() - info.title = "微信公众号" - info.content = "获取更多资讯,欢迎关注我的微信公众号:【我的Android开源之旅】" - val list: MutableList = ArrayList() - for (i in 0..4) { - list.add(info) - } - val result = ApiResult>() - result.data = list - println(JsonUtil.toJson(result)) - } -} \ No newline at end of file