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:defaultToDeviceProtectedStorage="true"
|
||||
android:directBootAware="true"
|
||||
android:enableOnBackInvokedCallback="false"
|
||||
android:fullBackupContent="@xml/backup_descriptor"
|
||||
android:hardwareAccelerated="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
@ -222,19 +223,13 @@
|
||||
android:value="640" />
|
||||
|
||||
<service
|
||||
android:name=".service.HttpService"
|
||||
android:enabled="true" />
|
||||
<service
|
||||
android:name=".service.NetworkStateService"
|
||||
android:enabled="true" />
|
||||
<service
|
||||
android:name=".service.BatteryService"
|
||||
android:name=".service.HttpServerService"
|
||||
android:enabled="true" />
|
||||
<service
|
||||
android:name=".service.ForegroundService"
|
||||
android:enabled="true" />
|
||||
<service
|
||||
android:name=".service.NotifyService"
|
||||
android:name=".service.NotificationService"
|
||||
android:enabled="true"
|
||||
android:exported="false"
|
||||
android:label="@string/app_name"
|
||||
@ -248,9 +243,15 @@
|
||||
android:exported="false"
|
||||
android:permission="android.permission.BIND_JOB_SERVICE" />
|
||||
|
||||
|
||||
<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:directBootAware="true"
|
||||
android:exported="true"
|
||||
@ -299,7 +300,7 @@
|
||||
<action android:name="android.intent.action.SIM_STATE_CHANGED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver android:name=".receiver.AlarmReceiver" />
|
||||
|
||||
</application>
|
||||
|
||||
</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.repository.*
|
||||
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.service.BatteryService
|
||||
import com.idormy.sms.forwarder.service.ForegroundService
|
||||
import com.idormy.sms.forwarder.service.HttpService
|
||||
import com.idormy.sms.forwarder.service.NetworkStateService
|
||||
import com.idormy.sms.forwarder.service.HttpServerService
|
||||
import com.idormy.sms.forwarder.utils.*
|
||||
import com.idormy.sms.forwarder.utils.sdkinit.UMengInit
|
||||
import com.idormy.sms.forwarder.utils.sdkinit.XBasicLibInit
|
||||
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 io.reactivex.Observable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
@ -121,23 +119,18 @@ class App : Application(), CactusCallback, Configuration.Provider by Core {
|
||||
startService(serviceIntent)
|
||||
}
|
||||
|
||||
//网络状态监听
|
||||
Intent(this, NetworkStateService::class.java).also {
|
||||
startService(it)
|
||||
}
|
||||
|
||||
//电池状态监听
|
||||
Intent(this, BatteryService::class.java).also {
|
||||
startService(it)
|
||||
}
|
||||
|
||||
//启动HttpServer
|
||||
if (HttpServerUtils.enableServerAutorun) {
|
||||
Intent(this, HttpService::class.java).also {
|
||||
Intent(this, HttpServerService::class.java).also {
|
||||
startService(it)
|
||||
}
|
||||
}
|
||||
|
||||
//监听电量&充电状态变化
|
||||
val batteryReceiver = BatteryReceiver()
|
||||
val filter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
|
||||
registerReceiver(batteryReceiver, filter)
|
||||
|
||||
//Cactus 集成双进程前台服务,JobScheduler,onePix(一像素),WorkManager,无声音乐
|
||||
if (SettingUtils.enableCactus) {
|
||||
//注册广播监听器
|
||||
@ -207,10 +200,6 @@ class App : Application(), CactusCallback, Configuration.Provider by Core {
|
||||
XUpdateInit.init(this)
|
||||
// 运营统计数据
|
||||
UMengInit.init(this)
|
||||
// 定时任务初始化
|
||||
AlarmUtils.initialize(this)
|
||||
// 三方时间库初始化
|
||||
//AndroidThreeTen.init(this)
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
|
@ -37,7 +37,7 @@ interface TaskDao {
|
||||
@RawQuery(observedEntities = [Task::class])
|
||||
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>
|
||||
|
||||
//TODO:根据条件查询,不推荐使用
|
||||
|
@ -4,6 +4,7 @@ import com.idormy.sms.forwarder.R
|
||||
import com.xuexiang.xui.utils.ResUtils
|
||||
import java.io.Serializable
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
data class BatteryInfo(
|
||||
var level: String = "",
|
||||
var scale: String = "",
|
||||
|
@ -5,12 +5,14 @@ import android.text.TextUtils
|
||||
import android.util.Log
|
||||
import com.idormy.sms.forwarder.App
|
||||
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.HttpServerUtils
|
||||
import com.idormy.sms.forwarder.utils.SettingUtils
|
||||
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.smsTemplate
|
||||
import com.idormy.sms.forwarder.utils.task.TaskUtils
|
||||
import com.xuexiang.xui.utils.ResUtils.getString
|
||||
import com.xuexiang.xutil.app.AppUtils
|
||||
import java.io.Serializable
|
||||
@ -109,6 +111,10 @@ data class MsgInfo(
|
||||
.replace(getString(R.string.tag_device_name), deviceMark)
|
||||
.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_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()
|
||||
return replaceLocationTag(replaceAppName(regexReplace(smsVoForSend, regexReplace), from))
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package com.idormy.sms.forwarder.entity.task
|
||||
|
||||
import android.os.BatteryManager
|
||||
import com.idormy.sms.forwarder.R
|
||||
import com.xuexiang.xutil.resource.ResUtils.getString
|
||||
import java.io.Serializable
|
||||
|
||||
data class BatterySetting(
|
||||
@ -19,4 +20,30 @@ data class BatterySetting(
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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.databinding.FragmentServerBinding
|
||||
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.xuexiang.xaop.annotation.SingleClick
|
||||
import com.xuexiang.xpage.annotation.Page
|
||||
@ -241,9 +241,9 @@ class ServerFragment : BaseFragment<FragmentServerBinding?>(), View.OnClickListe
|
||||
binding!!.sbApiLocation.isChecked = HttpServerUtils.enableApiLocation
|
||||
binding!!.sbApiLocation.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
|
||||
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: 重启服务")
|
||||
Intent(appContext, HttpService::class.java).also {
|
||||
Intent(appContext, HttpServerService::class.java).also {
|
||||
appContext?.stopService(it)
|
||||
Thread.sleep(500)
|
||||
appContext?.startService(it)
|
||||
@ -272,8 +272,8 @@ class ServerFragment : BaseFragment<FragmentServerBinding?>(), View.OnClickListe
|
||||
checkCallPermission()
|
||||
checkContactsPermission()
|
||||
checkLocationPermission()
|
||||
Intent(appContext, HttpService::class.java).also {
|
||||
if (ServiceUtils.isServiceRunning("com.idormy.sms.forwarder.service.HttpService")) {
|
||||
Intent(appContext, HttpServerService::class.java).also {
|
||||
if (ServiceUtils.isServiceRunning("com.idormy.sms.forwarder.service.HttpServerService")) {
|
||||
appContext?.stopService(it)
|
||||
} else {
|
||||
appContext?.startService(it)
|
||||
@ -348,8 +348,8 @@ class ServerFragment : BaseFragment<FragmentServerBinding?>(), View.OnClickListe
|
||||
HttpServerUtils.serverWebPath = webPath
|
||||
|
||||
XToastUtils.info(getString(R.string.restarting_httpserver))
|
||||
Intent(appContext, HttpService::class.java).also {
|
||||
if (ServiceUtils.isServiceRunning("com.idormy.sms.forwarder.service.HttpService")) {
|
||||
Intent(appContext, HttpServerService::class.java).also {
|
||||
if (ServiceUtils.isServiceRunning("com.idormy.sms.forwarder.service.HttpServerService")) {
|
||||
appContext?.stopService(it)
|
||||
Thread.sleep(500)
|
||||
appContext?.startService(it)
|
||||
@ -381,7 +381,7 @@ class ServerFragment : BaseFragment<FragmentServerBinding?>(), View.OnClickListe
|
||||
|
||||
//刷新按钮
|
||||
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!!.ivCopy.visibility = View.VISIBLE
|
||||
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.databinding.FragmentSettingsBinding
|
||||
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.utils.*
|
||||
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.dialog.materialdialog.DialogAction
|
||||
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.widget.builder.OptionsPickerBuilder
|
||||
import com.xuexiang.xui.widget.picker.widget.builder.TimePickerBuilder
|
||||
import com.xuexiang.xui.widget.picker.widget.listener.OnOptionsSelectListener
|
||||
import com.xuexiang.xutil.XUtil
|
||||
import com.xuexiang.xutil.XUtil.getPackageManager
|
||||
import com.xuexiang.xutil.app.AppUtils.getAppPackageName
|
||||
import com.xuexiang.xutil.data.DateUtils
|
||||
import kotlinx.coroutines.*
|
||||
import java.util.*
|
||||
|
||||
@ -125,15 +121,6 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
||||
//监听网络状态变化
|
||||
switchNetworkStateReceiver(binding!!.sbNetworkStateReceiver)
|
||||
|
||||
//监听电池状态变化
|
||||
switchBatteryReceiver(binding!!.sbBatteryReceiver)
|
||||
//电量预警
|
||||
editBatteryLevelAlarm(binding!!.xrsBatteryLevelAlarm, binding!!.scbBatteryLevelAlarmOnce)
|
||||
//定时推送电池状态
|
||||
switchBatteryCron(binding!!.sbBatteryCron)
|
||||
//设置推送电池状态时机
|
||||
editBatteryCronTiming(binding!!.etBatteryCronStartTime, binding!!.etBatteryCronInterval)
|
||||
|
||||
//开机启动
|
||||
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(
|
||||
@SuppressLint("UseSwitchCompatOrMaterialCode") sbWithReboot: SwitchButton, tvAutoStartup: TextView
|
||||
@ -715,7 +623,7 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
|
||||
tvAutoStartup.text = getAutoStartTips()
|
||||
|
||||
//获取组件
|
||||
val cm = ComponentName(getAppPackageName(), BootReceiver::class.java.name)
|
||||
val cm = ComponentName(getAppPackageName(), BootCompletedReceiver::class.java.name)
|
||||
val pm: PackageManager = getPackageManager()
|
||||
val state = pm.getComponentEnabledSetting(cm)
|
||||
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 -> {
|
||||
//取消旧任务的定时器 & 设置新的定时器
|
||||
//AlarmUtils.cancelAlarm(task)
|
||||
//AlarmUtils.scheduleAlarm(task)
|
||||
|
||||
CronJobScheduler.cancelTask(task.id)
|
||||
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")
|
||||
class SimStateReceiver : BroadcastReceiver() {
|
||||
|
||||
private var TAG = "SimStateReceiver"
|
||||
private var TAG = SimStateReceiver::class.java.simpleName
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
//纯客户端模式
|
||||
|
@ -23,7 +23,7 @@ import java.util.Date
|
||||
@Suppress("PrivatePropertyName")
|
||||
class SmsReceiver : BroadcastReceiver() {
|
||||
|
||||
private var TAG = "SmsReceiver"
|
||||
private var TAG = SmsReceiver::class.java.simpleName
|
||||
private var from = ""
|
||||
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")
|
||||
class ForegroundService : Service() {
|
||||
|
||||
private val TAG: String = "ForegroundService"
|
||||
private val TAG: String = ForegroundService::class.java.simpleName
|
||||
private var notificationManager: NotificationManager? = null
|
||||
|
||||
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.yanzhenjie.andserver.AndServer
|
||||
import com.yanzhenjie.andserver.Server
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@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 {
|
||||
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")
|
||||
class NotifyService : NotificationListenerService() {
|
||||
class NotificationService : NotificationListenerService() {
|
||||
|
||||
private val TAG: String = "NotifyService"
|
||||
private val TAG: String = NotificationService::class.java.simpleName
|
||||
|
||||
override fun onListenerConnected() {
|
||||
Log.d(TAG, "onListenerConnected")
|
@ -7,6 +7,7 @@ import com.idormy.sms.forwarder.R
|
||||
import com.idormy.sms.forwarder.entity.BatteryInfo
|
||||
import com.xuexiang.xui.utils.ResUtils.getString
|
||||
|
||||
@Suppress("DEPRECATION", "MemberVisibilityCanBePrivate")
|
||||
object BatteryUtils {
|
||||
private const val TAG = "BatteryUtils"
|
||||
|
||||
@ -27,22 +28,8 @@ object BatteryUtils {
|
||||
if (voltage > 0) batteryInfo.voltage = "${String.format("%.2f", voltage / 1000f)}V"
|
||||
if (temperature > 0) batteryInfo.temperature = "${String.format("%.2f", temperature / 10f)}℃"
|
||||
batteryInfo.status = getStatus(status)
|
||||
batteryInfo.health = 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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
batteryInfo.health = getHealth(health)
|
||||
batteryInfo.plugged = getPlugged(plugged)
|
||||
Log.i(TAG, batteryInfo.toString())
|
||||
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.fragment.MarkdownFragment
|
||||
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.core.PageOption
|
||||
import com.xuexiang.xui.utils.ColorUtils
|
||||
@ -273,10 +273,10 @@ class CommonUtils private constructor() {
|
||||
fun toggleNotificationListenerService(context: Context) {
|
||||
val pm = context.packageManager
|
||||
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(
|
||||
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 senderIndex = "sender_index"
|
||||
const val msgId = "msg_id"
|
||||
}
|
||||
|
||||
object TaskWorker {
|
||||
const val taskId = "task_id"
|
||||
const val actionType = "action_type"
|
||||
const val actionSetting = "action_setting"
|
||||
const val task = "task"
|
||||
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_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_PLAY_SILENCE_MUSIC = "enable_play_silence_music"
|
||||
const val SP_ENABLE_ONE_PIXEL_ACTIVITY = "enable_one_pixel_activity"
|
||||
@ -582,3 +576,8 @@ var TASK_ACTION_FRAGMENT_LIST = listOf(
|
||||
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 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)
|
||||
|
||||
|
@ -9,12 +9,10 @@ import android.util.Log
|
||||
import androidx.core.app.ActivityCompat
|
||||
import com.google.gson.Gson
|
||||
import com.idormy.sms.forwarder.App
|
||||
import com.idormy.sms.forwarder.R
|
||||
import com.idormy.sms.forwarder.database.AppDatabase
|
||||
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.xui.utils.ResUtils
|
||||
import com.xuexiang.xutil.XUtil
|
||||
import com.xuexiang.xutil.file.FileUtils
|
||||
import com.xuexiang.xutil.system.DeviceUtils
|
||||
@ -101,7 +99,7 @@ class SmsCommandUtils {
|
||||
}
|
||||
|
||||
"httpserver" -> {
|
||||
Intent(context, HttpService::class.java).also {
|
||||
Intent(context, HttpServerService::class.java).also {
|
||||
if (action == "start") {
|
||||
context.startService(it)
|
||||
} 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.WorkManager
|
||||
import com.idormy.sms.forwarder.database.entity.Task
|
||||
import com.idormy.sms.forwarder.utils.TaskWorker
|
||||
import com.idormy.sms.forwarder.workers.CronWorker
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@ -19,7 +20,7 @@ class CronJobScheduler {
|
||||
fun scheduleTask(task: Task) {
|
||||
val currentTimeMillis = System.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) {
|
||||
Log.d(TAG, "任务${task.id}:立即执行,delayInMillis = $delayInMillis")
|
||||
OneTimeWorkRequestBuilder<CronWorker>()
|
||||
|
@ -1,6 +1,10 @@
|
||||
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
|
||||
|
||||
/**
|
||||
@ -10,7 +14,19 @@ class TaskUtils private constructor() {
|
||||
|
||||
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,37 +13,51 @@ import com.idormy.sms.forwarder.R
|
||||
import com.idormy.sms.forwarder.database.entity.Rule
|
||||
import com.idormy.sms.forwarder.entity.MsgInfo
|
||||
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.SendUtils
|
||||
import com.idormy.sms.forwarder.utils.TASK_ACTION_NOTIFICATION
|
||||
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.xutil.XUtil
|
||||
|
||||
//执行每个task具体动作任务
|
||||
@Suppress("PrivatePropertyName", "DEPRECATION")
|
||||
class ActionWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
|
||||
|
||||
private val TAG: String = ActionWorker::class.java.simpleName
|
||||
|
||||
override suspend fun doWork(): Result {
|
||||
val taskId = inputData.getLong(Worker.taskId, -1L)
|
||||
val actionType = inputData.getInt(Worker.actionType, -1)
|
||||
val actionSetting = inputData.getString(Worker.actionSetting)
|
||||
val msgInfoJson = inputData.getString(Worker.sendMsgInfo)
|
||||
Log.d(TAG, "taskId: $taskId, actionType: $actionType, actionSetting: $actionSetting, msgInfoJson: $msgInfoJson")
|
||||
if (taskId == -1L || actionSetting == null) {
|
||||
val taskId = inputData.getLong(TaskWorker.taskId, -1L)
|
||||
val taskActionsJson = inputData.getString(TaskWorker.taskActions)
|
||||
val msgInfoJson = inputData.getString(TaskWorker.msgInfo)
|
||||
Log.d(TAG, "taskId: $taskId, taskActionsJson: $taskActionsJson, msgInfoJson: $msgInfoJson")
|
||||
if (taskId == -1L || taskActionsJson.isNullOrEmpty() || msgInfoJson.isNullOrEmpty()) {
|
||||
Log.d(TAG, "taskId is -1L or actionSetting is null")
|
||||
return Result.failure()
|
||||
}
|
||||
val msgInfo = Gson().fromJson(msgInfoJson, MsgInfo::class.java)
|
||||
|
||||
when (actionType) {
|
||||
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)
|
||||
if (msgInfo == null) {
|
||||
Log.d(TAG, "任务$taskId:msgInfo is null")
|
||||
return Result.failure()
|
||||
}
|
||||
|
||||
var successNum = 0
|
||||
for (action in actionList) {
|
||||
when (action.type) {
|
||||
TASK_ACTION_SENDSMS -> {
|
||||
val smsSetting = Gson().fromJson(actionSetting, SmsSetting::class.java)
|
||||
val smsSetting = Gson().fromJson(action.setting, SmsSetting::class.java)
|
||||
if (smsSetting == null) {
|
||||
Log.d(TAG, "任务$taskId:smsSetting is null")
|
||||
return Result.failure()
|
||||
continue
|
||||
}
|
||||
//获取卡槽信息
|
||||
if (App.SimInfoList.isEmpty()) {
|
||||
@ -59,30 +73,34 @@ class ActionWorker(context: Context, params: WorkerParameters) : CoroutineWorker
|
||||
val msg = if (ActivityCompat.checkSelfPermission(XUtil.getContext(), Manifest.permission.SEND_SMS) != PackageManager.PERMISSION_GRANTED) {
|
||||
ResUtils.getString(R.string.no_sms_sending_permission)
|
||||
} 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")
|
||||
return Result.success()
|
||||
continue
|
||||
}
|
||||
|
||||
TASK_ACTION_NOTIFICATION -> {
|
||||
return try {
|
||||
val settingVo = Gson().fromJson(actionSetting, Rule::class.java)
|
||||
try {
|
||||
val settingVo = Gson().fromJson(action.setting, Rule::class.java)
|
||||
//自动任务的不需要吐司或者更新日志,特殊处理 logId = -1,msgId = -1
|
||||
SendUtils.sendMsgSender(msgInfo, settingVo, 0, -1L, -1L)
|
||||
Result.success()
|
||||
successNum++
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
Result.failure()
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
else -> {
|
||||
Log.d(TAG, "任务$taskId:action.type is $actionType")
|
||||
return Result.failure()
|
||||
Log.d(TAG, "任务$taskId:action.type is ${action.type}")
|
||||
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.task.CronSetting
|
||||
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 gatewayapps.crondroid.CronExpression
|
||||
import java.util.Date
|
||||
@ -24,7 +24,7 @@ class CronWorker(context: Context, params: WorkerParameters) : CoroutineWorker(c
|
||||
private val TAG: String = CronWorker::class.java.simpleName
|
||||
|
||||
override suspend fun doWork(): Result {
|
||||
val taskId = inputData.getLong("taskId", -1L)
|
||||
val taskId = inputData.getLong(TaskWorker.taskId, -1L)
|
||||
if (taskId == -1L) {
|
||||
Log.d(TAG, "taskId is -1L")
|
||||
return Result.failure()
|
||||
@ -82,25 +82,15 @@ class CronWorker(context: Context, params: WorkerParameters) : CoroutineWorker(c
|
||||
return Result.success()
|
||||
}
|
||||
|
||||
//组装消息体
|
||||
//TODO: 组装消息体 && 执行具体任务
|
||||
val msgInfo = MsgInfo("task", task.name, task.description, Date(), task.name)
|
||||
|
||||
// TODO: 执行具体任务
|
||||
val actionList = Gson().fromJson(task.actions, Array<TaskSetting>::class.java).toMutableList()
|
||||
if (actionList.isEmpty()) {
|
||||
Log.d(TAG, "任务${task.id}:actionsList is empty")
|
||||
return Result.failure()
|
||||
}
|
||||
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))
|
||||
.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)
|
||||
}
|
||||
|
||||
// 为新的 nextExecTime 调度下一次任务执行
|
||||
CronJobScheduler.cancelTask(task.id)
|
||||
|
@ -758,206 +758,6 @@
|
||||
|
||||
</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
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -44,14 +44,14 @@
|
||||
android:paddingBottom="@dimen/config_padding_5dp">
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rb_battery_discharging"
|
||||
android:id="@+id/rb_battery_charging"
|
||||
style="@style/rg_rb_style_match"
|
||||
android:checked="true"
|
||||
android:text="@string/battery_charging"
|
||||
tools:ignore="TouchTargetSizeCheck" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/rb_battery_charging"
|
||||
android:id="@+id/rb_battery_discharging"
|
||||
style="@style/rg_rb_style_match"
|
||||
android:text="@string/battery_discharging"
|
||||
tools:ignore="TouchTargetSizeCheck" />
|
||||
|
@ -353,8 +353,6 @@
|
||||
<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="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_tips">Disabled when times = 0,\nthe interval is incremented</string>
|
||||
<string name="filtering_duplicate_messages">Filter Duplicate Messages</string>
|
||||
@ -476,10 +474,6 @@
|
||||
<string name="percent">%</string>
|
||||
<string name="above"><![CDATA[≥]]></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="interval_minutes">Interval(minutes): </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_change_remind">Network State Change Remind</string>
|
||||
<string name="network_state_change_remind_tips">Send a notification when the network status changes (connection mode/IP change)</string>
|
||||
<string name="battery_monitor">Battery Monitor</string>
|
||||
<string name="battery_monitor_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_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>
|
||||
@ -611,6 +603,10 @@
|
||||
<string name="tag_scheme">{{SCHEME}}</string>
|
||||
<string name="tag_call_type">{{CALL_TYPE}}</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="rule_sms">SMS</string>
|
||||
<string name="rule_call">CALL</string>
|
||||
|
@ -354,8 +354,6 @@
|
||||
<string name="carrier_mobile">序号/运营商_手机号</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="low_power_alarm_threshold">安全电量范围(%)</string>
|
||||
<string name="low_power_alarm_threshold_tips">超出安全范围将发出预警</string>
|
||||
<string name="retry_interval">请求重试机制</string>
|
||||
<string name="retry_interval_tips">次数=0禁用,逐次递增</string>
|
||||
<string name="filtering_duplicate_messages">自动过滤多久内重复消息</string>
|
||||
@ -477,10 +475,6 @@
|
||||
<string name="percent">%</string>
|
||||
<string name="above">高于</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="interval_minutes">间隔(分钟):</string>
|
||||
<string name="proxy_settings">代理设置</string>
|
||||
@ -567,8 +561,6 @@
|
||||
<string name="network_state_monitor_tips">需要手动创建APP转发规则,包名:77777777</string>
|
||||
<string name="network_state_change_remind">网络状态改变提醒</string>
|
||||
<string name="network_state_change_remind_tips">网络状态改变(连接方式/IP变化)时发出通知</string>
|
||||
<string name="battery_monitor">电池监控</string>
|
||||
<string name="battery_monitor_tips">需要手动创建APP转发规则,包名:88888888</string>
|
||||
<string name="keep_alive">保活措施</string>
|
||||
<string name="keep_alive_tips">建议开启前三项授权或设置,不要禁用通知栏,避免APP被杀</string>
|
||||
<string name="custom_settings">个性设置</string>
|
||||
@ -612,6 +604,10 @@
|
||||
<string name="tag_scheme">{{通知Scheme}}</string>
|
||||
<string name="tag_call_type">{{通话类型}}</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="rule_sms">短信</string>
|
||||
<string name="rule_call">来电</string>
|
||||
@ -974,8 +970,8 @@
|
||||
<string name="battery_status_monitor">电池状态监听</string>
|
||||
<string name="below_level_min">【电量预警】已低于电量预警下限,请及时充电!%s</string>
|
||||
<string name="over_level_max">【电量预警】已高于电量预警上限,请拔掉充电器!%s</string>
|
||||
<string name="reach_level_min">【电量预警】已低于电量预警下限,请及时充电!%s</string>
|
||||
<string name="reach_level_max">【电量预警】已高于电量预警上限,请拔掉充电器!%s</string>
|
||||
<string name="reach_level_min">【电量预警】已达到电量预警下限,请及时充电!%s</string>
|
||||
<string name="reach_level_max">【电量预警】已达到电量预警上限,请拔掉充电器!%s</string>
|
||||
<string name="battery_status_changed">【充电状态】发生变化:</string>
|
||||
<string name="no_indentation_allowed_on_the_first_line">第一行不允许缩进</string>
|
||||
<string name="sign_required">服务端启用签名密钥,sign节点必传</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user