新增:自动任务·快捷指令 (开发中)

pull/408/head
pppscn 7 months ago
parent 06ce0112a9
commit a6d1a13d44

@ -0,0 +1,8 @@
package com.idormy.sms.forwarder.entity.action
import java.io.Serializable
data class CleanerSetting(
var description: String = "", //描述
var days: Int = 0, //自动删除N天前的转发记录
) : Serializable

@ -1,10 +1,18 @@
package com.idormy.sms.forwarder.entity.action
import com.idormy.sms.forwarder.utils.HttpServerUtils
import java.io.Serializable
data class HttpServerSetting(
var description: String = "", //描述
var action: String = "start", //动作: start=启动, stop=停止
var startUid: String = "", //手机号码
var stopUid: String = "", //短信内容
var enableApiClone: Boolean = HttpServerUtils.enableApiClone, //是否启用一键克隆
var enableApiSmsSend: Boolean = HttpServerUtils.enableApiSmsSend, //是否启用远程发短信
var enableApiSmsQuery: Boolean = HttpServerUtils.enableApiSmsQuery, //是否启用远程查短信
var enableApiCallQuery: Boolean = HttpServerUtils.enableApiCallQuery, //是否启用远程查通话记录
var enableApiContactQuery: Boolean = HttpServerUtils.enableApiContactQuery, //是否启用远程查联系人
var enableApiContactAdd: Boolean = HttpServerUtils.enableApiContactAdd, //是否启用远程加联系人
var enableApiWol: Boolean = HttpServerUtils.enableApiWol, //是否启用远程WOL
var enableApiLocation: Boolean = HttpServerUtils.enableApiLocation, //是否启用远程找手机
var enableApiBatteryQuery: Boolean = HttpServerUtils.enableApiBatteryQuery, //是否启用远程查电量
) : Serializable

@ -166,12 +166,19 @@ class TasksEditFragment : BaseFragment<FragmentTasksEditBinding?>(), View.OnClic
R.drawable.auto_task_icon_frpc
),
PageInfo(
getString(R.string.task_server),
getString(R.string.task_http_server),
"com.idormy.sms.forwarder.fragment.action.HttpServerFragment",
"{\"\":\"\"}",
CoreAnim.slide,
R.drawable.auto_task_icon_http_server
),
PageInfo(
getString(R.string.task_cleaner),
"com.idormy.sms.forwarder.fragment.action.CleanerFragment",
"{\"\":\"\"}",
CoreAnim.slide,
R.drawable.auto_task_icon_cleaner
),
)
override fun initArgs() {

@ -0,0 +1,144 @@
package com.idormy.sms.forwarder.fragment.action
import android.annotation.SuppressLint
import android.content.Intent
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.google.gson.Gson
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.core.BaseFragment
import com.idormy.sms.forwarder.databinding.FragmentTasksActionCleanerBinding
import com.idormy.sms.forwarder.entity.action.CleanerSetting
import com.idormy.sms.forwarder.utils.KEY_BACK_DATA_ACTION
import com.idormy.sms.forwarder.utils.KEY_BACK_DESCRIPTION_ACTION
import com.idormy.sms.forwarder.utils.KEY_EVENT_DATA_ACTION
import com.idormy.sms.forwarder.utils.KEY_TEST_ACTION
import com.idormy.sms.forwarder.utils.TASK_ACTION_CLEANER
import com.idormy.sms.forwarder.utils.XToastUtils
import com.jeremyliao.liveeventbus.LiveEventBus
import com.xuexiang.xaop.annotation.SingleClick
import com.xuexiang.xpage.annotation.Page
import com.xuexiang.xrouter.annotation.AutoWired
import com.xuexiang.xrouter.launcher.XRouter
import com.xuexiang.xui.utils.CountDownButtonHelper
import com.xuexiang.xui.widget.actionbar.TitleBar
@Page(name = "Cleaner")
@Suppress("PrivatePropertyName")
class CleanerFragment : BaseFragment<FragmentTasksActionCleanerBinding?>(), View.OnClickListener {
private val TAG: String = CleanerFragment::class.java.simpleName
private var titleBar: TitleBar? = null
private var mCountDownHelper: CountDownButtonHelper? = null
@JvmField
@AutoWired(name = KEY_EVENT_DATA_ACTION)
var eventData: String? = null
override fun initArgs() {
XRouter.getInstance().inject(this)
}
override fun viewBindingInflate(
inflater: LayoutInflater,
container: ViewGroup,
): FragmentTasksActionCleanerBinding {
return FragmentTasksActionCleanerBinding.inflate(inflater, container, false)
}
override fun initTitle(): TitleBar? {
titleBar = super.initTitle()!!.setImmersive(false).setTitle(R.string.task_cleaner)
return titleBar
}
/**
* 初始化控件
*/
override fun initViews() {
//测试按钮增加倒计时,避免重复点击
mCountDownHelper = CountDownButtonHelper(binding!!.btnTest, 3)
mCountDownHelper!!.setOnCountDownListener(object : CountDownButtonHelper.OnCountDownListener {
override fun onCountDown(time: Int) {
binding!!.btnTest.text = String.format(getString(R.string.seconds_n), time)
}
override fun onFinished() {
binding!!.btnTest.text = getString(R.string.test)
}
})
var settingVo = CleanerSetting(getString(R.string.task_cleaner_tips), 0)
Log.d(TAG, "initViews eventData:$eventData")
if (eventData != null) {
settingVo = Gson().fromJson(eventData, CleanerSetting::class.java)
Log.d(TAG, "initViews settingVo:$settingVo")
}
binding!!.xsbDays.setDefaultValue(settingVo.days)
}
@SuppressLint("SetTextI18n")
override fun initListeners() {
binding!!.btnTest.setOnClickListener(this)
binding!!.btnDel.setOnClickListener(this)
binding!!.btnSave.setOnClickListener(this)
LiveEventBus.get(KEY_TEST_ACTION, String::class.java).observe(this) {
mCountDownHelper?.finish()
if (it == "success") {
XToastUtils.success("测试通过", 30000)
} else {
XToastUtils.error(it, 30000)
}
}
}
@SingleClick
override fun onClick(v: View) {
try {
when (v.id) {
R.id.btn_test -> {
mCountDownHelper?.start()
Thread {
try {
val settingVo = checkSetting()
Log.d(TAG, settingVo.toString())
LiveEventBus.get(KEY_TEST_ACTION, String::class.java).post("success")
} catch (e: Exception) {
LiveEventBus.get(KEY_TEST_ACTION, String::class.java).post(e.message.toString())
e.printStackTrace()
}
}.start()
return
}
R.id.btn_del -> {
popToBack()
return
}
R.id.btn_save -> {
val settingVo = checkSetting()
val intent = Intent()
intent.putExtra(KEY_BACK_DESCRIPTION_ACTION, settingVo.description)
intent.putExtra(KEY_BACK_DATA_ACTION, Gson().toJson(settingVo))
setFragmentResult(TASK_ACTION_CLEANER, intent)
popToBack()
return
}
}
} catch (e: Exception) {
XToastUtils.error(e.message.toString(), 30000)
e.printStackTrace()
}
}
//检查设置
@SuppressLint("SetTextI18n")
private fun checkSetting(): CleanerSetting {
val days = binding!!.xsbDays.selectedNumber
val description = "自动删除${days}天前的转发记录"
return CleanerSetting(description, days)
}
}

@ -9,9 +9,10 @@ import android.view.ViewGroup
import com.google.gson.Gson
import com.idormy.sms.forwarder.R
import com.idormy.sms.forwarder.core.BaseFragment
import com.idormy.sms.forwarder.databinding.FragmentTasksActionSendSmsBinding
import com.idormy.sms.forwarder.entity.condition.CronSetting
import com.idormy.sms.forwarder.databinding.FragmentTasksActionHttpServerBinding
import com.idormy.sms.forwarder.entity.action.HttpServerSetting
import com.idormy.sms.forwarder.utils.KEY_BACK_DATA_ACTION
import com.idormy.sms.forwarder.utils.KEY_BACK_DESCRIPTION_ACTION
import com.idormy.sms.forwarder.utils.KEY_EVENT_DATA_ACTION
import com.idormy.sms.forwarder.utils.KEY_TEST_ACTION
import com.idormy.sms.forwarder.utils.TASK_ACTION_HTTPSERVER
@ -26,7 +27,7 @@ import com.xuexiang.xui.widget.actionbar.TitleBar
@Page(name = "HttpServer")
@Suppress("PrivatePropertyName")
class HttpServerFragment : BaseFragment<FragmentTasksActionSendSmsBinding?>(), View.OnClickListener {
class HttpServerFragment : BaseFragment<FragmentTasksActionHttpServerBinding?>(), View.OnClickListener {
private val TAG: String = HttpServerFragment::class.java.simpleName
private var titleBar: TitleBar? = null
@ -36,9 +37,6 @@ class HttpServerFragment : BaseFragment<FragmentTasksActionSendSmsBinding?>(), V
@AutoWired(name = KEY_EVENT_DATA_ACTION)
var eventData: String? = null
private var expression = "* * * * * ? *"
private var description = "测试描述"
override fun initArgs() {
XRouter.getInstance().inject(this)
}
@ -46,12 +44,12 @@ class HttpServerFragment : BaseFragment<FragmentTasksActionSendSmsBinding?>(), V
override fun viewBindingInflate(
inflater: LayoutInflater,
container: ViewGroup,
): FragmentTasksActionSendSmsBinding {
return FragmentTasksActionSendSmsBinding.inflate(inflater, container, false)
): FragmentTasksActionHttpServerBinding {
return FragmentTasksActionHttpServerBinding.inflate(inflater, container, false)
}
override fun initTitle(): TitleBar? {
titleBar = super.initTitle()!!.setImmersive(false).setTitle(R.string.task_server)
titleBar = super.initTitle()!!.setImmersive(false).setTitle(R.string.task_http_server)
return titleBar
}
@ -72,10 +70,21 @@ class HttpServerFragment : BaseFragment<FragmentTasksActionSendSmsBinding?>(), V
})
Log.d(TAG, "initViews eventData:$eventData")
var settingVo = HttpServerSetting(getString(R.string.task_http_server_tips))
if (eventData != null) {
val settingVo = Gson().fromJson(eventData, CronSetting::class.java)
settingVo = Gson().fromJson(eventData, HttpServerSetting::class.java)
Log.d(TAG, "initViews settingVo:$settingVo")
}
binding!!.rgHttpServerState.check(if (settingVo.action == "start") R.id.rb_start_server else R.id.rb_stop_server)
binding!!.sbApiClone.isChecked = settingVo.enableApiClone
binding!!.sbApiQuerySms.isChecked = settingVo.enableApiSmsQuery
binding!!.sbApiSendSms.isChecked = settingVo.enableApiSmsSend
binding!!.sbApiQueryCall.isChecked = settingVo.enableApiCallQuery
binding!!.sbApiQueryContacts.isChecked = settingVo.enableApiContactQuery
binding!!.sbApiAddContacts.isChecked = settingVo.enableApiContactAdd
binding!!.sbApiWol.isChecked = settingVo.enableApiWol
binding!!.sbApiLocation.isChecked = settingVo.enableApiLocation
binding!!.sbApiQueryBattery.isChecked = settingVo.enableApiBatteryQuery
}
@SuppressLint("SetTextI18n")
@ -121,6 +130,7 @@ class HttpServerFragment : BaseFragment<FragmentTasksActionSendSmsBinding?>(), V
R.id.btn_save -> {
val settingVo = checkSetting()
val intent = Intent()
intent.putExtra(KEY_BACK_DESCRIPTION_ACTION, settingVo.description)
intent.putExtra(KEY_BACK_DATA_ACTION, Gson().toJson(settingVo))
setFragmentResult(TASK_ACTION_HTTPSERVER, intent)
popToBack()
@ -135,7 +145,52 @@ class HttpServerFragment : BaseFragment<FragmentTasksActionSendSmsBinding?>(), V
//检查设置
@SuppressLint("SetTextI18n")
private fun checkSetting(): CronSetting {
return CronSetting(description, expression)
private fun checkSetting(): HttpServerSetting {
val enableList = mutableListOf<String>()
val disableList = mutableListOf<String>()
val enableApiClone = binding!!.sbApiClone.isChecked
if (enableApiClone) enableList.add(getString(R.string.api_clone)) else disableList.add(getString(R.string.api_clone))
val enableApiSmsSend = binding!!.sbApiSendSms.isChecked
if (enableApiSmsSend) enableList.add(getString(R.string.api_sms_query)) else disableList.add(getString(R.string.api_sms_query))
val enableApiSmsQuery = binding!!.sbApiQuerySms.isChecked
if (enableApiSmsQuery) enableList.add(getString(R.string.api_sms_send)) else disableList.add(getString(R.string.api_sms_send))
val enableApiCallQuery = binding!!.sbApiQueryCall.isChecked
if (enableApiCallQuery) enableList.add(getString(R.string.api_call_query)) else disableList.add(getString(R.string.api_call_query))
val enableApiContactQuery = binding!!.sbApiQueryContacts.isChecked
if (enableApiContactQuery) enableList.add(getString(R.string.api_contact_query)) else disableList.add(getString(R.string.api_contact_query))
val enableApiContactAdd = binding!!.sbApiAddContacts.isChecked
if (enableApiContactAdd) enableList.add(getString(R.string.api_contact_add)) else disableList.add(getString(R.string.api_contact_add))
val enableApiWol = binding!!.sbApiWol.isChecked
if (enableApiWol) enableList.add(getString(R.string.api_wol)) else disableList.add(getString(R.string.api_wol))
val enableApiLocation = binding!!.sbApiLocation.isChecked
if (enableApiLocation) enableList.add(getString(R.string.api_location)) else disableList.add(getString(R.string.api_location))
val enableApiBatteryQuery = binding!!.sbApiQueryBattery.isChecked
if (enableApiBatteryQuery) enableList.add(getString(R.string.api_battery_query)) else disableList.add(getString(R.string.api_battery_query))
val description = StringBuilder()
val action = if (binding!!.rgHttpServerState.checkedRadioButtonId == R.id.rb_start_server) {
description.append(getString(R.string.start_server))
if (enableList.isNotEmpty()) {
description.append(", ").append(getString(R.string.enable_function)).append(": ").append(enableList.joinToString("/"))
}
if (disableList.isNotEmpty()) {
description.append(", ").append(getString(R.string.disable_function)).append(": ").append(disableList.joinToString("/"))
}
"start"
} else {
description.append(getString(R.string.stop_server))
"stop"
}
return HttpServerSetting(description.toString(), action, enableApiClone, enableApiSmsSend, enableApiSmsQuery, enableApiCallQuery, enableApiContactQuery, enableApiContactAdd, enableApiWol, enableApiLocation, enableApiBatteryQuery)
}
}

@ -18,6 +18,7 @@ import com.idormy.sms.forwarder.utils.SP_NETWORK_STATE
import com.idormy.sms.forwarder.utils.SP_SIM_STATE
import com.idormy.sms.forwarder.utils.SP_WIFI_SSID
import com.idormy.sms.forwarder.utils.SharedPreference
import com.idormy.sms.forwarder.utils.TASK_ACTION_CLEANER
import com.idormy.sms.forwarder.utils.TASK_ACTION_FRPC
import com.idormy.sms.forwarder.utils.TASK_ACTION_HTTPSERVER
import com.idormy.sms.forwarder.utils.TASK_ACTION_NOTIFICATION
@ -53,6 +54,7 @@ class TaskUtils private constructor() {
TASK_ACTION_NOTIFICATION -> R.drawable.auto_task_icon_sender
TASK_ACTION_FRPC -> R.drawable.auto_task_icon_frpc
TASK_ACTION_HTTPSERVER -> R.drawable.auto_task_icon_http_server
TASK_ACTION_CLEANER -> R.drawable.auto_task_icon_cleaner
else -> R.drawable.auto_task_icon_custom_time
}
}
@ -72,6 +74,7 @@ class TaskUtils private constructor() {
TASK_ACTION_NOTIFICATION -> R.drawable.auto_task_icon_sender_grey
TASK_ACTION_FRPC -> R.drawable.auto_task_icon_frpc_grey
TASK_ACTION_HTTPSERVER -> R.drawable.auto_task_icon_http_server_grey
TASK_ACTION_CLEANER -> R.drawable.auto_task_icon_cleaner_grey
else -> R.drawable.auto_task_icon_custom_time_grey
}
}

@ -11,20 +11,26 @@ import androidx.work.WorkerParameters
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.database.entity.Rule
import com.idormy.sms.forwarder.entity.MsgInfo
import com.idormy.sms.forwarder.entity.TaskSetting
import com.idormy.sms.forwarder.entity.action.CleanerSetting
import com.idormy.sms.forwarder.entity.action.FrpcSetting
import com.idormy.sms.forwarder.entity.action.HttpServerSetting
import com.idormy.sms.forwarder.entity.action.SmsSetting
import com.idormy.sms.forwarder.service.HttpServerService
import com.idormy.sms.forwarder.utils.CacheUtils
import com.idormy.sms.forwarder.utils.EVENT_TOAST_ERROR
import com.idormy.sms.forwarder.utils.EVENT_TOAST_INFO
import com.idormy.sms.forwarder.utils.EVENT_TOAST_SUCCESS
import com.idormy.sms.forwarder.utils.EVENT_TOAST_WARNING
import com.idormy.sms.forwarder.utils.HistoryUtils
import com.idormy.sms.forwarder.utils.HttpServerUtils
import com.idormy.sms.forwarder.utils.PhoneUtils
import com.idormy.sms.forwarder.utils.SendUtils
import com.idormy.sms.forwarder.utils.TASK_ACTION_CLEANER
import com.idormy.sms.forwarder.utils.TASK_ACTION_FRPC
import com.idormy.sms.forwarder.utils.TASK_ACTION_HTTPSERVER
import com.idormy.sms.forwarder.utils.TASK_ACTION_NOTIFICATION
@ -35,6 +41,7 @@ import com.xuexiang.xrouter.utils.TextUtils
import com.xuexiang.xutil.file.FileUtils
import com.xuexiang.xutil.resource.ResUtils.getString
import frpclib.Frpclib
import java.util.Calendar
//执行每个task具体动作任务
@Suppress("PrivatePropertyName")
@ -153,6 +160,16 @@ class ActionWorker(context: Context, params: WorkerParameters) : CoroutineWorker
writeLog("httpServerSetting is null")
continue
}
HttpServerUtils.enableApiClone = httpServerSetting.enableApiClone
HttpServerUtils.enableApiSmsQuery = httpServerSetting.enableApiSmsQuery
HttpServerUtils.enableApiSmsSend = httpServerSetting.enableApiSmsSend
HttpServerUtils.enableApiCallQuery = httpServerSetting.enableApiCallQuery
HttpServerUtils.enableApiContactQuery = httpServerSetting.enableApiContactQuery
HttpServerUtils.enableApiContactAdd = httpServerSetting.enableApiContactAdd
HttpServerUtils.enableApiWol = httpServerSetting.enableApiWol
HttpServerUtils.enableApiLocation = httpServerSetting.enableApiLocation
HttpServerUtils.enableApiBatteryQuery = httpServerSetting.enableApiBatteryQuery
Intent(App.context, HttpServerService::class.java).also {
if (httpServerSetting.action == "start") {
App.context.startService(it)
@ -165,6 +182,27 @@ class ActionWorker(context: Context, params: WorkerParameters) : CoroutineWorker
writeLog("httpServer success", "SUCCESS")
}
TASK_ACTION_CLEANER -> {
val cleanerSetting = Gson().fromJson(action.setting, CleanerSetting::class.java)
if (cleanerSetting == null) {
writeLog("cleanerSetting is null")
continue
}
if (cleanerSetting.days > 0) {
val cal = Calendar.getInstance()
cal.add(Calendar.DAY_OF_MONTH, 0 - cleanerSetting.days)
Core.msg.deleteTimeAgo(cal.timeInMillis)
} else {
Core.msg.deleteAll()
}
//清理缓存
HistoryUtils.clearPreference()
CacheUtils.clearAllCache(App.context)
successNum++
writeLog("cleaner success", "SUCCESS")
}
else -> {
writeLog("action.type is ${action.type}")
}

@ -32,7 +32,7 @@ class CronWorker(context: Context, params: WorkerParameters) : CoroutineWorker(c
}
val task = AppDatabase.getInstance(App.context).taskDao().getOne(taskId)
if (task.status == 0) {
if (task == null || task.status == 0) {
Log.d(TAG, "TASK-${task.id}task is disabled")
return Result.success()
}

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="25.0dip"
android:height="25.0dip"
android:autoMirrored="true"
android:viewportWidth="25.0"
android:viewportHeight="25.0">
<path
android:fillColor="@color/color_green_primary_default"
android:pathData="M6.66,0.66L18.66,0.66A6,6 0,0 1,24.66 6.66L24.66,18.66A6,6 0,0 1,18.66 24.66L6.66,24.66A6,6 0,0 1,0.66 18.66L0.66,6.66A6,6 0,0 1,6.66 0.66z" />
<group
android:scaleX="0.02"
android:scaleY="0.02"
android:translateX="2.5"
android:translateY="2.5">
<path
android:fillColor="#ffffff"
android:pathData="M710.6,398.3l-84.8,-84.8 183.9,-183.9c23.4,-23.4 61.4,-23.4 84.8,0l0,0c23.4,23.4 23.4,61.4 0,84.8L710.6,398.3z" />
<path
android:fillColor="#ffffff"
android:pathData="M711.5,571.8L451.5,311.8c62.4,-62.4 163.6,-62.4 226.1,0l33.9,33.9c62.4,62.4 62.4,163.6 0,226.1zM411.1,359.2L664.3,612.4c1.9,1.9 2.3,4.7 0.9,7 -13.7,21.9 -82.7,137.8 -101.2,291a1.8,1.8 0,0 1,-2.6 1.4l-86,-51.8c-0.8,-0.5 -1.1,-1.5 -0.7,-2.3 8.1,-16.9 85.5,-179 77.6,-171.1 -8.3,8.3 -61.9,65.2 -102,123.3l-23.1,31.8s-90.5,-60.9 -118.4,-98.8c-0.4,-0.6 -0.5,-1.1 0,-1.6 18.4,-22.3 114.1,-146.7 114.1,-146.7l-162.7,97.6c-0.8,0.4 -1.6,0.3 -2.2,-0.3 -7.9,-8.8 -62.2,-68.8 -77.9,-97 -0.3,-0.6 -0.3,-1.1 0.3,-1.6 15.5,-12.5 103.1,-86.7 103.1,-86.7l-123.3,43.7c-0.9,0.3 -1.8,-0.1 -2.2,-0.9l-45.6,-85.6c-0.6,-1 -0.2,-2.3 1,-2.5 21.7,-4.3 202.9,-42 290.8,-102.7 2.2,-1.5 5.1,-1.2 7,0.8z" />
<path
android:fillColor="#ffffff"
android:pathData="M356,248m-52,0a52,52 0,1 0,104 0,52 52,0 1,0 -104,0Z" />
<path
android:fillColor="#ffffff"
android:pathData="M680,808m-64,0a64,64 0,1 0,128 0,64 64,0 1,0 -128,0Z" />
<path
android:fillColor="#ffffff"
android:pathData="M800,736m-36,0a36,36 0,1 0,72 0,36 36,0 1,0 -72,0Z" />
</group>
</vector>

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="25.0dip"
android:height="25.0dip"
android:autoMirrored="true"
android:viewportWidth="25.0"
android:viewportHeight="25.0">
<path
android:fillColor="@color/auto_task_icon_grey_bg"
android:pathData="M6.66,0.66L18.66,0.66A6,6 0,0 1,24.66 6.66L24.66,18.66A6,6 0,0 1,18.66 24.66L6.66,24.66A6,6 0,0 1,0.66 18.66L0.66,6.66A6,6 0,0 1,6.66 0.66z" />
<group
android:scaleX="0.02"
android:scaleY="0.02"
android:translateX="2.5"
android:translateY="2.5">
<path
android:fillColor="@color/auto_task_icon_grey"
android:pathData="M710.6,398.3l-84.8,-84.8 183.9,-183.9c23.4,-23.4 61.4,-23.4 84.8,0l0,0c23.4,23.4 23.4,61.4 0,84.8L710.6,398.3z" />
<path
android:fillColor="@color/auto_task_icon_grey"
android:pathData="M711.5,571.8L451.5,311.8c62.4,-62.4 163.6,-62.4 226.1,0l33.9,33.9c62.4,62.4 62.4,163.6 0,226.1zM411.1,359.2L664.3,612.4c1.9,1.9 2.3,4.7 0.9,7 -13.7,21.9 -82.7,137.8 -101.2,291a1.8,1.8 0,0 1,-2.6 1.4l-86,-51.8c-0.8,-0.5 -1.1,-1.5 -0.7,-2.3 8.1,-16.9 85.5,-179 77.6,-171.1 -8.3,8.3 -61.9,65.2 -102,123.3l-23.1,31.8s-90.5,-60.9 -118.4,-98.8c-0.4,-0.6 -0.5,-1.1 0,-1.6 18.4,-22.3 114.1,-146.7 114.1,-146.7l-162.7,97.6c-0.8,0.4 -1.6,0.3 -2.2,-0.3 -7.9,-8.8 -62.2,-68.8 -77.9,-97 -0.3,-0.6 -0.3,-1.1 0.3,-1.6 15.5,-12.5 103.1,-86.7 103.1,-86.7l-123.3,43.7c-0.9,0.3 -1.8,-0.1 -2.2,-0.9l-45.6,-85.6c-0.6,-1 -0.2,-2.3 1,-2.5 21.7,-4.3 202.9,-42 290.8,-102.7 2.2,-1.5 5.1,-1.2 7,0.8z" />
<path
android:fillColor="@color/auto_task_icon_grey"
android:pathData="M356,248m-52,0a52,52 0,1 0,104 0,52 52,0 1,0 -104,0Z" />
<path
android:fillColor="@color/auto_task_icon_grey"
android:pathData="M680,808m-64,0a64,64 0,1 0,128 0,64 64,0 1,0 -128,0Z" />
<path
android:fillColor="@color/auto_task_icon_grey"
android:pathData="M800,736m-36,0a36,36 0,1 0,72 0,36 36,0 1,0 -72,0Z" />
</group>
</vector>

@ -0,0 +1,128 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/xui_config_color_background"
android:orientation="vertical">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:overScrollMode="never">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:gravity="center_horizontal"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_margin="10dp"
android:contentDescription="@string/task_cleaner"
app:srcCompat="@drawable/auto_task_icon_cleaner"
tools:ignore="ImageContrastCheck" />
<LinearLayout
style="@style/taskBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/task_cleaner"
android:textSize="@dimen/text_size_big"
android:textStyle="bold" />
<TextView
android:id="@+id/tv_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/task_cleaner_tips"
android:textSize="@dimen/text_size_mini"
tools:ignore="SmallSp" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:background="?attr/xui_config_color_separator_light" />
<LinearLayout
android:id="@+id/layout_start_server"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.xuexiang.xui.widget.picker.XSeekBar
android:id="@+id/xsb_days"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:xsb_insideRangeLineColor="#0bd97f"
app:xsb_insideRangeLineStrokeWidth="10dp"
app:xsb_isShowBubble="true"
app:xsb_isShowRuler="true"
app:xsb_max="60"
app:xsb_min="0"
app:xsb_numberTextColor="#ffffff"
app:xsb_numberTextSize="@dimen/text_size_small"
app:xsb_outsideRangeLineColor="#f0f0f0"
app:xsb_outsideRangeLineStrokeWidth="10dp"
app:xsb_rulerColor="@color/xui_config_color_gray_4"
app:xsb_rulerInterval="ten" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:text="@string/day"
android:textSize="12sp"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
android:padding="10dp">
<com.xuexiang.xui.widget.textview.supertextview.SuperButton
android:id="@+id/btn_del"
style="@style/SuperButton.Gray.Icon.Spacing"
android:drawableStart="@drawable/ic_delete"
android:text="@string/discard"
tools:ignore="RtlSymmetry,TextContrastCheck,TouchTargetSizeCheck" />
<com.xuexiang.xui.widget.textview.supertextview.SuperButton
android:id="@+id/btn_save"
style="@style/SuperButton.Blue.Icon.Spacing"
android:drawableStart="@drawable/ic_save"
android:text="@string/submit"
tools:ignore="RtlSymmetry,TextContrastCheck,TouchTargetSizeCheck" />
<com.xuexiang.xui.widget.textview.supertextview.SuperButton
android:id="@+id/btn_test"
style="@style/SuperButton.Green.Icon.Spacing"
android:drawableStart="@drawable/ic_test"
android:text="@string/test"
tools:ignore="RtlSymmetry,TextContrastCheck,TouchTargetSizeCheck" />
</LinearLayout>
</LinearLayout>

@ -0,0 +1,458 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/xui_config_color_background"
android:orientation="vertical">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:overScrollMode="never">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:gravity="center_horizontal"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_margin="10dp"
android:contentDescription="@string/task_http_server"
app:srcCompat="@drawable/auto_task_icon_http_server"
tools:ignore="ImageContrastCheck" />
<LinearLayout
style="@style/taskBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/task_http_server"
android:textSize="@dimen/text_size_big"
android:textStyle="bold" />
<TextView
android:id="@+id/tv_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/task_http_server_tips"
android:textSize="@dimen/text_size_mini"
tools:ignore="SmallSp" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:background="?attr/xui_config_color_separator_light" />
<RadioGroup
android:id="@+id/rg_http_server_state"
style="@style/rg_style"
android:orientation="horizontal"
android:paddingBottom="@dimen/config_padding_5dp">
<RadioButton
android:id="@+id/rb_start_server"
style="@style/rg_rb_style"
android:checked="true"
android:text="@string/start_server"
tools:ignore="TouchTargetSizeCheck" />
<RadioButton
android:id="@+id/rb_stop_server"
style="@style/rg_rb_style"
android:text="@string/stop_server"
tools:ignore="TouchTargetSizeCheck" />
</RadioGroup>
</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/enable_function"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:text="@string/enable_function_tips"
android:textSize="@dimen/text_size_mini"
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/api_clone"
android:textStyle="bold"
tools:ignore="RelativeOverlap" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/api_clone_tips"
android:textSize="@dimen/text_size_mini"
tools:ignore="SmallSp" />
</LinearLayout>
<com.xuexiang.xui.widget.button.switchbutton.SwitchButton
android:id="@+id/sb_api_clone"
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">
<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/api_sms_query"
android:textStyle="bold"
tools:ignore="RelativeOverlap" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/api_sms_query_tips"
android:textSize="@dimen/text_size_mini"
tools:ignore="SmallSp" />
</LinearLayout>
<com.xuexiang.xui.widget.button.switchbutton.SwitchButton
android:id="@+id/sb_api_query_sms"
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">
<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/api_sms_send"
android:textStyle="bold"
tools:ignore="RelativeOverlap" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/api_sms_send_tips"
android:textSize="@dimen/text_size_mini"
tools:ignore="SmallSp" />
</LinearLayout>
<com.xuexiang.xui.widget.button.switchbutton.SwitchButton
android:id="@+id/sb_api_send_sms"
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">
<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/api_call_query"
android:textStyle="bold"
tools:ignore="RelativeOverlap" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/api_call_query_tips"
android:textSize="@dimen/text_size_mini"
tools:ignore="SmallSp" />
</LinearLayout>
<com.xuexiang.xui.widget.button.switchbutton.SwitchButton
android:id="@+id/sb_api_query_call"
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">
<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/api_contact_query"
android:textStyle="bold"
tools:ignore="RelativeOverlap" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/api_contact_query_tips"
android:textSize="@dimen/text_size_mini"
tools:ignore="SmallSp" />
</LinearLayout>
<com.xuexiang.xui.widget.button.switchbutton.SwitchButton
android:id="@+id/sb_api_query_contacts"
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"
tools:ignore="TooManyViews">
<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/api_contact_add"
android:textStyle="bold"
tools:ignore="RelativeOverlap" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/api_contact_add_tips"
android:textSize="@dimen/text_size_mini"
tools:ignore="SmallSp" />
</LinearLayout>
<com.xuexiang.xui.widget.button.switchbutton.SwitchButton
android:id="@+id/sb_api_add_contacts"
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">
<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/api_wol"
android:textStyle="bold"
tools:ignore="RelativeOverlap,TooManyViews" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/api_wol_tips"
android:textSize="@dimen/text_size_mini"
tools:ignore="SmallSp" />
</LinearLayout>
<com.xuexiang.xui.widget.button.switchbutton.SwitchButton
android:id="@+id/sb_api_wol"
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">
<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/api_location"
android:textStyle="bold"
tools:ignore="RelativeOverlap,TooManyViews" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/api_location_tips"
android:textSize="@dimen/text_size_mini"
tools:ignore="SmallSp" />
</LinearLayout>
<com.xuexiang.xui.widget.button.switchbutton.SwitchButton
android:id="@+id/sb_api_location"
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"
tools:ignore="TooManyViews">
<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/api_battery_query"
android:textStyle="bold"
tools:ignore="RelativeOverlap" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/api_battery_query_tips"
android:textSize="@dimen/text_size_mini"
tools:ignore="SmallSp" />
</LinearLayout>
<com.xuexiang.xui.widget.button.switchbutton.SwitchButton
android:id="@+id/sb_api_query_battery"
style="@style/SwitchButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
android:padding="10dp">
<com.xuexiang.xui.widget.textview.supertextview.SuperButton
android:id="@+id/btn_del"
style="@style/SuperButton.Gray.Icon.Spacing"
android:drawableStart="@drawable/ic_delete"
android:text="@string/discard"
tools:ignore="RtlSymmetry,TextContrastCheck,TouchTargetSizeCheck" />
<com.xuexiang.xui.widget.textview.supertextview.SuperButton
android:id="@+id/btn_save"
style="@style/SuperButton.Blue.Icon.Spacing"
android:drawableStart="@drawable/ic_save"
android:text="@string/submit"
tools:ignore="RtlSymmetry,TextContrastCheck,TouchTargetSizeCheck" />
<com.xuexiang.xui.widget.textview.supertextview.SuperButton
android:id="@+id/btn_test"
style="@style/SuperButton.Green.Icon.Spacing"
android:drawableStart="@drawable/ic_test"
android:text="@string/test"
tools:ignore="RtlSymmetry,TextContrastCheck,TouchTargetSizeCheck" />
</LinearLayout>
</LinearLayout>

@ -897,6 +897,7 @@
<string name="copy" tools:ignore="PrivateResource">Copy</string>
<string name="random">Random</string>
<string name="enable_function">Enable Function</string>
<string name="disable_function">Disable Function</string>
<string name="enable_function_tips">Select the features you want to enable remote control as needed</string>
<string name="api_clone">OneKey Clone</string>
<string name="api_clone_tips">One-click cloning of the general config of the machine, sender, and rules to the new machine</string>
@ -1169,7 +1170,10 @@
<string name="task_notification">Notification</string>
<string name="task_frpc">Frpc Setting</string>
<string name="task_frpc_tips">Control the start/stop of FRPC.</string>
<string name="task_server">Server Setting</string>
<string name="task_http_server">Server Setting</string>
<string name="task_http_server_tips">Manage HttpServer start/stop and enable/disable functions</string>
<string name="task_cleaner">Cleaner</string>
<string name="task_cleaner_tips">Delete FW. logs older than N days, delete cache, etc.</string>
<string name="second">Second</string>
<string name="minute">Minute</string>

@ -898,6 +898,7 @@
<string name="rsa_key_tips2">已复制公钥到剪贴板</string>
<string name="sign_key_tips">已生成密钥,并复制到剪贴板</string>
<string name="enable_function">启用功能</string>
<string name="disable_function">禁用功能</string>
<string name="enable_function_tips">按需选择您要启用远程控制的功能</string>
<string name="api_clone">一键换新机</string>
<string name="api_clone_tips">一键克隆本机的通用配置、发送通道、转发规则到新机器</string>
@ -1170,7 +1171,10 @@
<string name="task_notification">通道推送</string>
<string name="task_frpc">Frpc设置</string>
<string name="task_frpc_tips">控制内网穿透·FRPC的启动/停止</string>
<string name="task_server">HttpServer设置</string>
<string name="task_http_server">HttpServer设置</string>
<string name="task_http_server_tips">控制HttpServer的启动/停止,并支持启用/禁用功能</string>
<string name="task_cleaner">清理日志</string>
<string name="task_cleaner_tips">批量删除N天前的转发记录、删除缓存等</string>
<string name="second"></string>
<string name="minute"></string>

@ -898,6 +898,7 @@
<string name="rsa_key_tips2">已複製公鑰到剪貼板</string>
<string name="sign_key_tips">已生成密鑰,並複製到剪貼板</string>
<string name="enable_function">啟用功能</string>
<string name="disable_function">禁用功能</string>
<string name="enable_function_tips">按需選擇您要啟用遠程控制的功能</string>
<string name="api_clone">一鍵換新機</string>
<string name="api_clone_tips">一鍵克隆本機的通用配置、發送通道、轉發規則到新機器</string>
@ -1170,7 +1171,10 @@
<string name="task_notification">通道推送</string>
<string name="task_frpc">Frpc設置</string>
<string name="task_frpc_tips">控制內網穿透·FRPC的啟動/停止</string>
<string name="task_server">HttpServer設置</string>
<string name="task_http_server">HttpServer設置</string>
<string name="task_http_server_tips">控制HttpServer的啟動/停止,並支持啟用/禁用功能</string>
<string name="task_cleaner">清理日誌</string>
<string name="task_cleaner_tips">批量刪除N天前的轉發記錄、刪除快取等</string>
<string name="second"></string>
<string name="minute"></string>

@ -898,6 +898,7 @@
<string name="rsa_key_tips2">已复制公钥到剪贴板</string>
<string name="sign_key_tips">已生成密钥,并复制到剪贴板</string>
<string name="enable_function">启用功能</string>
<string name="disable_function">禁用功能</string>
<string name="enable_function_tips">按需选择您要启用远程控制的功能</string>
<string name="api_clone">一键换新机</string>
<string name="api_clone_tips">一键克隆本机的通用配置、发送通道、转发规则到新机器</string>
@ -1170,7 +1171,10 @@
<string name="task_notification">通道推送</string>
<string name="task_frpc">Frpc设置</string>
<string name="task_frpc_tips">控制内网穿透·FRPC的启动/停止</string>
<string name="task_server">HttpServer设置</string>
<string name="task_http_server">HttpServer设置</string>
<string name="task_http_server_tips">控制HttpServer的启动/停止,并支持启用/禁用功能</string>
<string name="task_cleaner">清理日志</string>
<string name="task_cleaner_tips">批量删除N天前的转发记录、删除缓存等</string>
<string name="second"></string>
<string name="minute"></string>

Loading…
Cancel
Save