mirror of
https://github.com/pppscn/SmsForwarder
synced 2025-08-03 17:37:40 +08:00
parent
032837615f
commit
dd798e42cc
@ -202,6 +202,9 @@
|
|||||||
<service
|
<service
|
||||||
android:name=".service.HttpService"
|
android:name=".service.HttpService"
|
||||||
android:enabled="true" />
|
android:enabled="true" />
|
||||||
|
<service
|
||||||
|
android:name=".service.NetworkStateService"
|
||||||
|
android:enabled="true" />
|
||||||
<service
|
<service
|
||||||
android:name=".service.BatteryService"
|
android:name=".service.BatteryService"
|
||||||
android:enabled="true" />
|
android:enabled="true" />
|
||||||
|
@ -23,6 +23,7 @@ import com.idormy.sms.forwarder.receiver.CactusReceiver
|
|||||||
import com.idormy.sms.forwarder.service.BatteryService
|
import com.idormy.sms.forwarder.service.BatteryService
|
||||||
import com.idormy.sms.forwarder.service.ForegroundService
|
import com.idormy.sms.forwarder.service.ForegroundService
|
||||||
import com.idormy.sms.forwarder.service.HttpService
|
import com.idormy.sms.forwarder.service.HttpService
|
||||||
|
import com.idormy.sms.forwarder.service.NetworkStateService
|
||||||
import com.idormy.sms.forwarder.utils.*
|
import com.idormy.sms.forwarder.utils.*
|
||||||
import com.idormy.sms.forwarder.utils.sdkinit.UMengInit
|
import com.idormy.sms.forwarder.utils.sdkinit.UMengInit
|
||||||
import com.idormy.sms.forwarder.utils.sdkinit.XBasicLibInit
|
import com.idormy.sms.forwarder.utils.sdkinit.XBasicLibInit
|
||||||
@ -60,6 +61,7 @@ class App : Application(), CactusCallback, Configuration.Provider by Core {
|
|||||||
var SimInfoList: MutableMap<Int, SimInfo> = mutableMapOf()
|
var SimInfoList: MutableMap<Int, SimInfo> = mutableMapOf()
|
||||||
|
|
||||||
//已安装App信息
|
//已安装App信息
|
||||||
|
var LoadingAppList = false
|
||||||
var UserAppList: MutableList<AppUtils.AppInfo> = mutableListOf()
|
var UserAppList: MutableList<AppUtils.AppInfo> = mutableListOf()
|
||||||
var SystemAppList: MutableList<AppUtils.AppInfo> = mutableListOf()
|
var SystemAppList: MutableList<AppUtils.AppInfo> = mutableListOf()
|
||||||
|
|
||||||
@ -118,38 +120,14 @@ class App : Application(), CactusCallback, Configuration.Provider by Core {
|
|||||||
startService(intent)
|
startService(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//网络状态监听
|
||||||
|
val networkStateServiceIntent = Intent(this, NetworkStateService::class.java)
|
||||||
|
startService(networkStateServiceIntent)
|
||||||
|
|
||||||
//电池状态监听
|
//电池状态监听
|
||||||
val batteryServiceIntent = Intent(this, BatteryService::class.java)
|
val batteryServiceIntent = Intent(this, BatteryService::class.java)
|
||||||
startService(batteryServiceIntent)
|
startService(batteryServiceIntent)
|
||||||
|
|
||||||
//异步获取所有已安装 App 信息
|
|
||||||
if (SettingUtils.enableLoadAppList) {
|
|
||||||
val enableLoadUserAppList = SettingUtils.enableLoadUserAppList
|
|
||||||
val enableLoadSystemAppList = SettingUtils.enableLoadSystemAppList
|
|
||||||
val get = GlobalScope.async(Dispatchers.IO) {
|
|
||||||
val appInfoList = AppUtils.getAppsInfo()
|
|
||||||
for (appInfo in appInfoList) {
|
|
||||||
if (appInfo.isSystem && enableLoadSystemAppList) {
|
|
||||||
SystemAppList.add(appInfo)
|
|
||||||
} else if (enableLoadUserAppList) {
|
|
||||||
UserAppList.add(appInfo)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UserAppList.sortBy { appInfo -> appInfo.name }
|
|
||||||
SystemAppList.sortBy { appInfo -> appInfo.name }
|
|
||||||
}
|
|
||||||
GlobalScope.launch(Dispatchers.Main) {
|
|
||||||
runCatching {
|
|
||||||
get.await()
|
|
||||||
Log.d("GlobalScope", "AppUtils.getAppsInfo() Done")
|
|
||||||
//Log.d("GlobalScope", "UserAppList = $UserAppList")
|
|
||||||
//Log.d("GlobalScope", "SystemAppList = $SystemAppList")
|
|
||||||
}.onFailure {
|
|
||||||
//Log.e("GlobalScope", it.message.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//启动HttpServer
|
//启动HttpServer
|
||||||
if (HttpServerUtils.enableServerAutorun) {
|
if (HttpServerUtils.enableServerAutorun) {
|
||||||
startService(Intent(this, HttpService::class.java))
|
startService(Intent(this, HttpService::class.java))
|
||||||
|
@ -43,6 +43,8 @@ data class CloneInfo(
|
|||||||
var enableLoadSystemAppList: Boolean = false,
|
var enableLoadSystemAppList: Boolean = false,
|
||||||
@SerializedName("duplicate_messages_limits")
|
@SerializedName("duplicate_messages_limits")
|
||||||
var duplicateMessagesLimits: Int = 0,
|
var duplicateMessagesLimits: Int = 0,
|
||||||
|
@SerializedName("enable_network_state_receiver")
|
||||||
|
var enableNetworkStateReceiver: Boolean = false,
|
||||||
@SerializedName("enable_battery_receiver")
|
@SerializedName("enable_battery_receiver")
|
||||||
var enableBatteryReceiver: Boolean = false,
|
var enableBatteryReceiver: Boolean = false,
|
||||||
@SerializedName("battery_level_min")
|
@SerializedName("battery_level_min")
|
||||||
|
@ -2,16 +2,23 @@ package com.idormy.sms.forwarder.fragment
|
|||||||
|
|
||||||
import android.content.ClipData
|
import android.content.ClipData
|
||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.work.OneTimeWorkRequestBuilder
|
||||||
|
import androidx.work.WorkManager
|
||||||
import com.idormy.sms.forwarder.App
|
import com.idormy.sms.forwarder.App
|
||||||
import com.idormy.sms.forwarder.R
|
import com.idormy.sms.forwarder.R
|
||||||
import com.idormy.sms.forwarder.adapter.AppListAdapter
|
import com.idormy.sms.forwarder.adapter.AppListAdapter
|
||||||
import com.idormy.sms.forwarder.core.BaseFragment
|
import com.idormy.sms.forwarder.core.BaseFragment
|
||||||
import com.idormy.sms.forwarder.databinding.FragmentAppListBinding
|
import com.idormy.sms.forwarder.databinding.FragmentAppListBinding
|
||||||
|
import com.idormy.sms.forwarder.utils.EVENT_LOAD_APP_LIST
|
||||||
import com.idormy.sms.forwarder.utils.XToastUtils
|
import com.idormy.sms.forwarder.utils.XToastUtils
|
||||||
|
import com.idormy.sms.forwarder.workers.LoadAppListWorker
|
||||||
|
import com.jeremyliao.liveeventbus.LiveEventBus
|
||||||
import com.scwang.smartrefresh.layout.api.RefreshLayout
|
import com.scwang.smartrefresh.layout.api.RefreshLayout
|
||||||
import com.scwang.smartrefresh.layout.listener.OnRefreshLoadMoreListener
|
import com.scwang.smartrefresh.layout.listener.OnRefreshLoadMoreListener
|
||||||
import com.xuexiang.xaop.annotation.SingleClick
|
import com.xuexiang.xaop.annotation.SingleClick
|
||||||
@ -21,12 +28,19 @@ import com.xuexiang.xui.utils.ResUtils
|
|||||||
import com.xuexiang.xui.utils.ThemeUtils
|
import com.xuexiang.xui.utils.ThemeUtils
|
||||||
import com.xuexiang.xui.utils.WidgetUtils
|
import com.xuexiang.xui.utils.WidgetUtils
|
||||||
import com.xuexiang.xui.widget.actionbar.TitleBar
|
import com.xuexiang.xui.widget.actionbar.TitleBar
|
||||||
|
import com.xuexiang.xutil.XUtil
|
||||||
import com.xuexiang.xutil.app.AppUtils
|
import com.xuexiang.xutil.app.AppUtils
|
||||||
|
|
||||||
|
@Suppress("PrivatePropertyName")
|
||||||
@Page(name = "应用列表")
|
@Page(name = "应用列表")
|
||||||
class AppListFragment : BaseFragment<FragmentAppListBinding?>() {
|
class AppListFragment : BaseFragment<FragmentAppListBinding?>() {
|
||||||
|
|
||||||
|
private val TAG: String = AppListFragment::class.java.simpleName
|
||||||
var appListAdapter: AppListAdapter? = null
|
var appListAdapter: AppListAdapter? = null
|
||||||
|
private val appListObserver = Observer { it: String ->
|
||||||
|
Log.d(TAG, "EVENT_LOAD_APP_LIST: $it")
|
||||||
|
appListAdapter?.refresh(getAppsList(false))
|
||||||
|
}
|
||||||
private var currentType: String = "user"
|
private var currentType: String = "user"
|
||||||
|
|
||||||
override fun viewBindingInflate(
|
override fun viewBindingInflate(
|
||||||
@ -95,6 +109,8 @@ class AppListFragment : BaseFragment<FragmentAppListBinding?>() {
|
|||||||
binding!!.refreshLayout.setDisableContentWhenLoading(true)
|
binding!!.refreshLayout.setDisableContentWhenLoading(true)
|
||||||
appListAdapter?.refresh(getAppsList(false))
|
appListAdapter?.refresh(getAppsList(false))
|
||||||
binding!!.refreshLayout.finishRefresh()
|
binding!!.refreshLayout.finishRefresh()
|
||||||
|
//监听已安装App信息列表加载完成事件
|
||||||
|
LiveEventBus.get(EVENT_LOAD_APP_LIST, String::class.java).observeStickyForever(appListObserver)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
@ -104,18 +120,9 @@ class AppListFragment : BaseFragment<FragmentAppListBinding?>() {
|
|||||||
|
|
||||||
private fun getAppsList(refresh: Boolean): MutableList<AppUtils.AppInfo> {
|
private fun getAppsList(refresh: Boolean): MutableList<AppUtils.AppInfo> {
|
||||||
if (refresh || (currentType == "user" && App.UserAppList.isEmpty()) || (currentType == "system" && App.SystemAppList.isEmpty())) {
|
if (refresh || (currentType == "user" && App.UserAppList.isEmpty()) || (currentType == "system" && App.SystemAppList.isEmpty())) {
|
||||||
App.UserAppList.clear()
|
XToastUtils.info(getString(R.string.loading_app_list))
|
||||||
App.SystemAppList.clear()
|
val request = OneTimeWorkRequestBuilder<LoadAppListWorker>().build()
|
||||||
val appInfoList = AppUtils.getAppsInfo()
|
WorkManager.getInstance(XUtil.getContext()).enqueue(request)
|
||||||
for (appInfo in appInfoList) {
|
|
||||||
if (appInfo.isSystem) {
|
|
||||||
App.SystemAppList.add(appInfo)
|
|
||||||
} else {
|
|
||||||
App.UserAppList.add(appInfo)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
App.UserAppList.sortBy { appInfo -> appInfo.name }
|
|
||||||
App.SystemAppList.sortBy { appInfo -> appInfo.name }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return if (currentType == "system") App.SystemAppList else App.UserAppList
|
return if (currentType == "system") App.SystemAppList else App.UserAppList
|
||||||
|
@ -8,6 +8,9 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.*
|
import android.widget.*
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.work.OneTimeWorkRequestBuilder
|
||||||
|
import androidx.work.WorkManager
|
||||||
import com.idormy.sms.forwarder.App
|
import com.idormy.sms.forwarder.App
|
||||||
import com.idormy.sms.forwarder.R
|
import com.idormy.sms.forwarder.R
|
||||||
import com.idormy.sms.forwarder.adapter.spinner.AppListAdapterItem
|
import com.idormy.sms.forwarder.adapter.spinner.AppListAdapterItem
|
||||||
@ -23,6 +26,8 @@ import com.idormy.sms.forwarder.database.viewmodel.RuleViewModel
|
|||||||
import com.idormy.sms.forwarder.databinding.FragmentRulesEditBinding
|
import com.idormy.sms.forwarder.databinding.FragmentRulesEditBinding
|
||||||
import com.idormy.sms.forwarder.entity.MsgInfo
|
import com.idormy.sms.forwarder.entity.MsgInfo
|
||||||
import com.idormy.sms.forwarder.utils.*
|
import com.idormy.sms.forwarder.utils.*
|
||||||
|
import com.idormy.sms.forwarder.workers.LoadAppListWorker
|
||||||
|
import com.jeremyliao.liveeventbus.LiveEventBus
|
||||||
import com.xuexiang.xaop.annotation.SingleClick
|
import com.xuexiang.xaop.annotation.SingleClick
|
||||||
import com.xuexiang.xpage.annotation.Page
|
import com.xuexiang.xpage.annotation.Page
|
||||||
import com.xuexiang.xrouter.annotation.AutoWired
|
import com.xuexiang.xrouter.annotation.AutoWired
|
||||||
@ -32,7 +37,7 @@ import com.xuexiang.xui.utils.ResUtils
|
|||||||
import com.xuexiang.xui.widget.actionbar.TitleBar
|
import com.xuexiang.xui.widget.actionbar.TitleBar
|
||||||
import com.xuexiang.xui.widget.dialog.materialdialog.DialogAction
|
import com.xuexiang.xui.widget.dialog.materialdialog.DialogAction
|
||||||
import com.xuexiang.xui.widget.dialog.materialdialog.MaterialDialog
|
import com.xuexiang.xui.widget.dialog.materialdialog.MaterialDialog
|
||||||
import com.xuexiang.xutil.app.AppUtils
|
import com.xuexiang.xutil.XUtil
|
||||||
import io.reactivex.SingleObserver
|
import io.reactivex.SingleObserver
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
import io.reactivex.disposables.Disposable
|
import io.reactivex.disposables.Disposable
|
||||||
@ -61,6 +66,10 @@ class RulesEditFragment : BaseFragment<FragmentRulesEditBinding?>(), View.OnClic
|
|||||||
//已安装App信息列表
|
//已安装App信息列表
|
||||||
private val appListSpinnerList = ArrayList<AppListAdapterItem>()
|
private val appListSpinnerList = ArrayList<AppListAdapterItem>()
|
||||||
private lateinit var appListSpinnerAdapter: AppListSpinnerAdapter<*>
|
private lateinit var appListSpinnerAdapter: AppListSpinnerAdapter<*>
|
||||||
|
private val appListObserver = Observer { it: String ->
|
||||||
|
Log.d(TAG, "EVENT_LOAD_APP_LIST: $it")
|
||||||
|
initAppSpinner()
|
||||||
|
}
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
@AutoWired(name = KEY_RULE_ID)
|
@AutoWired(name = KEY_RULE_ID)
|
||||||
@ -105,6 +114,10 @@ class RulesEditFragment : BaseFragment<FragmentRulesEditBinding?>(), View.OnClic
|
|||||||
binding!!.btInsertExtra.visibility = View.GONE
|
binding!!.btInsertExtra.visibility = View.GONE
|
||||||
binding!!.btInsertSender.visibility = View.GONE
|
binding!!.btInsertSender.visibility = View.GONE
|
||||||
binding!!.btInsertContent.visibility = View.GONE
|
binding!!.btInsertContent.visibility = View.GONE
|
||||||
|
//初始化APP下拉列表
|
||||||
|
initAppSpinner()
|
||||||
|
//监听已安装App信息列表加载完成事件
|
||||||
|
LiveEventBus.get(EVENT_LOAD_APP_LIST, String::class.java).observeStickyForever(appListObserver)
|
||||||
}
|
}
|
||||||
"call" -> {
|
"call" -> {
|
||||||
titleBar?.setTitle(R.string.call_rule)
|
titleBar?.setTitle(R.string.call_rule)
|
||||||
@ -136,8 +149,6 @@ class RulesEditFragment : BaseFragment<FragmentRulesEditBinding?>(), View.OnClic
|
|||||||
initForm()
|
initForm()
|
||||||
}
|
}
|
||||||
|
|
||||||
//初始化APP下拉列表
|
|
||||||
initAppSpinner()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun initListeners() {
|
override fun initListeners() {
|
||||||
@ -408,68 +419,48 @@ class RulesEditFragment : BaseFragment<FragmentRulesEditBinding?>(), View.OnClic
|
|||||||
}
|
}
|
||||||
|
|
||||||
//初始化APP下拉列表
|
//初始化APP下拉列表
|
||||||
@OptIn(DelicateCoroutinesApi::class)
|
|
||||||
private fun initAppSpinner() {
|
private fun initAppSpinner() {
|
||||||
if (ruleType != "app") return
|
if (ruleType != "app") return
|
||||||
|
|
||||||
//未开启异步获取已安装App信息开关时,规则编辑不显示已安装APP下拉框
|
//未开启异步获取已安装App信息开关时,规则编辑不显示已安装APP下拉框
|
||||||
if (!SettingUtils.enableLoadUserAppList && !SettingUtils.enableLoadSystemAppList) return
|
if (!SettingUtils.enableLoadUserAppList && !SettingUtils.enableLoadSystemAppList) return
|
||||||
|
|
||||||
val get = GlobalScope.async(Dispatchers.IO) {
|
if (App.UserAppList.isEmpty() && App.SystemAppList.isEmpty()) {
|
||||||
if ((SettingUtils.enableLoadUserAppList && App.UserAppList.isEmpty()) || (SettingUtils.enableLoadSystemAppList && App.SystemAppList.isEmpty())) {
|
XToastUtils.info(getString(R.string.loading_app_list))
|
||||||
App.UserAppList.clear()
|
val request = OneTimeWorkRequestBuilder<LoadAppListWorker>().build()
|
||||||
App.SystemAppList.clear()
|
WorkManager.getInstance(XUtil.getContext()).enqueue(request)
|
||||||
val appInfoList = AppUtils.getAppsInfo()
|
return
|
||||||
for (appInfo in appInfoList) {
|
}
|
||||||
if (appInfo.isSystem) {
|
|
||||||
App.SystemAppList.add(appInfo)
|
appListSpinnerList.clear()
|
||||||
} else {
|
if (SettingUtils.enableLoadUserAppList) {
|
||||||
App.UserAppList.add(appInfo)
|
for (appInfo in App.UserAppList) {
|
||||||
}
|
if (TextUtils.isEmpty(appInfo.packageName)) continue
|
||||||
}
|
appListSpinnerList.add(AppListAdapterItem(appInfo.name, appInfo.icon, appInfo.packageName))
|
||||||
App.UserAppList.sortBy { appInfo -> appInfo.name }
|
|
||||||
App.SystemAppList.sortBy { appInfo -> appInfo.name }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GlobalScope.launch(Dispatchers.Main) {
|
if (SettingUtils.enableLoadSystemAppList) {
|
||||||
runCatching {
|
for (appInfo in App.SystemAppList) {
|
||||||
get.await()
|
if (TextUtils.isEmpty(appInfo.packageName)) continue
|
||||||
if (App.UserAppList.isEmpty() && App.SystemAppList.isEmpty()) return@runCatching
|
appListSpinnerList.add(AppListAdapterItem(appInfo.name, appInfo.icon, appInfo.packageName))
|
||||||
|
|
||||||
appListSpinnerList.clear()
|
|
||||||
if (SettingUtils.enableLoadUserAppList) {
|
|
||||||
for (appInfo in App.UserAppList) {
|
|
||||||
appListSpinnerList.add(AppListAdapterItem(appInfo.name, appInfo.icon, appInfo.packageName))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (SettingUtils.enableLoadSystemAppList) {
|
|
||||||
for (appInfo in App.SystemAppList) {
|
|
||||||
appListSpinnerList.add(AppListAdapterItem(appInfo.name, appInfo.icon, appInfo.packageName))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//列表为空也不显示下拉框
|
|
||||||
if (appListSpinnerList.isEmpty()) return@runCatching
|
|
||||||
|
|
||||||
appListSpinnerAdapter = AppListSpinnerAdapter(appListSpinnerList)
|
|
||||||
//.setTextColor(ResUtils.getColor(R.color.green))
|
|
||||||
//.setTextSize(12F)
|
|
||||||
.setIsFilterKey(true).setFilterColor("#EF5362").setBackgroundSelector(R.drawable.selector_custom_spinner_bg)
|
|
||||||
binding!!.spApp.setAdapter(appListSpinnerAdapter)
|
|
||||||
binding!!.spApp.setOnItemClickListener { _: AdapterView<*>, _: View, position: Int, _: Long ->
|
|
||||||
try {
|
|
||||||
//val appInfo = appListSpinnerList[position]
|
|
||||||
val appInfo = appListSpinnerAdapter.getItemSource(position) as AppListAdapterItem
|
|
||||||
CommonUtils.insertOrReplaceText2Cursor(binding!!.etValue, appInfo.packageName.toString())
|
|
||||||
} catch (e: Exception) {
|
|
||||||
XToastUtils.error(e.message.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
binding!!.layoutAppList.visibility = View.VISIBLE
|
|
||||||
}.onFailure {
|
|
||||||
Log.e("GlobalScope", it.message.toString())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//列表为空也不显示下拉框
|
||||||
|
if (appListSpinnerList.isEmpty()) return
|
||||||
|
|
||||||
|
appListSpinnerAdapter = AppListSpinnerAdapter(appListSpinnerList).setIsFilterKey(true).setFilterColor("#EF5362").setBackgroundSelector(R.drawable.selector_custom_spinner_bg)
|
||||||
|
binding!!.spApp.setAdapter(appListSpinnerAdapter)
|
||||||
|
binding!!.spApp.setOnItemClickListener { _: AdapterView<*>, _: View, position: Int, _: Long ->
|
||||||
|
try {
|
||||||
|
val appInfo = appListSpinnerAdapter.getItemSource(position) as AppListAdapterItem
|
||||||
|
CommonUtils.insertOrReplaceText2Cursor(binding!!.etValue, appInfo.packageName.toString())
|
||||||
|
} catch (e: Exception) {
|
||||||
|
XToastUtils.error(e.message.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
binding!!.layoutAppList.visibility = View.VISIBLE
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//初始化表单
|
//初始化表单
|
||||||
|
@ -18,6 +18,9 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.*
|
import android.widget.*
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.work.OneTimeWorkRequestBuilder
|
||||||
|
import androidx.work.WorkManager
|
||||||
import com.hjq.permissions.OnPermissionCallback
|
import com.hjq.permissions.OnPermissionCallback
|
||||||
import com.hjq.permissions.Permission
|
import com.hjq.permissions.Permission
|
||||||
import com.hjq.permissions.XXPermissions
|
import com.hjq.permissions.XXPermissions
|
||||||
@ -30,6 +33,7 @@ import com.idormy.sms.forwarder.databinding.FragmentSettingsBinding
|
|||||||
import com.idormy.sms.forwarder.entity.SimInfo
|
import com.idormy.sms.forwarder.entity.SimInfo
|
||||||
import com.idormy.sms.forwarder.receiver.BootReceiver
|
import com.idormy.sms.forwarder.receiver.BootReceiver
|
||||||
import com.idormy.sms.forwarder.utils.*
|
import com.idormy.sms.forwarder.utils.*
|
||||||
|
import com.idormy.sms.forwarder.workers.LoadAppListWorker
|
||||||
import com.jeremyliao.liveeventbus.LiveEventBus
|
import com.jeremyliao.liveeventbus.LiveEventBus
|
||||||
import com.xuexiang.xaop.annotation.SingleClick
|
import com.xuexiang.xaop.annotation.SingleClick
|
||||||
import com.xuexiang.xpage.annotation.Page
|
import com.xuexiang.xpage.annotation.Page
|
||||||
@ -46,13 +50,11 @@ import com.xuexiang.xui.widget.picker.widget.builder.TimePickerBuilder
|
|||||||
import com.xuexiang.xui.widget.picker.widget.listener.OnOptionsSelectListener
|
import com.xuexiang.xui.widget.picker.widget.listener.OnOptionsSelectListener
|
||||||
import com.xuexiang.xutil.XUtil
|
import com.xuexiang.xutil.XUtil
|
||||||
import com.xuexiang.xutil.XUtil.getPackageManager
|
import com.xuexiang.xutil.XUtil.getPackageManager
|
||||||
import com.xuexiang.xutil.app.AppUtils
|
|
||||||
import com.xuexiang.xutil.app.AppUtils.getAppPackageName
|
import com.xuexiang.xutil.app.AppUtils.getAppPackageName
|
||||||
import com.xuexiang.xutil.data.DateUtils
|
import com.xuexiang.xutil.data.DateUtils
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
@Suppress("PropertyName", "SpellCheckingInspection")
|
@Suppress("PropertyName", "SpellCheckingInspection")
|
||||||
@Page(name = "通用设置")
|
@Page(name = "通用设置")
|
||||||
class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickListener {
|
class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickListener {
|
||||||
@ -63,6 +65,10 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
|||||||
//已安装App信息列表
|
//已安装App信息列表
|
||||||
private val appListSpinnerList = ArrayList<AppListAdapterItem>()
|
private val appListSpinnerList = ArrayList<AppListAdapterItem>()
|
||||||
private lateinit var appListSpinnerAdapter: AppListSpinnerAdapter<*>
|
private lateinit var appListSpinnerAdapter: AppListSpinnerAdapter<*>
|
||||||
|
private val appListObserver = Observer { it: String ->
|
||||||
|
Log.d(TAG, "EVENT_LOAD_APP_LIST: $it")
|
||||||
|
initAppSpinner()
|
||||||
|
}
|
||||||
|
|
||||||
override fun viewBindingInflate(
|
override fun viewBindingInflate(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
@ -110,6 +116,9 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
|||||||
SettingUtils.autoCleanLogsDays = newValue
|
SettingUtils.autoCleanLogsDays = newValue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//监听网络状态变化
|
||||||
|
switchNetworkStateReceiver(binding!!.sbNetworkStateReceiver)
|
||||||
|
|
||||||
//监听电池状态变化
|
//监听电池状态变化
|
||||||
switchBatteryReceiver(binding!!.sbBatteryReceiver)
|
switchBatteryReceiver(binding!!.sbBatteryReceiver)
|
||||||
//电量预警
|
//电量预警
|
||||||
@ -157,7 +166,10 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
|||||||
|
|
||||||
//纯客户端模式
|
//纯客户端模式
|
||||||
switchDirectlyToClient(binding!!.sbDirectlyToClient)
|
switchDirectlyToClient(binding!!.sbDirectlyToClient)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
//初始化APP下拉列表
|
//初始化APP下拉列表
|
||||||
initAppSpinner()
|
initAppSpinner()
|
||||||
}
|
}
|
||||||
@ -172,6 +184,10 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
|||||||
binding!!.btInsertExtra.setOnClickListener(this)
|
binding!!.btInsertExtra.setOnClickListener(this)
|
||||||
binding!!.btInsertTime.setOnClickListener(this)
|
binding!!.btInsertTime.setOnClickListener(this)
|
||||||
binding!!.btInsertDeviceName.setOnClickListener(this)
|
binding!!.btInsertDeviceName.setOnClickListener(this)
|
||||||
|
|
||||||
|
//监听已安装App信息列表加载完成事件
|
||||||
|
LiveEventBus.get(EVENT_LOAD_APP_LIST, String::class.java).observeStickyForever(appListObserver)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
@ -433,20 +449,18 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
|||||||
SettingUtils.enableAppNotify = isChecked
|
SettingUtils.enableAppNotify = isChecked
|
||||||
if (isChecked) {
|
if (isChecked) {
|
||||||
//检查权限是否获取
|
//检查权限是否获取
|
||||||
XXPermissions.with(this)
|
XXPermissions.with(this).permission(Permission.BIND_NOTIFICATION_LISTENER_SERVICE).request(OnPermissionCallback { _, allGranted ->
|
||||||
.permission(Permission.BIND_NOTIFICATION_LISTENER_SERVICE)
|
if (!allGranted) {
|
||||||
.request(OnPermissionCallback { _, allGranted ->
|
SettingUtils.enableAppNotify = false
|
||||||
if (!allGranted) {
|
sbEnableAppNotify.isChecked = false
|
||||||
SettingUtils.enableAppNotify = false
|
XToastUtils.error(R.string.tips_notification_listener)
|
||||||
sbEnableAppNotify.isChecked = false
|
return@OnPermissionCallback
|
||||||
XToastUtils.error(R.string.tips_notification_listener)
|
}
|
||||||
return@OnPermissionCallback
|
|
||||||
}
|
|
||||||
|
|
||||||
SettingUtils.enableAppNotify = true
|
SettingUtils.enableAppNotify = true
|
||||||
sbEnableAppNotify.isChecked = true
|
sbEnableAppNotify.isChecked = true
|
||||||
CommonUtils.toggleNotificationListenerService(requireContext())
|
CommonUtils.toggleNotificationListenerService(requireContext())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
scbCancelAppNotify.isChecked = SettingUtils.enableCancelAppNotify
|
scbCancelAppNotify.isChecked = SettingUtils.enableCancelAppNotify
|
||||||
@ -487,6 +501,10 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
|||||||
return@setOnCheckedChangeListener
|
return@setOnCheckedChangeListener
|
||||||
}
|
}
|
||||||
SettingUtils.enableLoadAppList = isChecked
|
SettingUtils.enableLoadAppList = isChecked
|
||||||
|
|
||||||
|
XToastUtils.info(getString(R.string.loading_app_list))
|
||||||
|
val request = OneTimeWorkRequestBuilder<LoadAppListWorker>().build()
|
||||||
|
WorkManager.getInstance(XUtil.getContext()).enqueue(request)
|
||||||
}
|
}
|
||||||
scbLoadUserApp.isChecked = SettingUtils.enableLoadUserAppList
|
scbLoadUserApp.isChecked = SettingUtils.enableLoadUserAppList
|
||||||
scbLoadUserApp.setOnCheckedChangeListener { _: SmoothCheckBox, isChecked: Boolean ->
|
scbLoadUserApp.setOnCheckedChangeListener { _: SmoothCheckBox, isChecked: Boolean ->
|
||||||
@ -496,6 +514,13 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
|||||||
SettingUtils.enableLoadAppList = false
|
SettingUtils.enableLoadAppList = false
|
||||||
XToastUtils.error(getString(R.string.load_app_list_toast))
|
XToastUtils.error(getString(R.string.load_app_list_toast))
|
||||||
}
|
}
|
||||||
|
if (isChecked && SettingUtils.enableLoadAppList && App.UserAppList.isEmpty()) {
|
||||||
|
XToastUtils.info(getString(R.string.loading_app_list))
|
||||||
|
val request = OneTimeWorkRequestBuilder<LoadAppListWorker>().build()
|
||||||
|
WorkManager.getInstance(XUtil.getContext()).enqueue(request)
|
||||||
|
} else {
|
||||||
|
initAppSpinner()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
scbLoadSystemApp.isChecked = SettingUtils.enableLoadSystemAppList
|
scbLoadSystemApp.isChecked = SettingUtils.enableLoadSystemAppList
|
||||||
scbLoadSystemApp.setOnCheckedChangeListener { _: SmoothCheckBox, isChecked: Boolean ->
|
scbLoadSystemApp.setOnCheckedChangeListener { _: SmoothCheckBox, isChecked: Boolean ->
|
||||||
@ -505,6 +530,22 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
|||||||
SettingUtils.enableLoadAppList = false
|
SettingUtils.enableLoadAppList = false
|
||||||
XToastUtils.error(getString(R.string.load_app_list_toast))
|
XToastUtils.error(getString(R.string.load_app_list_toast))
|
||||||
}
|
}
|
||||||
|
if (isChecked && SettingUtils.enableLoadAppList && App.SystemAppList.isEmpty()) {
|
||||||
|
XToastUtils.info(getString(R.string.loading_app_list))
|
||||||
|
val request = OneTimeWorkRequestBuilder<LoadAppListWorker>().build()
|
||||||
|
WorkManager.getInstance(XUtil.getContext()).enqueue(request)
|
||||||
|
} else {
|
||||||
|
initAppSpinner()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//监听网络状态变化
|
||||||
|
@SuppressLint("UseSwitchCompatOrMaterialCode")
|
||||||
|
fun switchNetworkStateReceiver(sbNetworkStateReceiver: SwitchButton) {
|
||||||
|
sbNetworkStateReceiver.isChecked = SettingUtils.enableNetworkStateReceiver
|
||||||
|
sbNetworkStateReceiver.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
|
||||||
|
SettingUtils.enableNetworkStateReceiver = isChecked
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -553,8 +594,6 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
|||||||
sbBatteryCron.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
|
sbBatteryCron.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
|
||||||
binding!!.layoutBatteryCron.visibility = if (isChecked) View.VISIBLE else View.GONE
|
binding!!.layoutBatteryCron.visibility = if (isChecked) View.VISIBLE else View.GONE
|
||||||
SettingUtils.enableBatteryCron = isChecked
|
SettingUtils.enableBatteryCron = isChecked
|
||||||
//TODO:BatteryReportCronTask
|
|
||||||
//BatteryReportCronTask.getSingleton().updateTimer()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -568,11 +607,7 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
|||||||
calendar.time = DateUtils.getNowDate()
|
calendar.time = DateUtils.getNowDate()
|
||||||
val mTimePicker = TimePickerBuilder(context) { date: Date?, _: View? ->
|
val mTimePicker = TimePickerBuilder(context) { date: Date?, _: View? ->
|
||||||
etBatteryCronStartTime.setText(DateUtils.date2String(date, DateUtils.HHmm.get()))
|
etBatteryCronStartTime.setText(DateUtils.date2String(date, DateUtils.HHmm.get()))
|
||||||
//TODO:BatteryReportCronTask
|
}.setType(false, false, false, true, true, false).setTitleText(getString(R.string.time_picker)).setSubmitText(getString(R.string.ok)).setCancelText(getString(R.string.cancel)).setDate(calendar).build()
|
||||||
//BatteryReportCronTask.getSingleton().updateTimer()
|
|
||||||
}
|
|
||||||
//.setTimeSelectChangeListener { date: Date? -> etBatteryCronStartTime.setText(DateUtils.date2String(date, DateUtils.HHmm.get())) }
|
|
||||||
.setType(false, false, false, true, true, false).setTitleText(getString(R.string.time_picker)).setSubmitText(getString(R.string.ok)).setCancelText(getString(R.string.cancel)).setDate(calendar).build()
|
|
||||||
mTimePicker.show()
|
mTimePicker.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1077,68 +1112,47 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
|||||||
}
|
}
|
||||||
|
|
||||||
//初始化APP下拉列表
|
//初始化APP下拉列表
|
||||||
@OptIn(DelicateCoroutinesApi::class)
|
|
||||||
private fun initAppSpinner() {
|
private fun initAppSpinner() {
|
||||||
if (!SettingUtils.enableAppNotify) return
|
|
||||||
|
|
||||||
//未开启异步获取已安装App信息开关时,规则编辑不显示已安装APP下拉框
|
//未开启异步获取已安装App信息开关时,不显示已安装APP下拉框
|
||||||
if (!SettingUtils.enableLoadUserAppList && !SettingUtils.enableLoadSystemAppList) return
|
if (!SettingUtils.enableLoadUserAppList && !SettingUtils.enableLoadSystemAppList) return
|
||||||
|
|
||||||
val get = GlobalScope.async(Dispatchers.IO) {
|
if (App.UserAppList.isEmpty() && App.SystemAppList.isEmpty()) {
|
||||||
if ((SettingUtils.enableLoadUserAppList && App.UserAppList.isEmpty()) || (SettingUtils.enableLoadSystemAppList && App.SystemAppList.isEmpty())) {
|
//XToastUtils.info(getString(R.string.loading_app_list))
|
||||||
App.UserAppList.clear()
|
val request = OneTimeWorkRequestBuilder<LoadAppListWorker>().build()
|
||||||
App.SystemAppList.clear()
|
WorkManager.getInstance(XUtil.getContext()).enqueue(request)
|
||||||
val appInfoList = AppUtils.getAppsInfo()
|
return
|
||||||
for (appInfo in appInfoList) {
|
}
|
||||||
if (appInfo.isSystem) {
|
|
||||||
App.SystemAppList.add(appInfo)
|
appListSpinnerList.clear()
|
||||||
} else {
|
if (SettingUtils.enableLoadUserAppList) {
|
||||||
App.UserAppList.add(appInfo)
|
for (appInfo in App.UserAppList) {
|
||||||
}
|
if (TextUtils.isEmpty(appInfo.packageName)) continue
|
||||||
}
|
appListSpinnerList.add(AppListAdapterItem(appInfo.name, appInfo.icon, appInfo.packageName))
|
||||||
App.UserAppList.sortBy { appInfo -> appInfo.name }
|
|
||||||
App.SystemAppList.sortBy { appInfo -> appInfo.name }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GlobalScope.launch(Dispatchers.Main) {
|
if (SettingUtils.enableLoadSystemAppList) {
|
||||||
runCatching {
|
for (appInfo in App.SystemAppList) {
|
||||||
get.await()
|
if (TextUtils.isEmpty(appInfo.packageName)) continue
|
||||||
if (App.UserAppList.isEmpty() && App.SystemAppList.isEmpty()) return@runCatching
|
appListSpinnerList.add(AppListAdapterItem(appInfo.name, appInfo.icon, appInfo.packageName))
|
||||||
|
|
||||||
appListSpinnerList.clear()
|
|
||||||
if (SettingUtils.enableLoadUserAppList) {
|
|
||||||
for (appInfo in App.UserAppList) {
|
|
||||||
appListSpinnerList.add(AppListAdapterItem(appInfo.name, appInfo.icon, appInfo.packageName))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (SettingUtils.enableLoadSystemAppList) {
|
|
||||||
for (appInfo in App.SystemAppList) {
|
|
||||||
appListSpinnerList.add(AppListAdapterItem(appInfo.name, appInfo.icon, appInfo.packageName))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//列表为空也不显示下拉框
|
|
||||||
if (appListSpinnerList.isEmpty()) return@runCatching
|
|
||||||
|
|
||||||
appListSpinnerAdapter = AppListSpinnerAdapter(appListSpinnerList)
|
|
||||||
//.setTextColor(ResUtils.getColor(R.color.green))
|
|
||||||
//.setTextSize(12F)
|
|
||||||
.setIsFilterKey(true).setFilterColor("#EF5362").setBackgroundSelector(R.drawable.selector_custom_spinner_bg)
|
|
||||||
binding!!.spApp.setAdapter(appListSpinnerAdapter)
|
|
||||||
binding!!.spApp.setOnItemClickListener { _: AdapterView<*>, _: View, position: Int, _: Long ->
|
|
||||||
try {
|
|
||||||
//val appInfo = appListSpinnerList[position]
|
|
||||||
val appInfo = appListSpinnerAdapter.getItemSource(position) as AppListAdapterItem
|
|
||||||
CommonUtils.insertOrReplaceText2Cursor(binding!!.etAppList, appInfo.packageName.toString() + "\n")
|
|
||||||
} catch (e: Exception) {
|
|
||||||
XToastUtils.error(e.message.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
binding!!.spApp.visibility = View.VISIBLE
|
|
||||||
}.onFailure {
|
|
||||||
Log.e("GlobalScope", it.message.toString())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//列表为空也不显示下拉框
|
||||||
|
if (appListSpinnerList.isEmpty()) return
|
||||||
|
|
||||||
|
appListSpinnerAdapter = AppListSpinnerAdapter(appListSpinnerList).setIsFilterKey(true).setFilterColor("#EF5362").setBackgroundSelector(R.drawable.selector_custom_spinner_bg)
|
||||||
|
binding!!.spApp.setAdapter(appListSpinnerAdapter)
|
||||||
|
binding!!.spApp.setOnItemClickListener { _: AdapterView<*>, _: View, position: Int, _: Long ->
|
||||||
|
try {
|
||||||
|
val appInfo = appListSpinnerAdapter.getItemSource(position) as AppListAdapterItem
|
||||||
|
CommonUtils.insertOrReplaceText2Cursor(binding!!.etAppList, appInfo.packageName.toString() + "\n")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
XToastUtils.error(e.message.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
binding!!.layoutSpApp.visibility = View.VISIBLE
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -69,6 +69,9 @@ class BatteryService : Service() {
|
|||||||
private val batteryReceiver: BroadcastReceiver = object : BroadcastReceiver() {
|
private val batteryReceiver: BroadcastReceiver = object : BroadcastReceiver() {
|
||||||
@SuppressLint("DefaultLocale")
|
@SuppressLint("DefaultLocale")
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
|
||||||
|
if (intent.action != Intent.ACTION_BATTERY_CHANGED) return
|
||||||
|
|
||||||
//自动删除N天前的转发记录
|
//自动删除N天前的转发记录
|
||||||
if (SettingUtils.autoCleanLogsDays > 0) {
|
if (SettingUtils.autoCleanLogsDays > 0) {
|
||||||
Log.d(TAG, "自动删除N天前的转发记录")
|
Log.d(TAG, "自动删除N天前的转发记录")
|
||||||
@ -145,21 +148,12 @@ class BatteryService : Service() {
|
|||||||
private fun sendMessage(context: Context, msg: String) {
|
private fun sendMessage(context: Context, msg: String) {
|
||||||
Log.i(TAG, msg)
|
Log.i(TAG, msg)
|
||||||
try {
|
try {
|
||||||
val msgInfo = MsgInfo(
|
val msgInfo = MsgInfo("app", "88888888", msg, Date(), getString(R.string.battery_status_monitor), -1)
|
||||||
"app",
|
val request = OneTimeWorkRequestBuilder<SendWorker>().setInputData(
|
||||||
"88888888",
|
workDataOf(
|
||||||
msg,
|
Worker.sendMsgInfo to Gson().toJson(msgInfo),
|
||||||
Date(),
|
|
||||||
getString(R.string.battery_status_monitor),
|
|
||||||
-1
|
|
||||||
)
|
|
||||||
val request = OneTimeWorkRequestBuilder<SendWorker>()
|
|
||||||
.setInputData(
|
|
||||||
workDataOf(
|
|
||||||
Worker.sendMsgInfo to Gson().toJson(msgInfo),
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
.build()
|
).build()
|
||||||
WorkManager.getInstance(context).enqueue(request)
|
WorkManager.getInstance(context).enqueue(request)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "getLog e:" + e.message)
|
Log.e(TAG, "getLog e:" + e.message)
|
||||||
|
@ -10,12 +10,16 @@ import android.text.TextUtils
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
|
import androidx.work.OneTimeWorkRequestBuilder
|
||||||
|
import androidx.work.WorkManager
|
||||||
import com.idormy.sms.forwarder.App
|
import com.idormy.sms.forwarder.App
|
||||||
import com.idormy.sms.forwarder.R
|
import com.idormy.sms.forwarder.R
|
||||||
import com.idormy.sms.forwarder.activity.MainActivity
|
import com.idormy.sms.forwarder.activity.MainActivity
|
||||||
import com.idormy.sms.forwarder.database.AppDatabase
|
import com.idormy.sms.forwarder.database.AppDatabase
|
||||||
import com.idormy.sms.forwarder.utils.*
|
import com.idormy.sms.forwarder.utils.*
|
||||||
|
import com.idormy.sms.forwarder.workers.LoadAppListWorker
|
||||||
import com.jeremyliao.liveeventbus.LiveEventBus
|
import com.jeremyliao.liveeventbus.LiveEventBus
|
||||||
|
import com.xuexiang.xutil.XUtil
|
||||||
import com.xuexiang.xutil.file.FileUtils
|
import com.xuexiang.xutil.file.FileUtils
|
||||||
import frpclib.Frpclib
|
import frpclib.Frpclib
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
@ -86,6 +90,12 @@ class ForegroundService : Service() {
|
|||||||
CommonUtils.toggleNotificationListenerService(this)
|
CommonUtils.toggleNotificationListenerService(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//异步获取所有已安装 App 信息
|
||||||
|
if (SettingUtils.enableLoadAppList) {
|
||||||
|
val request = OneTimeWorkRequestBuilder<LoadAppListWorker>().build()
|
||||||
|
WorkManager.getInstance(XUtil.getContext()).enqueue(request)
|
||||||
|
}
|
||||||
|
|
||||||
if (FileUtils.isFileExists(filesDir.absolutePath + "/libs/libgojni.so")) {
|
if (FileUtils.isFileExists(filesDir.absolutePath + "/libs/libgojni.so")) {
|
||||||
//监听Frpc启动指令
|
//监听Frpc启动指令
|
||||||
LiveEventBus.get(INTENT_FRPC_APPLY_FILE, String::class.java).observeStickyForever(frpcObserver)
|
LiveEventBus.get(INTENT_FRPC_APPLY_FILE, String::class.java).observeStickyForever(frpcObserver)
|
||||||
|
@ -0,0 +1,126 @@
|
|||||||
|
package com.idormy.sms.forwarder.service
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Service
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
|
import android.net.ConnectivityManager
|
||||||
|
import android.os.IBinder
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.work.OneTimeWorkRequestBuilder
|
||||||
|
import androidx.work.WorkManager
|
||||||
|
import androidx.work.workDataOf
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.idormy.sms.forwarder.R
|
||||||
|
import com.idormy.sms.forwarder.entity.MsgInfo
|
||||||
|
import com.idormy.sms.forwarder.utils.SettingUtils
|
||||||
|
import com.idormy.sms.forwarder.utils.Worker
|
||||||
|
import com.idormy.sms.forwarder.workers.SendWorker
|
||||||
|
import com.xuexiang.xutil.app.ServiceUtils
|
||||||
|
import com.xuexiang.xutil.net.NetworkUtils
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION", "DeferredResultUnused")
|
||||||
|
class NetworkStateService : Service() {
|
||||||
|
|
||||||
|
override fun onBind(intent: Intent): IBinder? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
Log.i(TAG, "onCreate--------------")
|
||||||
|
|
||||||
|
//纯客户端模式
|
||||||
|
//if (SettingUtils.enablePureClientMode) return
|
||||||
|
|
||||||
|
val networkStateFilter = IntentFilter()
|
||||||
|
networkStateFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION)
|
||||||
|
registerReceiver(networkStateReceiver, networkStateFilter)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
|
||||||
|
Log.i(TAG, "onStartCommand--------------")
|
||||||
|
return START_STICKY
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
Log.i(TAG, "onDestroy--------------")
|
||||||
|
super.onDestroy()
|
||||||
|
|
||||||
|
//纯客户端模式
|
||||||
|
//if (SettingUtils.enablePureClientMode) return
|
||||||
|
|
||||||
|
unregisterReceiver(networkStateReceiver)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 接收电池信息更新的广播
|
||||||
|
private val networkStateReceiver: BroadcastReceiver = object : BroadcastReceiver() {
|
||||||
|
@SuppressLint("DefaultLocale")
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
|
||||||
|
if (intent.action != ConnectivityManager.CONNECTIVITY_ACTION) return
|
||||||
|
|
||||||
|
if (!SettingUtils.enableNetworkStateReceiver) return
|
||||||
|
|
||||||
|
Log.i(TAG, "网络状态已经改变")
|
||||||
|
|
||||||
|
val msg = StringBuilder()
|
||||||
|
|
||||||
|
//枚举网络状态 NET_NO:没有网络 , NET_2G:2g网络 , NET_3G:3g网络, NET_4G:4g网络, NET_5G:5g网络, NET_WIFI:wifi, NET_ETHERNET:有线网络, NET_UNKNOWN:未知网络
|
||||||
|
val netStateType = NetworkUtils.getNetStateType()
|
||||||
|
Log.d(TAG, "netStateType: $netStateType")
|
||||||
|
val netStateTypeName = when (netStateType) {
|
||||||
|
NetworkUtils.NetState.NET_NO -> "没有网络"
|
||||||
|
NetworkUtils.NetState.NET_2G -> "2G网络"
|
||||||
|
NetworkUtils.NetState.NET_3G -> "3G网络"
|
||||||
|
NetworkUtils.NetState.NET_4G -> "4G网络"
|
||||||
|
NetworkUtils.NetState.NET_5G -> "5G网络"
|
||||||
|
NetworkUtils.NetState.NET_WIFI -> "Wifi"
|
||||||
|
NetworkUtils.NetState.NET_ETHERNET -> "有线网络"
|
||||||
|
NetworkUtils.NetState.NET_UNKNOWN -> "未知网络"
|
||||||
|
else -> "未知网络"
|
||||||
|
}
|
||||||
|
msg.append(getString(R.string.network_type)).append(": ").append(netStateTypeName).append("\n")
|
||||||
|
|
||||||
|
//获取网络运营商名称:中国移动、中国联通、中国电信
|
||||||
|
if (netStateType == NetworkUtils.NetState.NET_2G || netStateType == NetworkUtils.NetState.NET_3G || netStateType == NetworkUtils.NetState.NET_4G || netStateType == NetworkUtils.NetState.NET_5G) {
|
||||||
|
val operatorName = NetworkUtils.getNetworkOperatorName()
|
||||||
|
msg.append(getString(R.string.operator_name)).append(": ").append(operatorName).append("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
val inetAddress = NetworkUtils.getLocalInetAddress()
|
||||||
|
var hostAddress: String = inetAddress?.hostAddress?.toString() ?: "127.0.0.1"
|
||||||
|
msg.append(getString(R.string.host_address)).append(": ").append(hostAddress).append("\n")
|
||||||
|
|
||||||
|
if (ServiceUtils.isServiceRunning("com.idormy.sms.forwarder.service.HttpService")) {
|
||||||
|
hostAddress = if (hostAddress.indexOf(':', 0, false) > 0) "[${hostAddress}]" else hostAddress
|
||||||
|
msg.append(getString(R.string.http_server)).append(": ").append("http://${hostAddress}:5000")
|
||||||
|
}
|
||||||
|
|
||||||
|
sendMessage(context, msg.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//发送信息
|
||||||
|
private fun sendMessage(context: Context, msg: String) {
|
||||||
|
Log.i(TAG, msg)
|
||||||
|
try {
|
||||||
|
val msgInfo = MsgInfo("app", "77777777", msg, Date(), getString(R.string.network_state_monitor), -1)
|
||||||
|
val request = OneTimeWorkRequestBuilder<SendWorker>().setInputData(
|
||||||
|
workDataOf(
|
||||||
|
Worker.sendMsgInfo to Gson().toJson(msgInfo),
|
||||||
|
)
|
||||||
|
).build()
|
||||||
|
WorkManager.getInstance(context).enqueue(request)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "getLog e:" + e.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "NetworkStateReceiver"
|
||||||
|
}
|
||||||
|
}
|
@ -36,13 +36,11 @@ import com.xuexiang.xui.widget.imageview.preview.PreviewBuilder
|
|||||||
import com.xuexiang.xutil.XUtil
|
import com.xuexiang.xutil.XUtil
|
||||||
import com.xuexiang.xutil.common.StringUtils
|
import com.xuexiang.xutil.common.StringUtils
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
import kotlin.math.max
|
|
||||||
import kotlin.math.min
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 常用工具类
|
* 常用工具类
|
||||||
*/
|
*/
|
||||||
@Suppress("RegExpRedundantEscape", "unused")
|
@Suppress("RegExpRedundantEscape", "unused", "RegExpUnnecessaryNonCapturingGroup")
|
||||||
class CommonUtils private constructor() {
|
class CommonUtils private constructor() {
|
||||||
companion object {
|
companion object {
|
||||||
/**
|
/**
|
||||||
@ -161,11 +159,19 @@ class CommonUtils private constructor() {
|
|||||||
|
|
||||||
//焦点位置插入文本
|
//焦点位置插入文本
|
||||||
fun insertOrReplaceText2Cursor(editText: EditText, str: String) {
|
fun insertOrReplaceText2Cursor(editText: EditText, str: String) {
|
||||||
|
if (TextUtils.isEmpty(str)) return
|
||||||
|
|
||||||
|
//避免出错:java.lang.IndexOutOfBoundsException: setSpan (36 ... 36) ends beyond length 20
|
||||||
|
if (str.length > 20) {
|
||||||
|
editText.text.append(str)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
editText.isFocusable = true
|
editText.isFocusable = true
|
||||||
editText.requestFocus()
|
editText.requestFocus()
|
||||||
val start = max(editText.selectionStart, 0)
|
val nSection: Int = editText.selectionStart
|
||||||
val end = max(editText.selectionEnd, 0)
|
editText.text.insert(nSection, str)
|
||||||
editText.text.replace(min(start, end), max(start, end), str, 0, str.length)
|
editText.setSelection(nSection + str.length)
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========图片预览===========//
|
//==========图片预览===========//
|
||||||
|
@ -50,6 +50,8 @@ const val SP_SILENT_PERIOD_START = "silent_period_start"
|
|||||||
const val SP_SILENT_PERIOD_END = "silent_period_end"
|
const val SP_SILENT_PERIOD_END = "silent_period_end"
|
||||||
const val SP_AUTO_CLEAN_LOGS_DAYS = "auto_clean_logs_days"
|
const val SP_AUTO_CLEAN_LOGS_DAYS = "auto_clean_logs_days"
|
||||||
|
|
||||||
|
const val SP_NET_STATE_RECEIVER = "enable_network_state_receiver"
|
||||||
|
|
||||||
const val SP_BATTERY_RECEIVER = "enable_battery_receiver"
|
const val SP_BATTERY_RECEIVER = "enable_battery_receiver"
|
||||||
const val SP_BATTERY_STATUS = "battery_status"
|
const val SP_BATTERY_STATUS = "battery_status"
|
||||||
const val SP_BATTERY_LEVEL_MIN = "battery_level_min"
|
const val SP_BATTERY_LEVEL_MIN = "battery_level_min"
|
||||||
@ -333,6 +335,8 @@ const val KEY_RULE_ID = "key_rule_id"
|
|||||||
const val KEY_RULE_TYPE = "key_rule_type"
|
const val KEY_RULE_TYPE = "key_rule_type"
|
||||||
const val KEY_RULE_CLONE = "key_rule_clone"
|
const val KEY_RULE_CLONE = "key_rule_clone"
|
||||||
|
|
||||||
|
const val EVENT_LOAD_APP_LIST = "EVENT_LOAD_APP_LIST"
|
||||||
|
|
||||||
const val EVENT_KEY_SIM_SLOT = "EVENT_KEY_SIM_SLOT"
|
const val EVENT_KEY_SIM_SLOT = "EVENT_KEY_SIM_SLOT"
|
||||||
const val EVENT_KEY_PHONE_NUMBERS = "EVENT_KEY_PHONE_NUMBERS"
|
const val EVENT_KEY_PHONE_NUMBERS = "EVENT_KEY_PHONE_NUMBERS"
|
||||||
|
|
||||||
|
@ -160,6 +160,7 @@ class HttpServerUtils private constructor() {
|
|||||||
cloneInfo.enableLoadUserAppList = SettingUtils.enableLoadUserAppList
|
cloneInfo.enableLoadUserAppList = SettingUtils.enableLoadUserAppList
|
||||||
cloneInfo.enableLoadSystemAppList = SettingUtils.enableLoadSystemAppList
|
cloneInfo.enableLoadSystemAppList = SettingUtils.enableLoadSystemAppList
|
||||||
cloneInfo.duplicateMessagesLimits = SettingUtils.duplicateMessagesLimits
|
cloneInfo.duplicateMessagesLimits = SettingUtils.duplicateMessagesLimits
|
||||||
|
cloneInfo.enableNetworkStateReceiver = SettingUtils.enableNetworkStateReceiver
|
||||||
cloneInfo.enableBatteryReceiver = SettingUtils.enableBatteryReceiver
|
cloneInfo.enableBatteryReceiver = SettingUtils.enableBatteryReceiver
|
||||||
cloneInfo.batteryLevelMin = SettingUtils.batteryLevelMin
|
cloneInfo.batteryLevelMin = SettingUtils.batteryLevelMin
|
||||||
cloneInfo.batteryLevelMax = SettingUtils.batteryLevelMax
|
cloneInfo.batteryLevelMax = SettingUtils.batteryLevelMax
|
||||||
@ -206,6 +207,7 @@ class HttpServerUtils private constructor() {
|
|||||||
SettingUtils.enableLoadUserAppList = cloneInfo.enableLoadUserAppList
|
SettingUtils.enableLoadUserAppList = cloneInfo.enableLoadUserAppList
|
||||||
SettingUtils.enableLoadSystemAppList = cloneInfo.enableLoadSystemAppList
|
SettingUtils.enableLoadSystemAppList = cloneInfo.enableLoadSystemAppList
|
||||||
SettingUtils.duplicateMessagesLimits = cloneInfo.duplicateMessagesLimits
|
SettingUtils.duplicateMessagesLimits = cloneInfo.duplicateMessagesLimits
|
||||||
|
SettingUtils.enableNetworkStateReceiver = cloneInfo.enableNetworkStateReceiver
|
||||||
SettingUtils.enableBatteryReceiver = cloneInfo.enableBatteryReceiver
|
SettingUtils.enableBatteryReceiver = cloneInfo.enableBatteryReceiver
|
||||||
SettingUtils.batteryLevelMin = cloneInfo.batteryLevelMin
|
SettingUtils.batteryLevelMin = cloneInfo.batteryLevelMin
|
||||||
SettingUtils.batteryLevelMax = cloneInfo.batteryLevelMax
|
SettingUtils.batteryLevelMax = cloneInfo.batteryLevelMax
|
||||||
|
@ -69,6 +69,9 @@ class SettingUtils private constructor() {
|
|||||||
//自动删除N天前的转发记录
|
//自动删除N天前的转发记录
|
||||||
var autoCleanLogsDays: Int by SharedPreference(SP_AUTO_CLEAN_LOGS_DAYS, 0)
|
var autoCleanLogsDays: Int by SharedPreference(SP_AUTO_CLEAN_LOGS_DAYS, 0)
|
||||||
|
|
||||||
|
//是否监听网络状态变化
|
||||||
|
var enableNetworkStateReceiver: Boolean by SharedPreference(SP_NET_STATE_RECEIVER, false)
|
||||||
|
|
||||||
//是否监听电池状态变化
|
//是否监听电池状态变化
|
||||||
var enableBatteryReceiver: Boolean by SharedPreference(SP_BATTERY_RECEIVER, false)
|
var enableBatteryReceiver: Boolean by SharedPreference(SP_BATTERY_RECEIVER, false)
|
||||||
|
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
package com.idormy.sms.forwarder.workers
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.work.CoroutineWorker
|
||||||
|
import androidx.work.WorkerParameters
|
||||||
|
import com.idormy.sms.forwarder.App
|
||||||
|
import com.idormy.sms.forwarder.utils.EVENT_LOAD_APP_LIST
|
||||||
|
import com.jeremyliao.liveeventbus.LiveEventBus
|
||||||
|
import com.xuexiang.xutil.app.AppUtils
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
class LoadAppListWorker(
|
||||||
|
context: Context,
|
||||||
|
workerParams: WorkerParameters,
|
||||||
|
) : CoroutineWorker(context, workerParams) {
|
||||||
|
|
||||||
|
override suspend fun doWork(): Result = withContext(Dispatchers.IO) {
|
||||||
|
if (App.LoadingAppList) {
|
||||||
|
Log.d("LoadAppListWorker", "LoadingAppList is true, return")
|
||||||
|
return@withContext Result.success()
|
||||||
|
}
|
||||||
|
|
||||||
|
App.LoadingAppList = true
|
||||||
|
App.UserAppList.clear()
|
||||||
|
App.SystemAppList.clear()
|
||||||
|
val appInfoList = AppUtils.getAppsInfo()
|
||||||
|
for (appInfo in appInfoList) {
|
||||||
|
if (appInfo.isSystem) {
|
||||||
|
App.SystemAppList.add(appInfo)
|
||||||
|
} else {
|
||||||
|
App.UserAppList.add(appInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
App.UserAppList.sortBy { appInfo -> appInfo.name }
|
||||||
|
App.SystemAppList.sortBy { appInfo -> appInfo.name }
|
||||||
|
|
||||||
|
|
||||||
|
LiveEventBus.get(EVENT_LOAD_APP_LIST, String::class.java).post("finish")
|
||||||
|
App.LoadingAppList = false
|
||||||
|
Log.d("LoadAppListWorker", "LoadAppListWorker finish, App.LoadingAppList=${App.LoadingAppList}")
|
||||||
|
|
||||||
|
return@withContext Result.success()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -329,40 +329,47 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:orientation="horizontal"
|
android:orientation="vertical"
|
||||||
android:paddingEnd="10dp"
|
android:paddingEnd="10dp"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
tools:ignore="RtlSymmetry">
|
tools:ignore="RtlSymmetry">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:ems="2"
|
|
||||||
android:text="@string/extra_app"
|
android:text="@string/extra_app"
|
||||||
android:textSize="12sp"
|
android:textSize="12sp"
|
||||||
android:textStyle="bold" />
|
android:textStyle="bold" />
|
||||||
|
|
||||||
<LinearLayout
|
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
|
||||||
android:layout_width="0dp"
|
android:id="@+id/et_app_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="5dp"
|
android:hint="@string/extra_app_hint"
|
||||||
android:layout_weight="1"
|
android:inputType="textMultiLine"
|
||||||
android:orientation="vertical">
|
app:met_clearButton="true" />
|
||||||
|
|
||||||
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
|
<LinearLayout
|
||||||
android:id="@+id/et_app_list"
|
android:id="@+id/layout_sp_app"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="3dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="@string/extra_app_hint"
|
android:text="@string/choose_app"
|
||||||
android:inputType="textMultiLine"
|
android:textSize="12sp"
|
||||||
app:met_clearButton="true" />
|
android:textStyle="bold" />
|
||||||
|
|
||||||
<com.xuexiang.xui.widget.spinner.editspinner.EditSpinner
|
<com.xuexiang.xui.widget.spinner.editspinner.EditSpinner
|
||||||
android:id="@+id/sp_app"
|
android:id="@+id/sp_app"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="3dp"
|
android:layout_marginStart="5dp"
|
||||||
android:visibility="gone"
|
|
||||||
app:es_hint="@string/choose_app_hint"
|
app:es_hint="@string/choose_app_hint"
|
||||||
app:es_maxLength="20"
|
app:es_maxLength="20"
|
||||||
app:es_maxLine="1" />
|
app:es_maxLine="1" />
|
||||||
@ -600,6 +607,64 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:layout_marginEnd="5dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/network_state_monitor"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:text="@string/network_state_monitor_tips"
|
||||||
|
android:textSize="10sp"
|
||||||
|
tools:ignore="SmallSp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
style="@style/settingBarStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/network_state_change_remind"
|
||||||
|
android:textStyle="bold"
|
||||||
|
tools:ignore="RelativeOverlap" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/network_state_change_remind_tips"
|
||||||
|
android:textSize="9sp"
|
||||||
|
tools:ignore="SmallSp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<com.xuexiang.xui.widget.button.switchbutton.SwitchButton
|
||||||
|
android:id="@+id/sb_network_state_receiver"
|
||||||
|
style="@style/SwitchButtonStyle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -542,6 +542,10 @@
|
|||||||
<string name="active_request_tips">Obtain instructions through passive reception or active polling to operate the machine</string>
|
<string name="active_request_tips">Obtain instructions through passive reception or active polling to operate the machine</string>
|
||||||
<string name="httpserver">Local HttpServer</string>
|
<string name="httpserver">Local HttpServer</string>
|
||||||
<string name="httpserver_tips">Available under WiFi network, after startup, other machines in the LAN can directly call the local interface</string>
|
<string name="httpserver_tips">Available under WiFi network, after startup, other machines in the LAN can directly call the local interface</string>
|
||||||
|
<string name="network_state_monitor">Network State Monitor</string>
|
||||||
|
<string name="network_state_monitor_tips">[Note] You need to manually create APP forwarding rules, package name: 77777777</string>
|
||||||
|
<string name="network_state_change_remind">Network State Change Remind</string>
|
||||||
|
<string name="network_state_change_remind_tips">Send a notification when the network status changes (connection mode/IP change)</string>
|
||||||
<string name="battery_monitor">Battery Monitor</string>
|
<string name="battery_monitor">Battery Monitor</string>
|
||||||
<string name="battery_monitor_tips">[Note] You need to manually create APP forwarding rules, package name: 88888888</string>
|
<string name="battery_monitor_tips">[Note] You need to manually create APP forwarding rules, package name: 88888888</string>
|
||||||
<string name="keep_alive">Keep Alive</string>
|
<string name="keep_alive">Keep Alive</string>
|
||||||
@ -995,4 +999,8 @@
|
|||||||
<string name="sender_del">Del Sender</string>
|
<string name="sender_del">Del Sender</string>
|
||||||
<string name="sender_disabled">Sender is disabled</string>
|
<string name="sender_disabled">Sender is disabled</string>
|
||||||
<string name="unknown_sender">Unknown sender</string>
|
<string name="unknown_sender">Unknown sender</string>
|
||||||
|
<string name="network_type">Network Type</string>
|
||||||
|
<string name="operator_name">Operator Name</string>
|
||||||
|
<string name="host_address">Host Address</string>
|
||||||
|
<string name="loading_app_list">Loading app list async...</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -543,6 +543,10 @@
|
|||||||
<string name="active_request_tips">通过 被动接收 或者 主动轮询 获取指令,从而操作本机</string>
|
<string name="active_request_tips">通过 被动接收 或者 主动轮询 获取指令,从而操作本机</string>
|
||||||
<string name="httpserver">被动接收本地 HttpServer</string>
|
<string name="httpserver">被动接收本地 HttpServer</string>
|
||||||
<string name="httpserver_tips">WiFi网络下可用,启动后局域网内其他机器可直接调用本机接口</string>
|
<string name="httpserver_tips">WiFi网络下可用,启动后局域网内其他机器可直接调用本机接口</string>
|
||||||
|
<string name="network_state_monitor">网络状态监控</string>
|
||||||
|
<string name="network_state_monitor_tips">【注意】需要手动创建APP转发规则,包名:77777777</string>
|
||||||
|
<string name="network_state_change_remind">网络状态改变提醒</string>
|
||||||
|
<string name="network_state_change_remind_tips">网络状态改变(连接方式/IP变化)时发出通知</string>
|
||||||
<string name="battery_monitor">电池监控</string>
|
<string name="battery_monitor">电池监控</string>
|
||||||
<string name="battery_monitor_tips">【注意】需要手动创建APP转发规则,包名:88888888</string>
|
<string name="battery_monitor_tips">【注意】需要手动创建APP转发规则,包名:88888888</string>
|
||||||
<string name="keep_alive">保活措施</string>
|
<string name="keep_alive">保活措施</string>
|
||||||
@ -996,4 +1000,8 @@
|
|||||||
<string name="sender_del">删除发送通道</string>
|
<string name="sender_del">删除发送通道</string>
|
||||||
<string name="sender_disabled">发送通道已禁用</string>
|
<string name="sender_disabled">发送通道已禁用</string>
|
||||||
<string name="unknown_sender">未知发送通道</string>
|
<string name="unknown_sender">未知发送通道</string>
|
||||||
|
<string name="network_type">网络类型</string>
|
||||||
|
<string name="operator_name">运营商</string>
|
||||||
|
<string name="host_address">本地IP</string>
|
||||||
|
<string name="loading_app_list">正在异步加载应用列表...</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user