mirror of
https://github.com/pppscn/SmsForwarder
synced 2025-08-03 01:17:41 +08:00
新增:自动任务·快捷指令 —— 电池电量&充电状态改变(废弃:88888888
)
This commit is contained in:
parent
e03a9b8198
commit
eb20d8ea05
@ -79,6 +79,7 @@
|
|||||||
android:configChanges="screenSize|keyboardHidden|orientation|keyboard"
|
android:configChanges="screenSize|keyboardHidden|orientation|keyboard"
|
||||||
android:defaultToDeviceProtectedStorage="true"
|
android:defaultToDeviceProtectedStorage="true"
|
||||||
android:directBootAware="true"
|
android:directBootAware="true"
|
||||||
|
android:enableOnBackInvokedCallback="false"
|
||||||
android:fullBackupContent="@xml/backup_descriptor"
|
android:fullBackupContent="@xml/backup_descriptor"
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
@ -222,19 +223,13 @@
|
|||||||
android:value="640" />
|
android:value="640" />
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".service.HttpService"
|
android:name=".service.HttpServerService"
|
||||||
android:enabled="true" />
|
|
||||||
<service
|
|
||||||
android:name=".service.NetworkStateService"
|
|
||||||
android:enabled="true" />
|
|
||||||
<service
|
|
||||||
android:name=".service.BatteryService"
|
|
||||||
android:enabled="true" />
|
android:enabled="true" />
|
||||||
<service
|
<service
|
||||||
android:name=".service.ForegroundService"
|
android:name=".service.ForegroundService"
|
||||||
android:enabled="true" />
|
android:enabled="true" />
|
||||||
<service
|
<service
|
||||||
android:name=".service.NotifyService"
|
android:name=".service.NotificationService"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
@ -248,9 +243,15 @@
|
|||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:permission="android.permission.BIND_JOB_SERVICE" />
|
android:permission="android.permission.BIND_JOB_SERVICE" />
|
||||||
|
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
android:name=".receiver.BootReceiver"
|
android:name=".receiver.BatteryReceiver"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.BATTERY_CHANGED" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
<receiver
|
||||||
|
android:name=".receiver.BootCompletedReceiver"
|
||||||
android:defaultToDeviceProtectedStorage="true"
|
android:defaultToDeviceProtectedStorage="true"
|
||||||
android:directBootAware="true"
|
android:directBootAware="true"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
@ -299,7 +300,7 @@
|
|||||||
<action android:name="android.intent.action.SIM_STATE_CHANGED" />
|
<action android:name="android.intent.action.SIM_STATE_CHANGED" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
<receiver android:name=".receiver.AlarmReceiver" />
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
@ -19,16 +19,14 @@ import com.idormy.sms.forwarder.core.Core
|
|||||||
import com.idormy.sms.forwarder.database.AppDatabase
|
import com.idormy.sms.forwarder.database.AppDatabase
|
||||||
import com.idormy.sms.forwarder.database.repository.*
|
import com.idormy.sms.forwarder.database.repository.*
|
||||||
import com.idormy.sms.forwarder.entity.SimInfo
|
import com.idormy.sms.forwarder.entity.SimInfo
|
||||||
|
import com.idormy.sms.forwarder.receiver.BatteryReceiver
|
||||||
import com.idormy.sms.forwarder.receiver.CactusReceiver
|
import com.idormy.sms.forwarder.receiver.CactusReceiver
|
||||||
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.HttpServerService
|
||||||
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
|
||||||
import com.idormy.sms.forwarder.utils.sdkinit.XUpdateInit
|
import com.idormy.sms.forwarder.utils.sdkinit.XUpdateInit
|
||||||
import com.idormy.sms.forwarder.utils.task.AlarmUtils
|
|
||||||
import com.idormy.sms.forwarder.utils.tinker.TinkerLoadLibrary
|
import com.idormy.sms.forwarder.utils.tinker.TinkerLoadLibrary
|
||||||
import io.reactivex.Observable
|
import io.reactivex.Observable
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
@ -121,23 +119,18 @@ class App : Application(), CactusCallback, Configuration.Provider by Core {
|
|||||||
startService(serviceIntent)
|
startService(serviceIntent)
|
||||||
}
|
}
|
||||||
|
|
||||||
//网络状态监听
|
|
||||||
Intent(this, NetworkStateService::class.java).also {
|
|
||||||
startService(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
//电池状态监听
|
|
||||||
Intent(this, BatteryService::class.java).also {
|
|
||||||
startService(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
//启动HttpServer
|
//启动HttpServer
|
||||||
if (HttpServerUtils.enableServerAutorun) {
|
if (HttpServerUtils.enableServerAutorun) {
|
||||||
Intent(this, HttpService::class.java).also {
|
Intent(this, HttpServerService::class.java).also {
|
||||||
startService(it)
|
startService(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//监听电量&充电状态变化
|
||||||
|
val batteryReceiver = BatteryReceiver()
|
||||||
|
val filter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
|
||||||
|
registerReceiver(batteryReceiver, filter)
|
||||||
|
|
||||||
//Cactus 集成双进程前台服务,JobScheduler,onePix(一像素),WorkManager,无声音乐
|
//Cactus 集成双进程前台服务,JobScheduler,onePix(一像素),WorkManager,无声音乐
|
||||||
if (SettingUtils.enableCactus) {
|
if (SettingUtils.enableCactus) {
|
||||||
//注册广播监听器
|
//注册广播监听器
|
||||||
@ -207,10 +200,6 @@ class App : Application(), CactusCallback, Configuration.Provider by Core {
|
|||||||
XUpdateInit.init(this)
|
XUpdateInit.init(this)
|
||||||
// 运营统计数据
|
// 运营统计数据
|
||||||
UMengInit.init(this)
|
UMengInit.init(this)
|
||||||
// 定时任务初始化
|
|
||||||
AlarmUtils.initialize(this)
|
|
||||||
// 三方时间库初始化
|
|
||||||
//AndroidThreeTen.init(this)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("CheckResult")
|
@SuppressLint("CheckResult")
|
||||||
|
@ -37,7 +37,7 @@ interface TaskDao {
|
|||||||
@RawQuery(observedEntities = [Task::class])
|
@RawQuery(observedEntities = [Task::class])
|
||||||
fun getAllRaw(query: SupportSQLiteQuery): List<Task>
|
fun getAllRaw(query: SupportSQLiteQuery): List<Task>
|
||||||
|
|
||||||
@Query("SELECT * FROM Task WHERE type = :taskType")
|
@Query("SELECT * FROM Task WHERE status = 1 AND type = :taskType")
|
||||||
fun getByType(taskType: Int): List<Task>
|
fun getByType(taskType: Int): List<Task>
|
||||||
|
|
||||||
//TODO:根据条件查询,不推荐使用
|
//TODO:根据条件查询,不推荐使用
|
||||||
|
@ -4,6 +4,7 @@ import com.idormy.sms.forwarder.R
|
|||||||
import com.xuexiang.xui.utils.ResUtils
|
import com.xuexiang.xui.utils.ResUtils
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
data class BatteryInfo(
|
data class BatteryInfo(
|
||||||
var level: String = "",
|
var level: String = "",
|
||||||
var scale: String = "",
|
var scale: String = "",
|
||||||
|
@ -5,12 +5,14 @@ import android.text.TextUtils
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
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.utils.BatteryUtils
|
||||||
import com.idormy.sms.forwarder.utils.CALL_TYPE_MAP
|
import com.idormy.sms.forwarder.utils.CALL_TYPE_MAP
|
||||||
import com.idormy.sms.forwarder.utils.HttpServerUtils
|
import com.idormy.sms.forwarder.utils.HttpServerUtils
|
||||||
import com.idormy.sms.forwarder.utils.SettingUtils
|
import com.idormy.sms.forwarder.utils.SettingUtils
|
||||||
import com.idormy.sms.forwarder.utils.SettingUtils.Companion.enableSmsTemplate
|
import com.idormy.sms.forwarder.utils.SettingUtils.Companion.enableSmsTemplate
|
||||||
import com.idormy.sms.forwarder.utils.SettingUtils.Companion.extraDeviceMark
|
import com.idormy.sms.forwarder.utils.SettingUtils.Companion.extraDeviceMark
|
||||||
import com.idormy.sms.forwarder.utils.SettingUtils.Companion.smsTemplate
|
import com.idormy.sms.forwarder.utils.SettingUtils.Companion.smsTemplate
|
||||||
|
import com.idormy.sms.forwarder.utils.task.TaskUtils
|
||||||
import com.xuexiang.xui.utils.ResUtils.getString
|
import com.xuexiang.xui.utils.ResUtils.getString
|
||||||
import com.xuexiang.xutil.app.AppUtils
|
import com.xuexiang.xutil.app.AppUtils
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
@ -109,6 +111,10 @@ data class MsgInfo(
|
|||||||
.replace(getString(R.string.tag_device_name), deviceMark)
|
.replace(getString(R.string.tag_device_name), deviceMark)
|
||||||
.replace(getString(R.string.tag_app_version), versionName)
|
.replace(getString(R.string.tag_app_version), versionName)
|
||||||
.replace(getString(R.string.tag_call_type), CALL_TYPE_MAP[callType.toString()] ?: getString(R.string.unknown_call))
|
.replace(getString(R.string.tag_call_type), CALL_TYPE_MAP[callType.toString()] ?: getString(R.string.unknown_call))
|
||||||
|
.replace(getString(R.string.tag_battery_pct), TaskUtils.batteryPct.toString())
|
||||||
|
.replace(getString(R.string.tag_battery_status), BatteryUtils.getStatus(TaskUtils.batteryStatus))
|
||||||
|
.replace(getString(R.string.tag_battery_plugged), BatteryUtils.getPlugged(TaskUtils.batteryPlugged))
|
||||||
|
.replace(getString(R.string.tag_battery_info), TaskUtils.batteryInfo)
|
||||||
.trim()
|
.trim()
|
||||||
return replaceLocationTag(replaceAppName(regexReplace(smsVoForSend, regexReplace), from))
|
return replaceLocationTag(replaceAppName(regexReplace(smsVoForSend, regexReplace), from))
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package com.idormy.sms.forwarder.entity.task
|
|||||||
|
|
||||||
import android.os.BatteryManager
|
import android.os.BatteryManager
|
||||||
import com.idormy.sms.forwarder.R
|
import com.idormy.sms.forwarder.R
|
||||||
|
import com.xuexiang.xutil.resource.ResUtils.getString
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
|
|
||||||
data class BatterySetting(
|
data class BatterySetting(
|
||||||
@ -19,4 +20,30 @@ data class BatterySetting(
|
|||||||
else -> R.id.rb_battery_charging
|
else -> R.id.rb_battery_charging
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getMsg(statusNew: Int, levelNew: Int, levelOld: Int, batteryInfo: String): String {
|
||||||
|
|
||||||
|
when (statusNew) {
|
||||||
|
BatteryManager.BATTERY_STATUS_CHARGING, BatteryManager.BATTERY_STATUS_FULL -> { //充电中
|
||||||
|
if (status != BatteryManager.BATTERY_STATUS_CHARGING) return ""
|
||||||
|
if (keepReminding && levelOld < levelNew && levelNew >= levelMax) {
|
||||||
|
return String.format(getString(R.string.over_level_max), batteryInfo)
|
||||||
|
} else if (!keepReminding && levelOld < levelNew && levelNew == levelMax) {
|
||||||
|
return String.format(getString(R.string.reach_level_max), batteryInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BatteryManager.BATTERY_STATUS_DISCHARGING, BatteryManager.BATTERY_STATUS_NOT_CHARGING -> { //放电中
|
||||||
|
if (status != BatteryManager.BATTERY_STATUS_DISCHARGING) return ""
|
||||||
|
if (keepReminding && levelOld > levelNew && levelNew <= levelMin) {
|
||||||
|
return String.format(getString(R.string.below_level_min), batteryInfo)
|
||||||
|
} else if (!keepReminding && levelOld > levelNew && levelNew == levelMin) {
|
||||||
|
return String.format(getString(R.string.reach_level_min), batteryInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,4 +71,11 @@ data class ChargeSetting(
|
|||||||
else -> R.id.rb_plugged_unknown
|
else -> R.id.rb_plugged_unknown
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getMsg(statusNew: Int, statusOld: Int, pluggedNew: Int, pluggedOld: Int, batteryInfo: String): String {
|
||||||
|
|
||||||
|
if (statusNew != status || pluggedNew != plugged) return ""
|
||||||
|
|
||||||
|
return getString(R.string.battery_status_changed) + getStatusStr(statusOld) + "(" + getPluggedStr(pluggedOld) + ") → " + getStatusStr(statusNew) + "(" + getPluggedStr(pluggedNew) + ")" + batteryInfo
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ import com.idormy.sms.forwarder.R
|
|||||||
import com.idormy.sms.forwarder.core.BaseFragment
|
import com.idormy.sms.forwarder.core.BaseFragment
|
||||||
import com.idormy.sms.forwarder.databinding.FragmentServerBinding
|
import com.idormy.sms.forwarder.databinding.FragmentServerBinding
|
||||||
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.HttpServerService
|
||||||
import com.idormy.sms.forwarder.utils.*
|
import com.idormy.sms.forwarder.utils.*
|
||||||
import com.xuexiang.xaop.annotation.SingleClick
|
import com.xuexiang.xaop.annotation.SingleClick
|
||||||
import com.xuexiang.xpage.annotation.Page
|
import com.xuexiang.xpage.annotation.Page
|
||||||
@ -241,9 +241,9 @@ class ServerFragment : BaseFragment<FragmentServerBinding?>(), View.OnClickListe
|
|||||||
binding!!.sbApiLocation.isChecked = HttpServerUtils.enableApiLocation
|
binding!!.sbApiLocation.isChecked = HttpServerUtils.enableApiLocation
|
||||||
binding!!.sbApiLocation.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
|
binding!!.sbApiLocation.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
|
||||||
HttpServerUtils.enableApiLocation = isChecked
|
HttpServerUtils.enableApiLocation = isChecked
|
||||||
if (ServiceUtils.isServiceRunning("com.idormy.sms.forwarder.service.HttpService")) {
|
if (ServiceUtils.isServiceRunning("com.idormy.sms.forwarder.service.HttpServerService")) {
|
||||||
Log.d("ServerFragment", "onClick: 重启服务")
|
Log.d("ServerFragment", "onClick: 重启服务")
|
||||||
Intent(appContext, HttpService::class.java).also {
|
Intent(appContext, HttpServerService::class.java).also {
|
||||||
appContext?.stopService(it)
|
appContext?.stopService(it)
|
||||||
Thread.sleep(500)
|
Thread.sleep(500)
|
||||||
appContext?.startService(it)
|
appContext?.startService(it)
|
||||||
@ -272,8 +272,8 @@ class ServerFragment : BaseFragment<FragmentServerBinding?>(), View.OnClickListe
|
|||||||
checkCallPermission()
|
checkCallPermission()
|
||||||
checkContactsPermission()
|
checkContactsPermission()
|
||||||
checkLocationPermission()
|
checkLocationPermission()
|
||||||
Intent(appContext, HttpService::class.java).also {
|
Intent(appContext, HttpServerService::class.java).also {
|
||||||
if (ServiceUtils.isServiceRunning("com.idormy.sms.forwarder.service.HttpService")) {
|
if (ServiceUtils.isServiceRunning("com.idormy.sms.forwarder.service.HttpServerService")) {
|
||||||
appContext?.stopService(it)
|
appContext?.stopService(it)
|
||||||
} else {
|
} else {
|
||||||
appContext?.startService(it)
|
appContext?.startService(it)
|
||||||
@ -348,8 +348,8 @@ class ServerFragment : BaseFragment<FragmentServerBinding?>(), View.OnClickListe
|
|||||||
HttpServerUtils.serverWebPath = webPath
|
HttpServerUtils.serverWebPath = webPath
|
||||||
|
|
||||||
XToastUtils.info(getString(R.string.restarting_httpserver))
|
XToastUtils.info(getString(R.string.restarting_httpserver))
|
||||||
Intent(appContext, HttpService::class.java).also {
|
Intent(appContext, HttpServerService::class.java).also {
|
||||||
if (ServiceUtils.isServiceRunning("com.idormy.sms.forwarder.service.HttpService")) {
|
if (ServiceUtils.isServiceRunning("com.idormy.sms.forwarder.service.HttpServerService")) {
|
||||||
appContext?.stopService(it)
|
appContext?.stopService(it)
|
||||||
Thread.sleep(500)
|
Thread.sleep(500)
|
||||||
appContext?.startService(it)
|
appContext?.startService(it)
|
||||||
@ -381,7 +381,7 @@ class ServerFragment : BaseFragment<FragmentServerBinding?>(), View.OnClickListe
|
|||||||
|
|
||||||
//刷新按钮
|
//刷新按钮
|
||||||
private fun refreshButtonText() {
|
private fun refreshButtonText() {
|
||||||
if (ServiceUtils.isServiceRunning("com.idormy.sms.forwarder.service.HttpService")) {
|
if (ServiceUtils.isServiceRunning("com.idormy.sms.forwarder.service.HttpServerService")) {
|
||||||
binding!!.btnToggleServer.text = resources.getText(R.string.stop_server)
|
binding!!.btnToggleServer.text = resources.getText(R.string.stop_server)
|
||||||
binding!!.ivCopy.visibility = View.VISIBLE
|
binding!!.ivCopy.visibility = View.VISIBLE
|
||||||
try {
|
try {
|
||||||
|
@ -32,7 +32,7 @@ import com.idormy.sms.forwarder.adapter.spinner.AppListSpinnerAdapter
|
|||||||
import com.idormy.sms.forwarder.core.BaseFragment
|
import com.idormy.sms.forwarder.core.BaseFragment
|
||||||
import com.idormy.sms.forwarder.databinding.FragmentSettingsBinding
|
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.BootCompletedReceiver
|
||||||
import com.idormy.sms.forwarder.service.ForegroundService
|
import com.idormy.sms.forwarder.service.ForegroundService
|
||||||
import com.idormy.sms.forwarder.utils.*
|
import com.idormy.sms.forwarder.utils.*
|
||||||
import com.idormy.sms.forwarder.workers.LoadAppListWorker
|
import com.idormy.sms.forwarder.workers.LoadAppListWorker
|
||||||
@ -44,16 +44,12 @@ import com.xuexiang.xui.widget.button.SmoothCheckBox
|
|||||||
import com.xuexiang.xui.widget.button.switchbutton.SwitchButton
|
import com.xuexiang.xui.widget.button.switchbutton.SwitchButton
|
||||||
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.xui.widget.picker.XRangeSlider
|
|
||||||
import com.xuexiang.xui.widget.picker.XRangeSlider.OnRangeSliderListener
|
|
||||||
import com.xuexiang.xui.widget.picker.XSeekBar
|
import com.xuexiang.xui.widget.picker.XSeekBar
|
||||||
import com.xuexiang.xui.widget.picker.widget.builder.OptionsPickerBuilder
|
import com.xuexiang.xui.widget.picker.widget.builder.OptionsPickerBuilder
|
||||||
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.getAppPackageName
|
import com.xuexiang.xutil.app.AppUtils.getAppPackageName
|
||||||
import com.xuexiang.xutil.data.DateUtils
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@ -125,15 +121,6 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
|||||||
//监听网络状态变化
|
//监听网络状态变化
|
||||||
switchNetworkStateReceiver(binding!!.sbNetworkStateReceiver)
|
switchNetworkStateReceiver(binding!!.sbNetworkStateReceiver)
|
||||||
|
|
||||||
//监听电池状态变化
|
|
||||||
switchBatteryReceiver(binding!!.sbBatteryReceiver)
|
|
||||||
//电量预警
|
|
||||||
editBatteryLevelAlarm(binding!!.xrsBatteryLevelAlarm, binding!!.scbBatteryLevelAlarmOnce)
|
|
||||||
//定时推送电池状态
|
|
||||||
switchBatteryCron(binding!!.sbBatteryCron)
|
|
||||||
//设置推送电池状态时机
|
|
||||||
editBatteryCronTiming(binding!!.etBatteryCronStartTime, binding!!.etBatteryCronInterval)
|
|
||||||
|
|
||||||
//开机启动
|
//开机启动
|
||||||
checkWithReboot(binding!!.sbWithReboot, binding!!.tvAutoStartup)
|
checkWithReboot(binding!!.sbWithReboot, binding!!.tvAutoStartup)
|
||||||
//忽略电池优化设置
|
//忽略电池优化设置
|
||||||
@ -629,85 +616,6 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//监听电池状态变化
|
|
||||||
@SuppressLint("UseSwitchCompatOrMaterialCode")
|
|
||||||
fun switchBatteryReceiver(sbBatteryReceiver: SwitchButton) {
|
|
||||||
sbBatteryReceiver.isChecked = SettingUtils.enableBatteryReceiver
|
|
||||||
sbBatteryReceiver.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
|
|
||||||
SettingUtils.enableBatteryReceiver = isChecked
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//设置低电量报警
|
|
||||||
private fun editBatteryLevelAlarm(
|
|
||||||
xrsBatteryLevelAlarm: XRangeSlider, scbBatteryLevelAlarmOnce: SmoothCheckBox
|
|
||||||
) {
|
|
||||||
xrsBatteryLevelAlarm.setStartingMinMax(
|
|
||||||
SettingUtils.batteryLevelMin, SettingUtils.batteryLevelMax
|
|
||||||
)
|
|
||||||
xrsBatteryLevelAlarm.setOnRangeSliderListener(object : OnRangeSliderListener {
|
|
||||||
override fun onMaxChanged(slider: XRangeSlider, maxValue: Int) {
|
|
||||||
//SettingUtils.batteryLevelMin = slider.selectedMin
|
|
||||||
SettingUtils.batteryLevelMax = slider.selectedMax
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onMinChanged(slider: XRangeSlider, minValue: Int) {
|
|
||||||
SettingUtils.batteryLevelMin = slider.selectedMin
|
|
||||||
//SettingUtils.batteryLevelMax = slider.selectedMax
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
scbBatteryLevelAlarmOnce.isChecked = SettingUtils.batteryLevelOnce
|
|
||||||
scbBatteryLevelAlarmOnce.setOnCheckedChangeListener { _: SmoothCheckBox, isChecked: Boolean ->
|
|
||||||
SettingUtils.batteryLevelOnce = isChecked
|
|
||||||
if (isChecked && 0 == SettingUtils.batteryLevelMin && 0 == SettingUtils.batteryLevelMax) {
|
|
||||||
XToastUtils.warning(R.string.tips_battery_level_alarm_once)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//定时推送电池状态
|
|
||||||
@SuppressLint("UseSwitchCompatOrMaterialCode")
|
|
||||||
fun switchBatteryCron(sbBatteryCron: SwitchButton) {
|
|
||||||
sbBatteryCron.isChecked = SettingUtils.enableBatteryCron
|
|
||||||
binding!!.layoutBatteryCron.visibility = if (SettingUtils.enableBatteryCron) View.VISIBLE else View.GONE
|
|
||||||
sbBatteryCron.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
|
|
||||||
binding!!.layoutBatteryCron.visibility = if (isChecked) View.VISIBLE else View.GONE
|
|
||||||
SettingUtils.enableBatteryCron = isChecked
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//设置推送电池状态时机
|
|
||||||
private fun editBatteryCronTiming(
|
|
||||||
etBatteryCronStartTime: EditText, etBatteryCronInterval: EditText
|
|
||||||
) {
|
|
||||||
etBatteryCronStartTime.setText(SettingUtils.batteryCronStartTime)
|
|
||||||
etBatteryCronStartTime.setOnClickListener {
|
|
||||||
val calendar = Calendar.getInstance()
|
|
||||||
calendar.time = DateUtils.getNowDate()
|
|
||||||
val mTimePicker = TimePickerBuilder(context) { date: Date?, _: View? ->
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
|
|
||||||
etBatteryCronInterval.setText(SettingUtils.batteryCronInterval.toString())
|
|
||||||
etBatteryCronInterval.addTextChangedListener(object : TextWatcher {
|
|
||||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
|
|
||||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
|
|
||||||
override fun afterTextChanged(s: Editable) {
|
|
||||||
val interval = etBatteryCronInterval.text.toString().trim()
|
|
||||||
if (interval.isNotEmpty() && interval.toInt() > 0) {
|
|
||||||
SettingUtils.batteryCronInterval = interval.toInt()
|
|
||||||
//TODO:BatteryReportCronTask
|
|
||||||
//BatteryReportCronTask.getSingleton().updateTimer()
|
|
||||||
} else {
|
|
||||||
SettingUtils.batteryCronInterval = 60
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
//开机启动
|
//开机启动
|
||||||
private fun checkWithReboot(
|
private fun checkWithReboot(
|
||||||
@SuppressLint("UseSwitchCompatOrMaterialCode") sbWithReboot: SwitchButton, tvAutoStartup: TextView
|
@SuppressLint("UseSwitchCompatOrMaterialCode") sbWithReboot: SwitchButton, tvAutoStartup: TextView
|
||||||
@ -715,7 +623,7 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
|||||||
tvAutoStartup.text = getAutoStartTips()
|
tvAutoStartup.text = getAutoStartTips()
|
||||||
|
|
||||||
//获取组件
|
//获取组件
|
||||||
val cm = ComponentName(getAppPackageName(), BootReceiver::class.java.name)
|
val cm = ComponentName(getAppPackageName(), BootCompletedReceiver::class.java.name)
|
||||||
val pm: PackageManager = getPackageManager()
|
val pm: PackageManager = getPackageManager()
|
||||||
val state = pm.getComponentEnabledSetting(cm)
|
val state = pm.getComponentEnabledSetting(cm)
|
||||||
sbWithReboot.isChecked = !(state == PackageManager.COMPONENT_ENABLED_STATE_DISABLED || state == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER)
|
sbWithReboot.isChecked = !(state == PackageManager.COMPONENT_ENABLED_STATE_DISABLED || state == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER)
|
||||||
|
@ -335,9 +335,6 @@ class TasksEditFragment : BaseFragment<FragmentTasksEditBinding?>(), View.OnClic
|
|||||||
//定时任务
|
//定时任务
|
||||||
TASK_CONDITION_CRON -> {
|
TASK_CONDITION_CRON -> {
|
||||||
//取消旧任务的定时器 & 设置新的定时器
|
//取消旧任务的定时器 & 设置新的定时器
|
||||||
//AlarmUtils.cancelAlarm(task)
|
|
||||||
//AlarmUtils.scheduleAlarm(task)
|
|
||||||
|
|
||||||
CronJobScheduler.cancelTask(task.id)
|
CronJobScheduler.cancelTask(task.id)
|
||||||
CronJobScheduler.scheduleTask(task)
|
CronJobScheduler.scheduleTask(task)
|
||||||
}
|
}
|
||||||
|
@ -1,73 +0,0 @@
|
|||||||
package com.idormy.sms.forwarder.receiver
|
|
||||||
|
|
||||||
import android.content.BroadcastReceiver
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.util.Log
|
|
||||||
import com.google.gson.Gson
|
|
||||||
import com.idormy.sms.forwarder.App
|
|
||||||
import com.idormy.sms.forwarder.database.AppDatabase
|
|
||||||
import com.idormy.sms.forwarder.database.entity.Task
|
|
||||||
import com.idormy.sms.forwarder.entity.task.CronSetting
|
|
||||||
import com.idormy.sms.forwarder.entity.task.TaskSetting
|
|
||||||
import com.idormy.sms.forwarder.utils.task.AlarmUtils
|
|
||||||
import gatewayapps.crondroid.CronExpression
|
|
||||||
import java.util.Date
|
|
||||||
|
|
||||||
@Suppress("PropertyName", "DEPRECATION")
|
|
||||||
class AlarmReceiver : BroadcastReceiver() {
|
|
||||||
|
|
||||||
val TAG: String = AlarmReceiver::class.java.simpleName
|
|
||||||
|
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
|
||||||
val task = intent.getParcelableExtra<Task>("TASK")
|
|
||||||
if (task == null) {
|
|
||||||
Log.d(TAG, "onReceive task is null")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.d(TAG, "onReceive task $task")
|
|
||||||
Log.d(TAG, "lastExecTime = ${task.lastExecTime}, nextExecTime = ${task.nextExecTime}")
|
|
||||||
try {
|
|
||||||
//取消旧任务的定时器
|
|
||||||
AlarmUtils.cancelAlarm(task)
|
|
||||||
|
|
||||||
// 根据任务信息执行相应操作
|
|
||||||
val conditionList = Gson().fromJson(task.conditions, Array<TaskSetting>::class.java).toMutableList()
|
|
||||||
if (conditionList.isEmpty()) {
|
|
||||||
Log.d(TAG, "onReceive conditionList is empty")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val firstCondition = conditionList.firstOrNull()
|
|
||||||
if (firstCondition == null) {
|
|
||||||
Log.d(TAG, "onReceive firstCondition is null")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val cronSetting = Gson().fromJson(firstCondition.setting, CronSetting::class.java)
|
|
||||||
if (cronSetting == null) {
|
|
||||||
Log.d(TAG, "onReceive cronSetting is null")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 更新任务的上次执行时间和下次执行时间
|
|
||||||
val cronExpression = CronExpression(cronSetting.expression)
|
|
||||||
task.lastExecTime = Date()
|
|
||||||
task.nextExecTime = cronExpression.getNextValidTimeAfter(task.lastExecTime)
|
|
||||||
Log.d(TAG, "lastExecTime = ${task.lastExecTime}, nextExecTime = ${task.nextExecTime}")
|
|
||||||
// 自动禁用任务
|
|
||||||
if (task.nextExecTime <= task.lastExecTime) {
|
|
||||||
task.status = 0
|
|
||||||
}
|
|
||||||
// 更新任务信息
|
|
||||||
AppDatabase.getInstance(App.context).taskDao().update(task)
|
|
||||||
if (task.status == 0) {
|
|
||||||
Log.d(TAG, "onReceive task is disabled")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//设置新的定时器
|
|
||||||
AlarmUtils.scheduleAlarm(task)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e(TAG, "onReceive error $e")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,79 @@
|
|||||||
|
package com.idormy.sms.forwarder.receiver
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.BatteryManager
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.work.OneTimeWorkRequestBuilder
|
||||||
|
import androidx.work.WorkManager
|
||||||
|
import androidx.work.workDataOf
|
||||||
|
import com.idormy.sms.forwarder.utils.BatteryUtils
|
||||||
|
import com.idormy.sms.forwarder.utils.TASK_CONDITION_BATTERY
|
||||||
|
import com.idormy.sms.forwarder.utils.TASK_CONDITION_CHARGE
|
||||||
|
import com.idormy.sms.forwarder.utils.TaskWorker
|
||||||
|
import com.idormy.sms.forwarder.utils.task.TaskUtils
|
||||||
|
import com.idormy.sms.forwarder.workers.BatteryWorker
|
||||||
|
|
||||||
|
@Suppress("PropertyName")
|
||||||
|
class BatteryReceiver : BroadcastReceiver() {
|
||||||
|
|
||||||
|
val TAG: String = BatteryReceiver::class.java.simpleName
|
||||||
|
|
||||||
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
|
|
||||||
|
if (context == null || intent?.action != Intent.ACTION_BATTERY_CHANGED) return
|
||||||
|
|
||||||
|
val batteryInfo = BatteryUtils.getBatteryInfo(intent).toString()
|
||||||
|
TaskUtils.batteryInfo = batteryInfo
|
||||||
|
|
||||||
|
val levelNew = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0)
|
||||||
|
val levelOld = TaskUtils.batteryLevel
|
||||||
|
val isLevelChanged = levelNew != levelOld
|
||||||
|
TaskUtils.batteryLevel = levelNew
|
||||||
|
|
||||||
|
val scale: Int = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100)
|
||||||
|
TaskUtils.batteryPct = levelNew.toFloat() / scale.toFloat() * 100
|
||||||
|
|
||||||
|
val pluggedNew: Int = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1)
|
||||||
|
val pluggedOld = TaskUtils.batteryPlugged
|
||||||
|
val isPluggedChanged = pluggedNew != pluggedOld
|
||||||
|
TaskUtils.batteryPlugged = pluggedNew
|
||||||
|
|
||||||
|
val statusNew: Int = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1)
|
||||||
|
val statusOld = TaskUtils.batteryStatus
|
||||||
|
val isStatusChanged = statusNew != statusOld
|
||||||
|
TaskUtils.batteryStatus = statusNew
|
||||||
|
|
||||||
|
//电量改变
|
||||||
|
if (isLevelChanged) {
|
||||||
|
Log.d(TAG, "电量改变")
|
||||||
|
val request = OneTimeWorkRequestBuilder<BatteryWorker>().setInputData(
|
||||||
|
workDataOf(
|
||||||
|
TaskWorker.conditionType to TASK_CONDITION_BATTERY,
|
||||||
|
"status" to statusNew,
|
||||||
|
"level_new" to levelNew,
|
||||||
|
"level_old" to levelOld,
|
||||||
|
)
|
||||||
|
).build()
|
||||||
|
WorkManager.getInstance(context).enqueue(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
//充电状态改变
|
||||||
|
if (isPluggedChanged || isStatusChanged) {
|
||||||
|
Log.d(TAG, "充电状态改变")
|
||||||
|
val request = OneTimeWorkRequestBuilder<BatteryWorker>().setInputData(
|
||||||
|
workDataOf(
|
||||||
|
TaskWorker.conditionType to TASK_CONDITION_CHARGE,
|
||||||
|
"status_new" to statusNew,
|
||||||
|
"status_old" to statusOld,
|
||||||
|
"plugged_new" to pluggedNew,
|
||||||
|
"plugged_old" to pluggedOld,
|
||||||
|
)
|
||||||
|
).build()
|
||||||
|
WorkManager.getInstance(context).enqueue(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package com.idormy.sms.forwarder.receiver
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.util.Log
|
||||||
|
import com.idormy.sms.forwarder.activity.SplashActivity
|
||||||
|
|
||||||
|
@Suppress("PropertyName")
|
||||||
|
class BootCompletedReceiver : BroadcastReceiver() {
|
||||||
|
|
||||||
|
val TAG: String = BootCompletedReceiver::class.java.simpleName
|
||||||
|
|
||||||
|
override fun onReceive(context: Context, intent: Intent?) {
|
||||||
|
|
||||||
|
if (intent?.action != Intent.ACTION_BOOT_COMPLETED && intent?.action != Intent.ACTION_LOCKED_BOOT_COMPLETED) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
Log.d(TAG, "强制重启APP一次")
|
||||||
|
val intent1 = Intent(context, SplashActivity::class.java)
|
||||||
|
intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
||||||
|
context.startActivity(intent1)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -1,28 +0,0 @@
|
|||||||
package com.idormy.sms.forwarder.receiver
|
|
||||||
|
|
||||||
import android.content.BroadcastReceiver
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.util.Log
|
|
||||||
import com.idormy.sms.forwarder.activity.SplashActivity
|
|
||||||
|
|
||||||
@Suppress("PropertyName")
|
|
||||||
class BootReceiver : BroadcastReceiver() {
|
|
||||||
|
|
||||||
val TAG: String = BootReceiver::class.java.simpleName
|
|
||||||
|
|
||||||
override fun onReceive(context: Context, intent: Intent?) {
|
|
||||||
val receiveAction: String? = intent?.action
|
|
||||||
Log.d(TAG, "onReceive intent $receiveAction")
|
|
||||||
if (receiveAction == Intent.ACTION_BOOT_COMPLETED || receiveAction == Intent.ACTION_LOCKED_BOOT_COMPLETED) {
|
|
||||||
try {
|
|
||||||
Log.d(TAG, "强制重启APP一次")
|
|
||||||
val intent1 = Intent(context, SplashActivity::class.java)
|
|
||||||
intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
|
||||||
context.startActivity(intent1)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -22,7 +22,7 @@ import java.util.Date
|
|||||||
@Suppress("PrivatePropertyName", "UNUSED_PARAMETER")
|
@Suppress("PrivatePropertyName", "UNUSED_PARAMETER")
|
||||||
class SimStateReceiver : BroadcastReceiver() {
|
class SimStateReceiver : BroadcastReceiver() {
|
||||||
|
|
||||||
private var TAG = "SimStateReceiver"
|
private var TAG = SimStateReceiver::class.java.simpleName
|
||||||
|
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
//纯客户端模式
|
//纯客户端模式
|
||||||
|
@ -23,7 +23,7 @@ import java.util.Date
|
|||||||
@Suppress("PrivatePropertyName")
|
@Suppress("PrivatePropertyName")
|
||||||
class SmsReceiver : BroadcastReceiver() {
|
class SmsReceiver : BroadcastReceiver() {
|
||||||
|
|
||||||
private var TAG = "SmsReceiver"
|
private var TAG = SmsReceiver::class.java.simpleName
|
||||||
private var from = ""
|
private var from = ""
|
||||||
private var msg = ""
|
private var msg = ""
|
||||||
|
|
||||||
|
@ -1,172 +0,0 @@
|
|||||||
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.os.IBinder
|
|
||||||
import android.text.TextUtils
|
|
||||||
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.App
|
|
||||||
import com.idormy.sms.forwarder.R
|
|
||||||
import com.idormy.sms.forwarder.core.Core
|
|
||||||
import com.idormy.sms.forwarder.database.AppDatabase
|
|
||||||
import com.idormy.sms.forwarder.entity.MsgInfo
|
|
||||||
import com.idormy.sms.forwarder.utils.BatteryUtils
|
|
||||||
import com.idormy.sms.forwarder.utils.CacheUtils
|
|
||||||
import com.idormy.sms.forwarder.utils.HistoryUtils
|
|
||||||
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.file.FileUtils
|
|
||||||
import frpclib.Frpclib
|
|
||||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.GlobalScope
|
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
@OptIn(DelicateCoroutinesApi::class)
|
|
||||||
@Suppress("DeferredResultUnused")
|
|
||||||
class BatteryService : Service() {
|
|
||||||
|
|
||||||
override fun onBind(intent: Intent): IBinder? {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate() {
|
|
||||||
super.onCreate()
|
|
||||||
Log.i(TAG, "onCreate--------------")
|
|
||||||
|
|
||||||
//纯客户端模式
|
|
||||||
//if (SettingUtils.enablePureClientMode) return
|
|
||||||
|
|
||||||
val batteryFilter = IntentFilter()
|
|
||||||
batteryFilter.addAction(Intent.ACTION_BATTERY_CHANGED)
|
|
||||||
registerReceiver(batteryReceiver, batteryFilter)
|
|
||||||
}
|
|
||||||
|
|
||||||
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(batteryReceiver)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 接收电池信息更新的广播
|
|
||||||
private val batteryReceiver: BroadcastReceiver = object : BroadcastReceiver() {
|
|
||||||
@SuppressLint("DefaultLocale")
|
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
|
||||||
|
|
||||||
if (intent.action != Intent.ACTION_BATTERY_CHANGED) return
|
|
||||||
|
|
||||||
//自动删除N天前的转发记录
|
|
||||||
if (SettingUtils.autoCleanLogsDays > 0) {
|
|
||||||
Log.d(TAG, "自动删除N天前的转发记录")
|
|
||||||
val cal = Calendar.getInstance()
|
|
||||||
cal.add(Calendar.DAY_OF_MONTH, 0 - SettingUtils.autoCleanLogsDays)
|
|
||||||
Core.msg.deleteTimeAgo(cal.timeInMillis)
|
|
||||||
|
|
||||||
//清理缓存
|
|
||||||
HistoryUtils.clearPreference()
|
|
||||||
CacheUtils.clearAllCache(context)
|
|
||||||
}
|
|
||||||
|
|
||||||
//守护自启动的Frpc
|
|
||||||
if (FileUtils.isFileExists(filesDir.absolutePath + "/libs/libgojni.so")) {
|
|
||||||
GlobalScope.async(Dispatchers.IO) {
|
|
||||||
val frpcList = AppDatabase.getInstance(App.context).frpcDao().getAutorun()
|
|
||||||
|
|
||||||
if (frpcList.isEmpty()) {
|
|
||||||
Log.d(TAG, "没有自启动的Frpc")
|
|
||||||
return@async
|
|
||||||
}
|
|
||||||
|
|
||||||
for (frpc in frpcList) {
|
|
||||||
if (!Frpclib.isRunning(frpc.uid)) {
|
|
||||||
val error = Frpclib.runContent(frpc.uid, frpc.config)
|
|
||||||
if (!TextUtils.isEmpty(error)) {
|
|
||||||
Log.e(TAG, error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//电量发生变化
|
|
||||||
val levelCur: Int = intent.getIntExtra("level", 0)
|
|
||||||
val levelPre: Int = SettingUtils.batteryLevelCurrent
|
|
||||||
if (levelCur != levelPre) {
|
|
||||||
var msg: String = BatteryUtils.getBatteryInfo(intent).toString()
|
|
||||||
SettingUtils.batteryLevelCurrent = levelCur
|
|
||||||
val levelMin: Int = SettingUtils.batteryLevelMin
|
|
||||||
val levelMax: Int = SettingUtils.batteryLevelMax
|
|
||||||
if (SettingUtils.batteryLevelOnce && levelMin > 0 && levelPre > levelCur && levelCur <= levelMin) { //电量下降到下限
|
|
||||||
msg = String.format(getString(R.string.below_level_min), msg)
|
|
||||||
sendMessage(context, msg)
|
|
||||||
return
|
|
||||||
} else if (SettingUtils.batteryLevelOnce && levelMax > 0 && levelPre < levelCur && levelCur >= levelMax) { //电量上升到上限
|
|
||||||
msg = String.format(getString(R.string.over_level_max), msg)
|
|
||||||
sendMessage(context, msg)
|
|
||||||
return
|
|
||||||
} else if (!SettingUtils.batteryLevelOnce && levelMin > 0 && levelPre > levelCur && levelCur == levelMin) { //电量下降到下限
|
|
||||||
msg = String.format(getString(R.string.reach_level_min), msg)
|
|
||||||
sendMessage(context, msg)
|
|
||||||
return
|
|
||||||
} else if (!SettingUtils.batteryLevelOnce && levelMax > 0 && levelPre < levelCur && levelCur == levelMax) { //电量上升到上限
|
|
||||||
msg = String.format(getString(R.string.reach_level_max), msg)
|
|
||||||
sendMessage(context, msg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//充电状态改变
|
|
||||||
val status: Int = intent.getIntExtra("status", 0)
|
|
||||||
if (SettingUtils.enableBatteryReceiver) {
|
|
||||||
val oldStatus: Int = SettingUtils.batteryStatus
|
|
||||||
if (status != oldStatus) {
|
|
||||||
var msg: String = BatteryUtils.getBatteryInfo(intent).toString()
|
|
||||||
SettingUtils.batteryStatus = status
|
|
||||||
msg = getString(R.string.battery_status_changed) + BatteryUtils.getStatus(
|
|
||||||
oldStatus
|
|
||||||
) + " → " + BatteryUtils.getStatus(status) + msg
|
|
||||||
sendMessage(context, msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//发送信息
|
|
||||||
private fun sendMessage(context: Context, msg: String) {
|
|
||||||
Log.i(TAG, msg)
|
|
||||||
try {
|
|
||||||
val msgInfo = MsgInfo("app", "88888888", msg, Date(), getString(R.string.battery_status_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 = "BatteryReceiver"
|
|
||||||
}
|
|
||||||
}
|
|
@ -49,7 +49,7 @@ import java.util.Date
|
|||||||
@Suppress("PrivatePropertyName", "DeferredResultUnused", "OPT_IN_USAGE", "DEPRECATION", "LiftReturnOrAssignment")
|
@Suppress("PrivatePropertyName", "DeferredResultUnused", "OPT_IN_USAGE", "DEPRECATION", "LiftReturnOrAssignment")
|
||||||
class ForegroundService : Service() {
|
class ForegroundService : Service() {
|
||||||
|
|
||||||
private val TAG: String = "ForegroundService"
|
private val TAG: String = ForegroundService::class.java.simpleName
|
||||||
private var notificationManager: NotificationManager? = null
|
private var notificationManager: NotificationManager? = null
|
||||||
|
|
||||||
private val compositeDisposable = CompositeDisposable()
|
private val compositeDisposable = CompositeDisposable()
|
||||||
|
@ -9,13 +9,12 @@ import com.idormy.sms.forwarder.utils.HTTP_SERVER_TIME_OUT
|
|||||||
import com.idormy.sms.forwarder.utils.SettingUtils
|
import com.idormy.sms.forwarder.utils.SettingUtils
|
||||||
import com.yanzhenjie.andserver.AndServer
|
import com.yanzhenjie.andserver.AndServer
|
||||||
import com.yanzhenjie.andserver.Server
|
import com.yanzhenjie.andserver.Server
|
||||||
import java.util.*
|
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
@Suppress("PrivatePropertyName")
|
@Suppress("PrivatePropertyName")
|
||||||
class HttpService : Service(), Server.ServerListener {
|
class HttpServerService : Service(), Server.ServerListener {
|
||||||
|
|
||||||
private val TAG: String = "HttpService"
|
private val TAG: String = HttpServerService::class.java.simpleName
|
||||||
private val server by lazy {
|
private val server by lazy {
|
||||||
AndServer.webServer(this).port(HTTP_SERVER_PORT).listener(this).timeout(HTTP_SERVER_TIME_OUT, TimeUnit.SECONDS).build()
|
AndServer.webServer(this).port(HTTP_SERVER_PORT).listener(this).timeout(HTTP_SERVER_TIME_OUT, TimeUnit.SECONDS).build()
|
||||||
}
|
}
|
@ -1,265 +0,0 @@
|
|||||||
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.net.wifi.WifiInfo
|
|
||||||
import android.net.wifi.WifiManager
|
|
||||||
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.CommonUtils
|
|
||||||
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.*
|
|
||||||
|
|
||||||
import android.os.Build
|
|
||||||
import android.telephony.SubscriptionInfo
|
|
||||||
import android.telephony.SubscriptionManager
|
|
||||||
import androidx.annotation.RequiresApi
|
|
||||||
import com.idormy.sms.forwarder.App
|
|
||||||
import com.idormy.sms.forwarder.utils.PhoneUtils
|
|
||||||
import java.lang.reflect.Method
|
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
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() {
|
|
||||||
@RequiresApi(Build.VERSION_CODES.Q)
|
|
||||||
@SuppressLint("DefaultLocale")
|
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
|
||||||
|
|
||||||
if (intent.action != ConnectivityManager.CONNECTIVITY_ACTION) return
|
|
||||||
|
|
||||||
if (!SettingUtils.enableNetworkStateReceiver) return
|
|
||||||
|
|
||||||
Log.i(TAG, "网络状态已经改变,延时2秒后获取信息")
|
|
||||||
Thread.sleep(2000)
|
|
||||||
|
|
||||||
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 -> getString(R.string.no_network)
|
|
||||||
NetworkUtils.NetState.NET_2G -> getString(R.string.net_2g)
|
|
||||||
NetworkUtils.NetState.NET_3G -> getString(R.string.net_3g)
|
|
||||||
NetworkUtils.NetState.NET_4G -> getString(R.string.net_4g)
|
|
||||||
NetworkUtils.NetState.NET_5G -> getString(R.string.net_5g)
|
|
||||||
NetworkUtils.NetState.NET_WIFI -> getString(R.string.net_wifi)
|
|
||||||
NetworkUtils.NetState.NET_ETHERNET -> getString(R.string.net_ethernet)
|
|
||||||
NetworkUtils.NetState.NET_UNKNOWN -> getString(R.string.net_unknown)
|
|
||||||
else -> getString(R.string.net_unknown)
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
// 获取当前使用的 SIM index
|
|
||||||
val simIndex = getSlotId(context)
|
|
||||||
if (simIndex != -1) {
|
|
||||||
// 获取 SIM 卡信息
|
|
||||||
App.SimInfoList = PhoneUtils.getSimMultiInfo()
|
|
||||||
Log.d(TAG, App.SimInfoList.toString())
|
|
||||||
if (App.SimInfoList[simIndex]?.mCarrierName != null) {
|
|
||||||
//获取网络运营商名称:中国移动、中国联通、中国电信
|
|
||||||
msg.append(getString(R.string.carrier_name)).append(": ").append(App.SimInfoList[simIndex]?.mCarrierName).append("\n")
|
|
||||||
}
|
|
||||||
msg.append(getString(R.string.data_sim_index)).append(": SIM-").append(simIndex + 1).append("\n")
|
|
||||||
}
|
|
||||||
} else if (netStateType == NetworkUtils.NetState.NET_WIFI) {
|
|
||||||
//获取当前连接的WiFi名称
|
|
||||||
val wifiSSID = getWifiSSID(context)
|
|
||||||
msg.append(getString(R.string.wifi_ssid)).append(": ").append(wifiSSID).append("\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
//获取IP地址
|
|
||||||
val ipList = CommonUtils.getIPAddresses().filter { !isLocalAddress(it) }
|
|
||||||
if (ServiceUtils.isServiceRunning("com.idormy.sms.forwarder.service.HttpService")) {
|
|
||||||
ipList.forEach {
|
|
||||||
msg.append(getString(R.string.host_address)).append(": ").append(it).append("\n")
|
|
||||||
val hostAddress = if (it.indexOf(':', 0, false) > 0) "[${CommonUtils.removeInterfaceFromIP(it)}]" else it
|
|
||||||
msg.append(getString(R.string.http_server)).append(": ").append("http://${hostAddress}:5000").append("\n")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ipList.forEach {
|
|
||||||
msg.append(getString(R.string.host_address)).append(": ").append(it).append("\n")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sendMessage(context, msg.toString().trimEnd())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 判断手机数据流量是否打开
|
|
||||||
@Suppress("rawtypes", "unchecked")
|
|
||||||
private fun isMobileDataOpen(context: Context): Boolean {
|
|
||||||
return try {
|
|
||||||
val mConnectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
|
||||||
val ownerClass = mConnectivityManager.javaClass
|
|
||||||
val method = ownerClass.getMethod("getMobileDataEnabled")
|
|
||||||
method.invoke(mConnectivityManager) as Boolean
|
|
||||||
} catch (e: Exception) {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取当前数据连接的卡槽ID
|
|
||||||
@RequiresApi(Build.VERSION_CODES.Q)
|
|
||||||
private fun getSlotId(context: Context): Int {
|
|
||||||
if (!isMobileDataOpen(context)) {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
var dataSubId = 0
|
|
||||||
try {
|
|
||||||
dataSubId = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
||||||
SubscriptionManager.getDefaultDataSubscriptionId()
|
|
||||||
} else {
|
|
||||||
getDataSubId(context)
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
return SubscriptionManager.getSlotIndex(dataSubId)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取数据连接的订阅ID
|
|
||||||
@SuppressLint("DiscouragedPrivateApi")
|
|
||||||
private fun getDataSubId(context: Context): Int {
|
|
||||||
val defaultDataSlotId = getDefaultDataSlotId(context)
|
|
||||||
try {
|
|
||||||
val obj = Class.forName("android.telephony.SubscriptionManager")
|
|
||||||
.getDeclaredMethod("getSubId", Int::class.javaPrimitiveType)
|
|
||||||
.invoke(null, defaultDataSlotId)
|
|
||||||
if (obj != null) {
|
|
||||||
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
return (obj as LongArray)[0].toInt()
|
|
||||||
}
|
|
||||||
return (obj as IntArray)[0]
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
return defaultDataSlotId
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取默认数据卡的卡槽ID
|
|
||||||
private fun getDefaultDataSlotId(context: Context): Int {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
|
|
||||||
val subscriptionManager = SubscriptionManager.from(context.applicationContext)
|
|
||||||
if (subscriptionManager != null) {
|
|
||||||
try {
|
|
||||||
val subClass = Class.forName(subscriptionManager.javaClass.name)
|
|
||||||
val getSubID = subClass.getMethod("getDefaultDataSubscriptionInfo")
|
|
||||||
val subInfo = getSubID.invoke(subscriptionManager) as SubscriptionInfo
|
|
||||||
return subInfo.simSlotIndex
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
val cls = Class.forName("android.telephony.SubscriptionManager")
|
|
||||||
val getSubId: Method = try {
|
|
||||||
cls.getDeclaredMethod("getDefaultDataSubId")
|
|
||||||
} catch (e: NoSuchMethodException) {
|
|
||||||
cls.getDeclaredMethod("getDefaultDataSubscriptionId")
|
|
||||||
}
|
|
||||||
val subId = getSubId.invoke(null) as Int
|
|
||||||
val slotId: Int = if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
val getSlotId = cls.getDeclaredMethod("getSlotId", Long::class.javaPrimitiveType)
|
|
||||||
getSlotId.invoke(null, subId.toLong()) as Int
|
|
||||||
} else {
|
|
||||||
val getSlotId = cls.getDeclaredMethod("getSlotId", Int::class.javaPrimitiveType)
|
|
||||||
getSlotId.invoke(null, subId) as Int
|
|
||||||
}
|
|
||||||
return slotId
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
//发送信息
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//获取当前连接的WiFi名称
|
|
||||||
@SuppressLint("WifiManagerPotentialLeak")
|
|
||||||
private fun getWifiSSID(context: Context): String {
|
|
||||||
val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager
|
|
||||||
val wifiInfo: WifiInfo? = wifiManager.connectionInfo
|
|
||||||
|
|
||||||
if (wifiInfo != null && wifiInfo.networkId != -1) {
|
|
||||||
return wifiInfo.ssid.replace("\"", "")
|
|
||||||
}
|
|
||||||
|
|
||||||
return "Not connected to WiFi"
|
|
||||||
}
|
|
||||||
|
|
||||||
//检查IP地址是否为本地地址
|
|
||||||
private fun isLocalAddress(ip: String): Boolean {
|
|
||||||
return ip == "127.0.0.1" || ip == "::1" || ip.startsWith("fe80:") || ip.startsWith("fec0:")
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "NetworkStateReceiver"
|
|
||||||
}
|
|
||||||
}
|
|
@ -24,9 +24,9 @@ import java.util.*
|
|||||||
|
|
||||||
|
|
||||||
@Suppress("PrivatePropertyName", "DEPRECATION")
|
@Suppress("PrivatePropertyName", "DEPRECATION")
|
||||||
class NotifyService : NotificationListenerService() {
|
class NotificationService : NotificationListenerService() {
|
||||||
|
|
||||||
private val TAG: String = "NotifyService"
|
private val TAG: String = NotificationService::class.java.simpleName
|
||||||
|
|
||||||
override fun onListenerConnected() {
|
override fun onListenerConnected() {
|
||||||
Log.d(TAG, "onListenerConnected")
|
Log.d(TAG, "onListenerConnected")
|
@ -7,6 +7,7 @@ import com.idormy.sms.forwarder.R
|
|||||||
import com.idormy.sms.forwarder.entity.BatteryInfo
|
import com.idormy.sms.forwarder.entity.BatteryInfo
|
||||||
import com.xuexiang.xui.utils.ResUtils.getString
|
import com.xuexiang.xui.utils.ResUtils.getString
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION", "MemberVisibilityCanBePrivate")
|
||||||
object BatteryUtils {
|
object BatteryUtils {
|
||||||
private const val TAG = "BatteryUtils"
|
private const val TAG = "BatteryUtils"
|
||||||
|
|
||||||
@ -27,22 +28,8 @@ object BatteryUtils {
|
|||||||
if (voltage > 0) batteryInfo.voltage = "${String.format("%.2f", voltage / 1000f)}V"
|
if (voltage > 0) batteryInfo.voltage = "${String.format("%.2f", voltage / 1000f)}V"
|
||||||
if (temperature > 0) batteryInfo.temperature = "${String.format("%.2f", temperature / 10f)}℃"
|
if (temperature > 0) batteryInfo.temperature = "${String.format("%.2f", temperature / 10f)}℃"
|
||||||
batteryInfo.status = getStatus(status)
|
batteryInfo.status = getStatus(status)
|
||||||
batteryInfo.health = when (health) {
|
batteryInfo.health = getHealth(health)
|
||||||
BatteryManager.BATTERY_HEALTH_UNKNOWN -> getString(R.string.battery_unknown)
|
batteryInfo.plugged = getPlugged(plugged)
|
||||||
BatteryManager.BATTERY_HEALTH_GOOD -> getString(R.string.battery_good)
|
|
||||||
BatteryManager.BATTERY_HEALTH_OVERHEAT -> getString(R.string.battery_overheat)
|
|
||||||
BatteryManager.BATTERY_HEALTH_DEAD -> getString(R.string.battery_dead)
|
|
||||||
BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE -> getString(R.string.battery_over_voltage)
|
|
||||||
BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE -> getString(R.string.battery_unspecified_failure)
|
|
||||||
BatteryManager.BATTERY_HEALTH_COLD -> getString(R.string.battery_cold)
|
|
||||||
else -> getString(R.string.battery_unknown)
|
|
||||||
}
|
|
||||||
batteryInfo.plugged = when (plugged) {
|
|
||||||
BatteryManager.BATTERY_PLUGGED_AC -> getString(R.string.battery_ac)
|
|
||||||
BatteryManager.BATTERY_PLUGGED_USB -> getString(R.string.battery_usb)
|
|
||||||
BatteryManager.BATTERY_PLUGGED_WIRELESS -> getString(R.string.battery_wireless)
|
|
||||||
else -> getString(R.string.battery_unknown)
|
|
||||||
}
|
|
||||||
Log.i(TAG, batteryInfo.toString())
|
Log.i(TAG, batteryInfo.toString())
|
||||||
return batteryInfo
|
return batteryInfo
|
||||||
}
|
}
|
||||||
@ -58,4 +45,26 @@ object BatteryUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getHealth(health: Int): String {
|
||||||
|
return when (health) {
|
||||||
|
BatteryManager.BATTERY_HEALTH_UNKNOWN -> getString(R.string.battery_unknown)
|
||||||
|
BatteryManager.BATTERY_HEALTH_GOOD -> getString(R.string.battery_good)
|
||||||
|
BatteryManager.BATTERY_HEALTH_OVERHEAT -> getString(R.string.battery_overheat)
|
||||||
|
BatteryManager.BATTERY_HEALTH_DEAD -> getString(R.string.battery_dead)
|
||||||
|
BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE -> getString(R.string.battery_over_voltage)
|
||||||
|
BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE -> getString(R.string.battery_unspecified_failure)
|
||||||
|
BatteryManager.BATTERY_HEALTH_COLD -> getString(R.string.battery_cold)
|
||||||
|
else -> getString(R.string.battery_unknown)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPlugged(plugged: Int): String {
|
||||||
|
return when (plugged) {
|
||||||
|
BatteryManager.BATTERY_PLUGGED_AC -> getString(R.string.battery_ac)
|
||||||
|
BatteryManager.BATTERY_PLUGGED_USB -> getString(R.string.battery_usb)
|
||||||
|
BatteryManager.BATTERY_PLUGGED_WIRELESS -> getString(R.string.battery_wireless)
|
||||||
|
else -> getString(R.string.battery_unknown)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -23,7 +23,7 @@ import com.idormy.sms.forwarder.core.webview.AgentWebFragment
|
|||||||
import com.idormy.sms.forwarder.entity.ImageInfo
|
import com.idormy.sms.forwarder.entity.ImageInfo
|
||||||
import com.idormy.sms.forwarder.fragment.MarkdownFragment
|
import com.idormy.sms.forwarder.fragment.MarkdownFragment
|
||||||
import com.idormy.sms.forwarder.fragment.ServiceProtocolFragment
|
import com.idormy.sms.forwarder.fragment.ServiceProtocolFragment
|
||||||
import com.idormy.sms.forwarder.service.NotifyService
|
import com.idormy.sms.forwarder.service.NotificationService
|
||||||
import com.xuexiang.xpage.base.XPageFragment
|
import com.xuexiang.xpage.base.XPageFragment
|
||||||
import com.xuexiang.xpage.core.PageOption
|
import com.xuexiang.xpage.core.PageOption
|
||||||
import com.xuexiang.xui.utils.ColorUtils
|
import com.xuexiang.xui.utils.ColorUtils
|
||||||
@ -273,10 +273,10 @@ class CommonUtils private constructor() {
|
|||||||
fun toggleNotificationListenerService(context: Context) {
|
fun toggleNotificationListenerService(context: Context) {
|
||||||
val pm = context.packageManager
|
val pm = context.packageManager
|
||||||
pm.setComponentEnabledSetting(
|
pm.setComponentEnabledSetting(
|
||||||
ComponentName(context.applicationContext, NotifyService::class.java), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP
|
ComponentName(context.applicationContext, NotificationService::class.java), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP
|
||||||
)
|
)
|
||||||
pm.setComponentEnabledSetting(
|
pm.setComponentEnabledSetting(
|
||||||
ComponentName(context.applicationContext, NotifyService::class.java), PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP
|
ComponentName(context.applicationContext, NotificationService::class.java), PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,9 +16,14 @@ object Worker {
|
|||||||
const val rule = "rule"
|
const val rule = "rule"
|
||||||
const val senderIndex = "sender_index"
|
const val senderIndex = "sender_index"
|
||||||
const val msgId = "msg_id"
|
const val msgId = "msg_id"
|
||||||
|
}
|
||||||
|
|
||||||
|
object TaskWorker {
|
||||||
const val taskId = "task_id"
|
const val taskId = "task_id"
|
||||||
const val actionType = "action_type"
|
const val task = "task"
|
||||||
const val actionSetting = "action_setting"
|
const val taskActions = "task_actions"
|
||||||
|
const val conditionType = "condition_type"
|
||||||
|
const val msgInfo = "msg_info"
|
||||||
}
|
}
|
||||||
|
|
||||||
//初始化相关
|
//初始化相关
|
||||||
@ -59,17 +64,6 @@ const val SP_AUTO_CLEAN_LOGS_DAYS = "auto_clean_logs_days"
|
|||||||
|
|
||||||
const val SP_NET_STATE_RECEIVER = "enable_network_state_receiver"
|
const val SP_NET_STATE_RECEIVER = "enable_network_state_receiver"
|
||||||
|
|
||||||
const val SP_BATTERY_RECEIVER = "enable_battery_receiver"
|
|
||||||
const val SP_BATTERY_STATUS = "battery_status"
|
|
||||||
const val SP_BATTERY_LEVEL_MIN = "battery_level_min"
|
|
||||||
const val SP_BATTERY_LEVEL_MAX = "battery_level_max"
|
|
||||||
const val SP_BATTERY_LEVEL_ONCE = "battery_level_once"
|
|
||||||
const val SP_BATTERY_LEVEL_CURRENT = "battery_level_current"
|
|
||||||
|
|
||||||
const val SP_BATTERY_CRON = "enable_battery_cron"
|
|
||||||
const val SP_BATTERY_CRON_START_TIME = "battery_cron_start_time"
|
|
||||||
const val SP_BATTERY_CRON_INTERVAL = "battery_cron_interval"
|
|
||||||
|
|
||||||
const val SP_ENABLE_EXCLUDE_FROM_RECENTS = "enable_exclude_from_recents"
|
const val SP_ENABLE_EXCLUDE_FROM_RECENTS = "enable_exclude_from_recents"
|
||||||
const val SP_ENABLE_PLAY_SILENCE_MUSIC = "enable_play_silence_music"
|
const val SP_ENABLE_PLAY_SILENCE_MUSIC = "enable_play_silence_music"
|
||||||
const val SP_ENABLE_ONE_PIXEL_ACTIVITY = "enable_one_pixel_activity"
|
const val SP_ENABLE_ONE_PIXEL_ACTIVITY = "enable_one_pixel_activity"
|
||||||
@ -581,4 +575,9 @@ var TASK_ACTION_FRAGMENT_LIST = listOf(
|
|||||||
CoreAnim.slide,
|
CoreAnim.slide,
|
||||||
R.drawable.auto_task_icon_http_server
|
R.drawable.auto_task_icon_http_server
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const val SP_BATTERY_STATUS = "battery_status"
|
||||||
|
const val SP_BATTERY_LEVEL = "battery_level"
|
||||||
|
const val SP_BATTERY_PCT = "battery_pct"
|
||||||
|
const val SP_BATTERY_PLUGGED = "battery_plugged"
|
@ -77,33 +77,6 @@ class SettingUtils private constructor() {
|
|||||||
//是否监听网络状态变化
|
//是否监听网络状态变化
|
||||||
var enableNetworkStateReceiver: Boolean by SharedPreference(SP_NET_STATE_RECEIVER, false)
|
var enableNetworkStateReceiver: Boolean by SharedPreference(SP_NET_STATE_RECEIVER, false)
|
||||||
|
|
||||||
//是否监听电池状态变化
|
|
||||||
var enableBatteryReceiver: Boolean by SharedPreference(SP_BATTERY_RECEIVER, false)
|
|
||||||
|
|
||||||
//电量预警当前状态
|
|
||||||
var batteryStatus: Int by SharedPreference(SP_BATTERY_STATUS, 0)
|
|
||||||
|
|
||||||
//电量预警当前值
|
|
||||||
var batteryLevelCurrent: Int by SharedPreference(SP_BATTERY_LEVEL_CURRENT, 0)
|
|
||||||
|
|
||||||
//电量预警最低值
|
|
||||||
var batteryLevelMin: Int by SharedPreference(SP_BATTERY_LEVEL_MIN, 0)
|
|
||||||
|
|
||||||
//电量预警最高值
|
|
||||||
var batteryLevelMax: Int by SharedPreference(SP_BATTERY_LEVEL_MAX, 100)
|
|
||||||
|
|
||||||
//是否持续电量预警
|
|
||||||
var batteryLevelOnce: Boolean by SharedPreference(SP_BATTERY_LEVEL_ONCE, false)
|
|
||||||
|
|
||||||
//是否定时推送电池状态
|
|
||||||
var enableBatteryCron: Boolean by SharedPreference(SP_BATTERY_CRON, false)
|
|
||||||
|
|
||||||
//是否定时推送电池状态——开始时间
|
|
||||||
var batteryCronStartTime: String by SharedPreference(SP_BATTERY_CRON_START_TIME, "00:00")
|
|
||||||
|
|
||||||
//是否定时推送电池状态——间隔时间(分钟)
|
|
||||||
var batteryCronInterval: Int by SharedPreference(SP_BATTERY_CRON_INTERVAL, 60)
|
|
||||||
|
|
||||||
//是否不在最近任务列表中显示
|
//是否不在最近任务列表中显示
|
||||||
var enableExcludeFromRecents: Boolean by SharedPreference(SP_ENABLE_EXCLUDE_FROM_RECENTS, false)
|
var enableExcludeFromRecents: Boolean by SharedPreference(SP_ENABLE_EXCLUDE_FROM_RECENTS, false)
|
||||||
|
|
||||||
|
@ -9,12 +9,10 @@ import android.util.Log
|
|||||||
import androidx.core.app.ActivityCompat
|
import androidx.core.app.ActivityCompat
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.idormy.sms.forwarder.App
|
import com.idormy.sms.forwarder.App
|
||||||
import com.idormy.sms.forwarder.R
|
|
||||||
import com.idormy.sms.forwarder.database.AppDatabase
|
import com.idormy.sms.forwarder.database.AppDatabase
|
||||||
import com.idormy.sms.forwarder.server.model.SmsSendData
|
import com.idormy.sms.forwarder.server.model.SmsSendData
|
||||||
import com.idormy.sms.forwarder.service.HttpService
|
import com.idormy.sms.forwarder.service.HttpServerService
|
||||||
import com.xuexiang.xrouter.utils.TextUtils
|
import com.xuexiang.xrouter.utils.TextUtils
|
||||||
import com.xuexiang.xui.utils.ResUtils
|
|
||||||
import com.xuexiang.xutil.XUtil
|
import com.xuexiang.xutil.XUtil
|
||||||
import com.xuexiang.xutil.file.FileUtils
|
import com.xuexiang.xutil.file.FileUtils
|
||||||
import com.xuexiang.xutil.system.DeviceUtils
|
import com.xuexiang.xutil.system.DeviceUtils
|
||||||
@ -101,7 +99,7 @@ class SmsCommandUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
"httpserver" -> {
|
"httpserver" -> {
|
||||||
Intent(context, HttpService::class.java).also {
|
Intent(context, HttpServerService::class.java).also {
|
||||||
if (action == "start") {
|
if (action == "start") {
|
||||||
context.startService(it)
|
context.startService(it)
|
||||||
} else if (action == "stop") {
|
} else if (action == "stop") {
|
||||||
|
@ -1,69 +0,0 @@
|
|||||||
package com.idormy.sms.forwarder.utils.task
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.app.AlarmManager
|
|
||||||
import android.app.PendingIntent
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Build
|
|
||||||
import com.idormy.sms.forwarder.database.entity.Task
|
|
||||||
import com.idormy.sms.forwarder.receiver.AlarmReceiver
|
|
||||||
|
|
||||||
class AlarmUtils {
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
@SuppressLint("StaticFieldLeak")
|
|
||||||
private lateinit var context: Context
|
|
||||||
|
|
||||||
fun initialize(context: Context) {
|
|
||||||
this.context = context.applicationContext
|
|
||||||
}
|
|
||||||
|
|
||||||
fun cancelAlarm(task: Task?) {
|
|
||||||
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
|
||||||
val alarmIntent = Intent(context, AlarmReceiver::class.java)
|
|
||||||
val requestCode = task?.id?.toInt() ?: -1
|
|
||||||
|
|
||||||
val pendingIntent = PendingIntent.getBroadcast(
|
|
||||||
context,
|
|
||||||
requestCode,
|
|
||||||
alarmIntent,
|
|
||||||
PendingIntent.FLAG_NO_CREATE or PendingIntent.FLAG_MUTABLE
|
|
||||||
)
|
|
||||||
pendingIntent?.let {
|
|
||||||
alarmManager.cancel(it)
|
|
||||||
it.cancel()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("ScheduleExactAlarm")
|
|
||||||
fun scheduleAlarm(task: Task) {
|
|
||||||
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
|
||||||
val alarmIntent = Intent(context, AlarmReceiver::class.java)
|
|
||||||
val requestCode = task.id.toInt()
|
|
||||||
alarmIntent.putExtra("TASK", task)
|
|
||||||
val pendingIntent = PendingIntent.getBroadcast(
|
|
||||||
context,
|
|
||||||
requestCode,
|
|
||||||
alarmIntent,
|
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
|
|
||||||
)
|
|
||||||
|
|
||||||
// TODO:设置闹钟,低电量模式下无法设置精确闹钟
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
||||||
alarmManager.setExactAndAllowWhileIdle(
|
|
||||||
AlarmManager.RTC_WAKEUP,
|
|
||||||
task.nextExecTime.time,
|
|
||||||
pendingIntent
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
alarmManager.setExact(
|
|
||||||
AlarmManager.RTC_WAKEUP,
|
|
||||||
task.nextExecTime.time,
|
|
||||||
pendingIntent
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,6 +6,7 @@ import androidx.work.ExistingWorkPolicy
|
|||||||
import androidx.work.OneTimeWorkRequestBuilder
|
import androidx.work.OneTimeWorkRequestBuilder
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
import com.idormy.sms.forwarder.database.entity.Task
|
import com.idormy.sms.forwarder.database.entity.Task
|
||||||
|
import com.idormy.sms.forwarder.utils.TaskWorker
|
||||||
import com.idormy.sms.forwarder.workers.CronWorker
|
import com.idormy.sms.forwarder.workers.CronWorker
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
@ -19,7 +20,7 @@ class CronJobScheduler {
|
|||||||
fun scheduleTask(task: Task) {
|
fun scheduleTask(task: Task) {
|
||||||
val currentTimeMillis = System.currentTimeMillis()
|
val currentTimeMillis = System.currentTimeMillis()
|
||||||
val delayInMillis = task.nextExecTime.time / 1000 * 1000 - currentTimeMillis
|
val delayInMillis = task.nextExecTime.time / 1000 * 1000 - currentTimeMillis
|
||||||
val inputData = Data.Builder().putLong("taskId", task.id).build()
|
val inputData = Data.Builder().putLong(TaskWorker.taskId, task.id).build()
|
||||||
val taskRequest = if (delayInMillis <= 0L) {
|
val taskRequest = if (delayInMillis <= 0L) {
|
||||||
Log.d(TAG, "任务${task.id}:立即执行,delayInMillis = $delayInMillis")
|
Log.d(TAG, "任务${task.id}:立即执行,delayInMillis = $delayInMillis")
|
||||||
OneTimeWorkRequestBuilder<CronWorker>()
|
OneTimeWorkRequestBuilder<CronWorker>()
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
package com.idormy.sms.forwarder.utils.task
|
package com.idormy.sms.forwarder.utils.task
|
||||||
|
|
||||||
import com.idormy.sms.forwarder.utils.SP_ENABLE_SERVER_AUTORUN
|
import android.os.BatteryManager
|
||||||
|
import com.idormy.sms.forwarder.utils.SP_BATTERY_LEVEL
|
||||||
|
import com.idormy.sms.forwarder.utils.SP_BATTERY_PCT
|
||||||
|
import com.idormy.sms.forwarder.utils.SP_BATTERY_PLUGGED
|
||||||
|
import com.idormy.sms.forwarder.utils.SP_BATTERY_STATUS
|
||||||
import com.idormy.sms.forwarder.utils.SharedPreference
|
import com.idormy.sms.forwarder.utils.SharedPreference
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -10,7 +14,19 @@ class TaskUtils private constructor() {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
//是否启用HttpServer开机自启
|
//电池信息
|
||||||
var enableServerAutorun: Boolean by SharedPreference(SP_ENABLE_SERVER_AUTORUN, false)
|
var batteryInfo: String by SharedPreference("batteryInfo", "")
|
||||||
|
|
||||||
|
//当前电量
|
||||||
|
var batteryLevel: Int by SharedPreference(SP_BATTERY_LEVEL, 0)
|
||||||
|
|
||||||
|
//当前电量百分比(level/scale)
|
||||||
|
var batteryPct: Float by SharedPreference(SP_BATTERY_PCT, 0.00F)
|
||||||
|
|
||||||
|
//电池状态
|
||||||
|
var batteryStatus: Int by SharedPreference(SP_BATTERY_STATUS, BatteryManager.BATTERY_STATUS_UNKNOWN)
|
||||||
|
|
||||||
|
//充电方式
|
||||||
|
var batteryPlugged: Int by SharedPreference(SP_BATTERY_PLUGGED, BatteryManager.BATTERY_PLUGGED_AC)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -13,76 +13,94 @@ import com.idormy.sms.forwarder.R
|
|||||||
import com.idormy.sms.forwarder.database.entity.Rule
|
import com.idormy.sms.forwarder.database.entity.Rule
|
||||||
import com.idormy.sms.forwarder.entity.MsgInfo
|
import com.idormy.sms.forwarder.entity.MsgInfo
|
||||||
import com.idormy.sms.forwarder.entity.task.SmsSetting
|
import com.idormy.sms.forwarder.entity.task.SmsSetting
|
||||||
|
import com.idormy.sms.forwarder.entity.task.TaskSetting
|
||||||
import com.idormy.sms.forwarder.utils.PhoneUtils
|
import com.idormy.sms.forwarder.utils.PhoneUtils
|
||||||
import com.idormy.sms.forwarder.utils.SendUtils
|
import com.idormy.sms.forwarder.utils.SendUtils
|
||||||
import com.idormy.sms.forwarder.utils.TASK_ACTION_NOTIFICATION
|
import com.idormy.sms.forwarder.utils.TASK_ACTION_NOTIFICATION
|
||||||
import com.idormy.sms.forwarder.utils.TASK_ACTION_SENDSMS
|
import com.idormy.sms.forwarder.utils.TASK_ACTION_SENDSMS
|
||||||
import com.idormy.sms.forwarder.utils.Worker
|
import com.idormy.sms.forwarder.utils.TaskWorker
|
||||||
import com.xuexiang.xui.utils.ResUtils
|
import com.xuexiang.xui.utils.ResUtils
|
||||||
import com.xuexiang.xutil.XUtil
|
import com.xuexiang.xutil.XUtil
|
||||||
|
|
||||||
|
//执行每个task具体动作任务
|
||||||
@Suppress("PrivatePropertyName", "DEPRECATION")
|
@Suppress("PrivatePropertyName", "DEPRECATION")
|
||||||
class ActionWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
|
class ActionWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
|
||||||
|
|
||||||
private val TAG: String = ActionWorker::class.java.simpleName
|
private val TAG: String = ActionWorker::class.java.simpleName
|
||||||
|
|
||||||
override suspend fun doWork(): Result {
|
override suspend fun doWork(): Result {
|
||||||
val taskId = inputData.getLong(Worker.taskId, -1L)
|
val taskId = inputData.getLong(TaskWorker.taskId, -1L)
|
||||||
val actionType = inputData.getInt(Worker.actionType, -1)
|
val taskActionsJson = inputData.getString(TaskWorker.taskActions)
|
||||||
val actionSetting = inputData.getString(Worker.actionSetting)
|
val msgInfoJson = inputData.getString(TaskWorker.msgInfo)
|
||||||
val msgInfoJson = inputData.getString(Worker.sendMsgInfo)
|
Log.d(TAG, "taskId: $taskId, taskActionsJson: $taskActionsJson, msgInfoJson: $msgInfoJson")
|
||||||
Log.d(TAG, "taskId: $taskId, actionType: $actionType, actionSetting: $actionSetting, msgInfoJson: $msgInfoJson")
|
if (taskId == -1L || taskActionsJson.isNullOrEmpty() || msgInfoJson.isNullOrEmpty()) {
|
||||||
if (taskId == -1L || actionSetting == null) {
|
|
||||||
Log.d(TAG, "taskId is -1L or actionSetting is null")
|
Log.d(TAG, "taskId is -1L or actionSetting is null")
|
||||||
return Result.failure()
|
return Result.failure()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val actionList = Gson().fromJson(taskActionsJson, Array<TaskSetting>::class.java).toMutableList()
|
||||||
|
if (actionList.isEmpty()) {
|
||||||
|
Log.d(TAG, "任务$taskId:actionList is empty")
|
||||||
|
return Result.failure()
|
||||||
|
}
|
||||||
|
|
||||||
val msgInfo = Gson().fromJson(msgInfoJson, MsgInfo::class.java)
|
val msgInfo = Gson().fromJson(msgInfoJson, MsgInfo::class.java)
|
||||||
|
if (msgInfo == null) {
|
||||||
|
Log.d(TAG, "任务$taskId:msgInfo is null")
|
||||||
|
return Result.failure()
|
||||||
|
}
|
||||||
|
|
||||||
when (actionType) {
|
var successNum = 0
|
||||||
TASK_ACTION_SENDSMS -> {
|
for (action in actionList) {
|
||||||
val smsSetting = Gson().fromJson(actionSetting, SmsSetting::class.java)
|
when (action.type) {
|
||||||
if (smsSetting == null) {
|
TASK_ACTION_SENDSMS -> {
|
||||||
Log.d(TAG, "任务$taskId:smsSetting is null")
|
val smsSetting = Gson().fromJson(action.setting, SmsSetting::class.java)
|
||||||
return Result.failure()
|
if (smsSetting == null) {
|
||||||
}
|
Log.d(TAG, "任务$taskId:smsSetting is null")
|
||||||
//获取卡槽信息
|
continue
|
||||||
if (App.SimInfoList.isEmpty()) {
|
}
|
||||||
App.SimInfoList = PhoneUtils.getSimMultiInfo()
|
//获取卡槽信息
|
||||||
}
|
if (App.SimInfoList.isEmpty()) {
|
||||||
Log.d(TAG, App.SimInfoList.toString())
|
App.SimInfoList = PhoneUtils.getSimMultiInfo()
|
||||||
|
}
|
||||||
|
Log.d(TAG, App.SimInfoList.toString())
|
||||||
|
|
||||||
//发送卡槽: 1=SIM1, 2=SIM2
|
//发送卡槽: 1=SIM1, 2=SIM2
|
||||||
val simSlotIndex = smsSetting.simSlot - 1
|
val simSlotIndex = smsSetting.simSlot - 1
|
||||||
//TODO:取不到卡槽信息时,采用默认卡槽发送
|
//TODO:取不到卡槽信息时,采用默认卡槽发送
|
||||||
val mSubscriptionId: Int = App.SimInfoList[simSlotIndex]?.mSubscriptionId ?: -1
|
val mSubscriptionId: Int = App.SimInfoList[simSlotIndex]?.mSubscriptionId ?: -1
|
||||||
|
|
||||||
val msg = if (ActivityCompat.checkSelfPermission(XUtil.getContext(), Manifest.permission.SEND_SMS) != PackageManager.PERMISSION_GRANTED) {
|
val msg = if (ActivityCompat.checkSelfPermission(XUtil.getContext(), Manifest.permission.SEND_SMS) != PackageManager.PERMISSION_GRANTED) {
|
||||||
ResUtils.getString(R.string.no_sms_sending_permission)
|
ResUtils.getString(R.string.no_sms_sending_permission)
|
||||||
} else {
|
} else {
|
||||||
PhoneUtils.sendSms(mSubscriptionId, smsSetting.phoneNumbers, smsSetting.msgContent) ?: "success"
|
PhoneUtils.sendSms(mSubscriptionId, smsSetting.phoneNumbers, smsSetting.msgContent)
|
||||||
|
successNum++
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.d(TAG, "任务$taskId:send sms result: $msg")
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.d(TAG, "任务$taskId:send sms result: $msg")
|
TASK_ACTION_NOTIFICATION -> {
|
||||||
return Result.success()
|
try {
|
||||||
}
|
val settingVo = Gson().fromJson(action.setting, Rule::class.java)
|
||||||
|
//自动任务的不需要吐司或者更新日志,特殊处理 logId = -1,msgId = -1
|
||||||
TASK_ACTION_NOTIFICATION -> {
|
SendUtils.sendMsgSender(msgInfo, settingVo, 0, -1L, -1L)
|
||||||
return try {
|
successNum++
|
||||||
val settingVo = Gson().fromJson(actionSetting, Rule::class.java)
|
} catch (e: Exception) {
|
||||||
//自动任务的不需要吐司或者更新日志,特殊处理 logId = -1,msgId = -1
|
e.printStackTrace()
|
||||||
SendUtils.sendMsgSender(msgInfo, settingVo, 0, -1L, -1L)
|
}
|
||||||
Result.success()
|
continue
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
Result.failure()
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
Log.d(TAG, "任务$taskId:action.type is $actionType")
|
Log.d(TAG, "任务$taskId:action.type is ${action.type}")
|
||||||
return Result.failure()
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return if (successNum == actionList.size) Result.success() else Result.failure()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -0,0 +1,149 @@
|
|||||||
|
package com.idormy.sms.forwarder.workers
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.work.CoroutineWorker
|
||||||
|
import androidx.work.Data
|
||||||
|
import androidx.work.OneTimeWorkRequestBuilder
|
||||||
|
import androidx.work.WorkManager
|
||||||
|
import androidx.work.WorkerParameters
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.idormy.sms.forwarder.App
|
||||||
|
import com.idormy.sms.forwarder.database.AppDatabase
|
||||||
|
import com.idormy.sms.forwarder.entity.MsgInfo
|
||||||
|
import com.idormy.sms.forwarder.entity.task.BatterySetting
|
||||||
|
import com.idormy.sms.forwarder.entity.task.ChargeSetting
|
||||||
|
import com.idormy.sms.forwarder.entity.task.TaskSetting
|
||||||
|
import com.idormy.sms.forwarder.utils.TASK_CONDITION_BATTERY
|
||||||
|
import com.idormy.sms.forwarder.utils.TASK_CONDITION_CHARGE
|
||||||
|
import com.idormy.sms.forwarder.utils.TaskWorker
|
||||||
|
import com.idormy.sms.forwarder.utils.task.TaskUtils
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
|
@Suppress("PrivatePropertyName", "DEPRECATION")
|
||||||
|
class BatteryWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
|
||||||
|
|
||||||
|
private val TAG: String = BatteryWorker::class.java.simpleName
|
||||||
|
|
||||||
|
override suspend fun doWork(): Result {
|
||||||
|
|
||||||
|
when (val conditionType = inputData.getInt(TaskWorker.conditionType, -1)) {
|
||||||
|
|
||||||
|
TASK_CONDITION_BATTERY -> {
|
||||||
|
val status = inputData.getInt("status", -1)
|
||||||
|
val levelNew = inputData.getInt("level_new", -1)
|
||||||
|
val levelOld = inputData.getInt("level_old", -1)
|
||||||
|
Log.d(TAG, "levelNew: $levelNew, levelOld: $levelOld")
|
||||||
|
if (levelNew == -1 || levelOld == -1) {
|
||||||
|
Log.d(TAG, "levelNew or levelOld is -1")
|
||||||
|
return Result.failure()
|
||||||
|
}
|
||||||
|
|
||||||
|
val taskList = AppDatabase.getInstance(App.context).taskDao().getByType(TASK_CONDITION_BATTERY)
|
||||||
|
for (task in taskList) {
|
||||||
|
Log.d(TAG, "task = $task")
|
||||||
|
|
||||||
|
// 根据任务信息执行相应操作
|
||||||
|
val conditionList = Gson().fromJson(task.conditions, Array<TaskSetting>::class.java).toMutableList()
|
||||||
|
if (conditionList.isEmpty()) {
|
||||||
|
Log.d(TAG, "任务${task.id}:conditionList is empty")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
val firstCondition = conditionList.firstOrNull()
|
||||||
|
if (firstCondition == null) {
|
||||||
|
Log.d(TAG, "任务${task.id}:firstCondition is null")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
val batterySetting = Gson().fromJson(firstCondition.setting, BatterySetting::class.java)
|
||||||
|
if (batterySetting == null) {
|
||||||
|
Log.d(TAG, "任务${task.id}:batterySetting is null")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
val msg = batterySetting.getMsg(status, levelNew, levelOld, TaskUtils.batteryInfo)
|
||||||
|
if (msg.isEmpty()) {
|
||||||
|
Log.d(TAG, "任务${task.id}:msg is empty, batterySetting = $batterySetting, status = $status, levelNew = $levelNew, levelOld = $levelOld")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO:判断其他条件是否满足
|
||||||
|
|
||||||
|
//TODO: 组装消息体 && 执行具体任务
|
||||||
|
val msgInfo = MsgInfo("task", task.name, msg, Date(), task.name)
|
||||||
|
val actionData = Data.Builder()
|
||||||
|
.putLong(TaskWorker.taskId, task.id)
|
||||||
|
.putString(TaskWorker.taskActions, task.actions)
|
||||||
|
.putString(TaskWorker.msgInfo, Gson().toJson(msgInfo))
|
||||||
|
.build()
|
||||||
|
val actionRequest = OneTimeWorkRequestBuilder<ActionWorker>().setInputData(actionData).build()
|
||||||
|
WorkManager.getInstance().enqueue(actionRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.success()
|
||||||
|
}
|
||||||
|
|
||||||
|
TASK_CONDITION_CHARGE -> {
|
||||||
|
val statusNew = inputData.getInt("status_new", -1)
|
||||||
|
val statusOld = inputData.getInt("status_old", -1)
|
||||||
|
val pluggedNew = inputData.getInt("plugged_new", -1)
|
||||||
|
val pluggedOld = inputData.getInt("plugged_old", -1)
|
||||||
|
Log.d(TAG, "statusNew: $statusNew, statusOld: $statusOld, pluggedNew: $pluggedNew, pluggedOld: $pluggedOld")
|
||||||
|
if (statusNew == -1 || statusOld == -1 || pluggedNew == -1 || pluggedOld == -1) {
|
||||||
|
Log.d(TAG, "statusNew or statusOld or pluggedNew or pluggedOld is -1")
|
||||||
|
return Result.failure()
|
||||||
|
}
|
||||||
|
|
||||||
|
val taskList = AppDatabase.getInstance(App.context).taskDao().getByType(TASK_CONDITION_CHARGE)
|
||||||
|
for (task in taskList) {
|
||||||
|
Log.d(TAG, "task = $task")
|
||||||
|
|
||||||
|
// 根据任务信息执行相应操作
|
||||||
|
val conditionList = Gson().fromJson(task.conditions, Array<TaskSetting>::class.java).toMutableList()
|
||||||
|
if (conditionList.isEmpty()) {
|
||||||
|
Log.d(TAG, "任务${task.id}:conditionList is empty")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
val firstCondition = conditionList.firstOrNull()
|
||||||
|
if (firstCondition == null) {
|
||||||
|
Log.d(TAG, "任务${task.id}:firstCondition is null")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
val chargeSetting = Gson().fromJson(firstCondition.setting, ChargeSetting::class.java)
|
||||||
|
if (chargeSetting == null) {
|
||||||
|
Log.d(TAG, "任务${task.id}:chargeSetting is null")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
val msg = chargeSetting.getMsg(statusNew, statusOld, pluggedNew, pluggedOld, TaskUtils.batteryInfo)
|
||||||
|
if (msg.isEmpty()) {
|
||||||
|
Log.d(TAG, "任务${task.id}:msg is empty, chargeSetting = $chargeSetting, statusNew = $statusNew, statusOld = $statusOld, pluggedNew = $pluggedNew, pluggedOld = $pluggedOld")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO:判断其他条件是否满足
|
||||||
|
|
||||||
|
//TODO: 组装消息体 && 执行具体任务
|
||||||
|
val msgInfo = MsgInfo("task", task.name, msg, Date(), task.name)
|
||||||
|
val actionData = Data.Builder()
|
||||||
|
.putLong(TaskWorker.taskId, task.id)
|
||||||
|
.putString(TaskWorker.taskActions, task.actions)
|
||||||
|
.putString(TaskWorker.msgInfo, Gson().toJson(msgInfo))
|
||||||
|
.build()
|
||||||
|
val actionRequest = OneTimeWorkRequestBuilder<ActionWorker>().setInputData(actionData).build()
|
||||||
|
WorkManager.getInstance().enqueue(actionRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result.success()
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
Log.d(TAG, "conditionType is $conditionType")
|
||||||
|
return Result.failure()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -13,7 +13,7 @@ import com.idormy.sms.forwarder.database.AppDatabase
|
|||||||
import com.idormy.sms.forwarder.entity.MsgInfo
|
import com.idormy.sms.forwarder.entity.MsgInfo
|
||||||
import com.idormy.sms.forwarder.entity.task.CronSetting
|
import com.idormy.sms.forwarder.entity.task.CronSetting
|
||||||
import com.idormy.sms.forwarder.entity.task.TaskSetting
|
import com.idormy.sms.forwarder.entity.task.TaskSetting
|
||||||
import com.idormy.sms.forwarder.utils.Worker
|
import com.idormy.sms.forwarder.utils.TaskWorker
|
||||||
import com.idormy.sms.forwarder.utils.task.CronJobScheduler
|
import com.idormy.sms.forwarder.utils.task.CronJobScheduler
|
||||||
import gatewayapps.crondroid.CronExpression
|
import gatewayapps.crondroid.CronExpression
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
@ -24,7 +24,7 @@ class CronWorker(context: Context, params: WorkerParameters) : CoroutineWorker(c
|
|||||||
private val TAG: String = CronWorker::class.java.simpleName
|
private val TAG: String = CronWorker::class.java.simpleName
|
||||||
|
|
||||||
override suspend fun doWork(): Result {
|
override suspend fun doWork(): Result {
|
||||||
val taskId = inputData.getLong("taskId", -1L)
|
val taskId = inputData.getLong(TaskWorker.taskId, -1L)
|
||||||
if (taskId == -1L) {
|
if (taskId == -1L) {
|
||||||
Log.d(TAG, "taskId is -1L")
|
Log.d(TAG, "taskId is -1L")
|
||||||
return Result.failure()
|
return Result.failure()
|
||||||
@ -82,25 +82,15 @@ class CronWorker(context: Context, params: WorkerParameters) : CoroutineWorker(c
|
|||||||
return Result.success()
|
return Result.success()
|
||||||
}
|
}
|
||||||
|
|
||||||
//组装消息体
|
//TODO: 组装消息体 && 执行具体任务
|
||||||
val msgInfo = MsgInfo("task", task.name, task.description, Date(), task.name)
|
val msgInfo = MsgInfo("task", task.name, task.description, Date(), task.name)
|
||||||
|
val actionData = Data.Builder()
|
||||||
// TODO: 执行具体任务
|
.putLong(TaskWorker.taskId, task.id)
|
||||||
val actionList = Gson().fromJson(task.actions, Array<TaskSetting>::class.java).toMutableList()
|
.putString(TaskWorker.taskActions, task.actions)
|
||||||
if (actionList.isEmpty()) {
|
.putString(TaskWorker.msgInfo, Gson().toJson(msgInfo))
|
||||||
Log.d(TAG, "任务${task.id}:actionsList is empty")
|
.build()
|
||||||
return Result.failure()
|
val actionRequest = OneTimeWorkRequestBuilder<ActionWorker>().setInputData(actionData).build()
|
||||||
}
|
WorkManager.getInstance().enqueue(actionRequest)
|
||||||
for (action in actionList) {
|
|
||||||
val actionData = Data.Builder()
|
|
||||||
.putLong(Worker.taskId, task.id)
|
|
||||||
.putInt(Worker.actionType, action.type)
|
|
||||||
.putString(Worker.actionSetting, action.setting)
|
|
||||||
.putString(Worker.sendMsgInfo, Gson().toJson(msgInfo))
|
|
||||||
.build()
|
|
||||||
val actionRequest = OneTimeWorkRequestBuilder<ActionWorker>().setInputData(actionData).build()
|
|
||||||
WorkManager.getInstance().enqueue(actionRequest)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 为新的 nextExecTime 调度下一次任务执行
|
// 为新的 nextExecTime 调度下一次任务执行
|
||||||
CronJobScheduler.cancelTask(task.id)
|
CronJobScheduler.cancelTask(task.id)
|
||||||
|
@ -758,206 +758,6 @@
|
|||||||
|
|
||||||
</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/battery_monitor"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="10dp"
|
|
||||||
android:text="@string/battery_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/monitor_battery_status_changes"
|
|
||||||
android:textStyle="bold"
|
|
||||||
tools:ignore="RelativeOverlap" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/battery_status_changes_tips"
|
|
||||||
android:textSize="9sp"
|
|
||||||
tools:ignore="SmallSp" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<com.xuexiang.xui.widget.button.switchbutton.SwitchButton
|
|
||||||
android:id="@+id/sb_battery_receiver"
|
|
||||||
style="@style/SwitchButtonStyle"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
style="@style/settingBarStyle"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingEnd="10dp"
|
|
||||||
tools:ignore="RtlSymmetry">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/low_power_alarm_threshold"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/low_power_alarm_threshold_tips"
|
|
||||||
android:textSize="9sp"
|
|
||||||
tools:ignore="SmallSp" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<com.xuexiang.xui.widget.picker.XRangeSlider
|
|
||||||
android:id="@+id/xrs_battery_level_alarm"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="5dp"
|
|
||||||
android:layout_weight="1"
|
|
||||||
app:xrs_insideRangeLineColor="#0bd97f"
|
|
||||||
app:xrs_max="100"
|
|
||||||
app:xrs_min="0"
|
|
||||||
app:xrs_verticalPadding="0dp" />
|
|
||||||
|
|
||||||
<com.xuexiang.xui.widget.button.SmoothCheckBox
|
|
||||||
android:id="@+id/scb_battery_level_alarm_once"
|
|
||||||
android:layout_width="15dp"
|
|
||||||
android:layout_height="15dp"
|
|
||||||
android:layout_marginStart="5dp"
|
|
||||||
app:scb_color_checked="@color/colorPrimary" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/keep_reminding"
|
|
||||||
android:textSize="10sp"
|
|
||||||
tools:ignore="SmallSp" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
style="@style/settingBarStyle"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:visibility="gone">
|
|
||||||
|
|
||||||
<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/timing_report_battery_status"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/timing_report_battery_status_tips"
|
|
||||||
android:textSize="9sp"
|
|
||||||
tools:ignore="SmallSp" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/layout_battery_cron"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:visibility="gone">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/first_send_time"
|
|
||||||
android:textSize="12sp"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/et_battery_cron_start_time"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:autofillHints=""
|
|
||||||
android:ems="5"
|
|
||||||
android:focusable="false"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:text=""
|
|
||||||
android:textAlignment="center"
|
|
||||||
android:textSize="12sp"
|
|
||||||
tools:ignore="LabelFor,TextFields" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="10dp"
|
|
||||||
android:text="@string/interval_minutes"
|
|
||||||
android:textSize="12sp"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/et_battery_cron_interval"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:autofillHints=""
|
|
||||||
android:digits="0123456789"
|
|
||||||
android:ems="4"
|
|
||||||
android:inputType="number"
|
|
||||||
android:maxLength="4"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:text=""
|
|
||||||
android:textAlignment="center"
|
|
||||||
android:textSize="12sp"
|
|
||||||
tools:ignore="LabelFor" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<com.xuexiang.xui.widget.button.switchbutton.SwitchButton
|
|
||||||
android:id="@+id/sb_battery_cron"
|
|
||||||
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"
|
||||||
|
@ -44,14 +44,14 @@
|
|||||||
android:paddingBottom="@dimen/config_padding_5dp">
|
android:paddingBottom="@dimen/config_padding_5dp">
|
||||||
|
|
||||||
<RadioButton
|
<RadioButton
|
||||||
android:id="@+id/rb_battery_discharging"
|
android:id="@+id/rb_battery_charging"
|
||||||
style="@style/rg_rb_style_match"
|
style="@style/rg_rb_style_match"
|
||||||
android:checked="true"
|
android:checked="true"
|
||||||
android:text="@string/battery_charging"
|
android:text="@string/battery_charging"
|
||||||
tools:ignore="TouchTargetSizeCheck" />
|
tools:ignore="TouchTargetSizeCheck" />
|
||||||
|
|
||||||
<RadioButton
|
<RadioButton
|
||||||
android:id="@+id/rb_battery_charging"
|
android:id="@+id/rb_battery_discharging"
|
||||||
style="@style/rg_rb_style_match"
|
style="@style/rg_rb_style_match"
|
||||||
android:text="@string/battery_discharging"
|
android:text="@string/battery_discharging"
|
||||||
tools:ignore="TouchTargetSizeCheck" />
|
tools:ignore="TouchTargetSizeCheck" />
|
||||||
|
@ -353,8 +353,6 @@
|
|||||||
<string name="carrier_mobile" tools:ignore="Typos">Label of SIM,\neg. AT&T_88888888</string>
|
<string name="carrier_mobile" tools:ignore="Typos">Label of SIM,\neg. AT&T_88888888</string>
|
||||||
<string name="tip_number_only_error_message">Number must be greater than 0!</string>
|
<string name="tip_number_only_error_message">Number must be greater than 0!</string>
|
||||||
<string name="regexp_number_only" tools:ignore="TypographyDashes,Typos">^[1-9]?\\d+$</string>
|
<string name="regexp_number_only" tools:ignore="TypographyDashes,Typos">^[1-9]?\\d+$</string>
|
||||||
<string name="low_power_alarm_threshold">Low Power Alarm</string>
|
|
||||||
<string name="low_power_alarm_threshold_tips">Value range: 0–99.\nLeft blank or 0 is disabled</string>
|
|
||||||
<string name="retry_interval">Retry Interval</string>
|
<string name="retry_interval">Retry Interval</string>
|
||||||
<string name="retry_interval_tips">Disabled when times = 0,\nthe interval is incremented</string>
|
<string name="retry_interval_tips">Disabled when times = 0,\nthe interval is incremented</string>
|
||||||
<string name="filtering_duplicate_messages">Filter Duplicate Messages</string>
|
<string name="filtering_duplicate_messages">Filter Duplicate Messages</string>
|
||||||
@ -476,10 +474,6 @@
|
|||||||
<string name="percent">%</string>
|
<string name="percent">%</string>
|
||||||
<string name="above"><![CDATA[≥]]></string>
|
<string name="above"><![CDATA[≥]]></string>
|
||||||
<string name="zero">0</string>
|
<string name="zero">0</string>
|
||||||
<string name="monitor_battery_status_changes">Monitor Battery Status Changes</string>
|
|
||||||
<string name="battery_status_changes_tips">Notify when charge status changes (charging/discharging/uncharged/full)</string>
|
|
||||||
<string name="timing_report_battery_status">Push Battery Status Regularly</string>
|
|
||||||
<string name="timing_report_battery_status_tips">Please set the daily first sending time and re-sending interval</string>
|
|
||||||
<string name="first_send_time">First time: </string>
|
<string name="first_send_time">First time: </string>
|
||||||
<string name="interval_minutes">Interval(minutes): </string>
|
<string name="interval_minutes">Interval(minutes): </string>
|
||||||
<string name="proxy_settings">Proxy Settings</string>
|
<string name="proxy_settings">Proxy Settings</string>
|
||||||
@ -566,8 +560,6 @@
|
|||||||
<string name="network_state_monitor_tips">[Note] You need to manually create APP forwarding rules, package name: 77777777</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">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="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_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>
|
||||||
<string name="keep_alive_tips">It is recommended to open the first three switch, do not disable the notification bar, to avoid APP being killed</string>
|
<string name="keep_alive_tips">It is recommended to open the first three switch, do not disable the notification bar, to avoid APP being killed</string>
|
||||||
<string name="custom_settings">Custom Settings</string>
|
<string name="custom_settings">Custom Settings</string>
|
||||||
@ -611,6 +603,10 @@
|
|||||||
<string name="tag_scheme">{{SCHEME}}</string>
|
<string name="tag_scheme">{{SCHEME}}</string>
|
||||||
<string name="tag_call_type">{{CALL_TYPE}}</string>
|
<string name="tag_call_type">{{CALL_TYPE}}</string>
|
||||||
<string name="tag_location">{{LOCATION}}</string>
|
<string name="tag_location">{{LOCATION}}</string>
|
||||||
|
<string name="tag_battery_pct">{{BATTERY_PCT}}</string>
|
||||||
|
<string name="tag_battery_status">{{BATTERY_STATUS}}</string>
|
||||||
|
<string name="tag_battery_plugged">{{BATTERY_PLUGGED}}</string>
|
||||||
|
<string name="tag_battery_info">{{BATTERY_INFO}}</string>
|
||||||
<string name="tag_uid">{{UID}}</string>
|
<string name="tag_uid">{{UID}}</string>
|
||||||
<string name="rule_sms">SMS</string>
|
<string name="rule_sms">SMS</string>
|
||||||
<string name="rule_call">CALL</string>
|
<string name="rule_call">CALL</string>
|
||||||
|
@ -354,8 +354,6 @@
|
|||||||
<string name="carrier_mobile">序号/运营商_手机号</string>
|
<string name="carrier_mobile">序号/运营商_手机号</string>
|
||||||
<string name="tip_number_only_error_message">数字必须大于0!</string>
|
<string name="tip_number_only_error_message">数字必须大于0!</string>
|
||||||
<string name="regexp_number_only" tools:ignore="TypographyDashes,Typos">^[1-9]?\\d+$</string>
|
<string name="regexp_number_only" tools:ignore="TypographyDashes,Typos">^[1-9]?\\d+$</string>
|
||||||
<string name="low_power_alarm_threshold">安全电量范围(%)</string>
|
|
||||||
<string name="low_power_alarm_threshold_tips">超出安全范围将发出预警</string>
|
|
||||||
<string name="retry_interval">请求重试机制</string>
|
<string name="retry_interval">请求重试机制</string>
|
||||||
<string name="retry_interval_tips">次数=0禁用,逐次递增</string>
|
<string name="retry_interval_tips">次数=0禁用,逐次递增</string>
|
||||||
<string name="filtering_duplicate_messages">自动过滤多久内重复消息</string>
|
<string name="filtering_duplicate_messages">自动过滤多久内重复消息</string>
|
||||||
@ -477,10 +475,6 @@
|
|||||||
<string name="percent">%</string>
|
<string name="percent">%</string>
|
||||||
<string name="above">高于</string>
|
<string name="above">高于</string>
|
||||||
<string name="zero">0</string>
|
<string name="zero">0</string>
|
||||||
<string name="monitor_battery_status_changes">监听电池状态变化</string>
|
|
||||||
<string name="battery_status_changes_tips">充电状态改变(充电中/放电中/未充电/已充满)时发出通知</string>
|
|
||||||
<string name="timing_report_battery_status">定时推送电池状态</string>
|
|
||||||
<string name="timing_report_battery_status_tips">请设置每日首次发送时间与再次发送间隔时间</string>
|
|
||||||
<string name="first_send_time">首次发送时间:</string>
|
<string name="first_send_time">首次发送时间:</string>
|
||||||
<string name="interval_minutes">间隔(分钟):</string>
|
<string name="interval_minutes">间隔(分钟):</string>
|
||||||
<string name="proxy_settings">代理设置</string>
|
<string name="proxy_settings">代理设置</string>
|
||||||
@ -567,8 +561,6 @@
|
|||||||
<string name="network_state_monitor_tips">需要手动创建APP转发规则,包名:77777777</string>
|
<string name="network_state_monitor_tips">需要手动创建APP转发规则,包名:77777777</string>
|
||||||
<string name="network_state_change_remind">网络状态改变提醒</string>
|
<string name="network_state_change_remind">网络状态改变提醒</string>
|
||||||
<string name="network_state_change_remind_tips">网络状态改变(连接方式/IP变化)时发出通知</string>
|
<string name="network_state_change_remind_tips">网络状态改变(连接方式/IP变化)时发出通知</string>
|
||||||
<string name="battery_monitor">电池监控</string>
|
|
||||||
<string name="battery_monitor_tips">需要手动创建APP转发规则,包名:88888888</string>
|
|
||||||
<string name="keep_alive">保活措施</string>
|
<string name="keep_alive">保活措施</string>
|
||||||
<string name="keep_alive_tips">建议开启前三项授权或设置,不要禁用通知栏,避免APP被杀</string>
|
<string name="keep_alive_tips">建议开启前三项授权或设置,不要禁用通知栏,避免APP被杀</string>
|
||||||
<string name="custom_settings">个性设置</string>
|
<string name="custom_settings">个性设置</string>
|
||||||
@ -612,6 +604,10 @@
|
|||||||
<string name="tag_scheme">{{通知Scheme}}</string>
|
<string name="tag_scheme">{{通知Scheme}}</string>
|
||||||
<string name="tag_call_type">{{通话类型}}</string>
|
<string name="tag_call_type">{{通话类型}}</string>
|
||||||
<string name="tag_location">{{定位信息}}</string>
|
<string name="tag_location">{{定位信息}}</string>
|
||||||
|
<string name="tag_battery_pct">{{电池电量}}</string>
|
||||||
|
<string name="tag_battery_status">{{电池状态}}</string>
|
||||||
|
<string name="tag_battery_plugged">{{充电方式}}</string>
|
||||||
|
<string name="tag_battery_info">{{电池信息}}</string>
|
||||||
<string name="tag_uid">{{UID}}</string>
|
<string name="tag_uid">{{UID}}</string>
|
||||||
<string name="rule_sms">短信</string>
|
<string name="rule_sms">短信</string>
|
||||||
<string name="rule_call">来电</string>
|
<string name="rule_call">来电</string>
|
||||||
@ -974,8 +970,8 @@
|
|||||||
<string name="battery_status_monitor">电池状态监听</string>
|
<string name="battery_status_monitor">电池状态监听</string>
|
||||||
<string name="below_level_min">【电量预警】已低于电量预警下限,请及时充电!%s</string>
|
<string name="below_level_min">【电量预警】已低于电量预警下限,请及时充电!%s</string>
|
||||||
<string name="over_level_max">【电量预警】已高于电量预警上限,请拔掉充电器!%s</string>
|
<string name="over_level_max">【电量预警】已高于电量预警上限,请拔掉充电器!%s</string>
|
||||||
<string name="reach_level_min">【电量预警】已低于电量预警下限,请及时充电!%s</string>
|
<string name="reach_level_min">【电量预警】已达到电量预警下限,请及时充电!%s</string>
|
||||||
<string name="reach_level_max">【电量预警】已高于电量预警上限,请拔掉充电器!%s</string>
|
<string name="reach_level_max">【电量预警】已达到电量预警上限,请拔掉充电器!%s</string>
|
||||||
<string name="battery_status_changed">【充电状态】发生变化:</string>
|
<string name="battery_status_changed">【充电状态】发生变化:</string>
|
||||||
<string name="no_indentation_allowed_on_the_first_line">第一行不允许缩进</string>
|
<string name="no_indentation_allowed_on_the_first_line">第一行不允许缩进</string>
|
||||||
<string name="sign_required">服务端启用签名密钥,sign节点必传</string>
|
<string name="sign_required">服务端启用签名密钥,sign节点必传</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user