新增:短信指令(根据短信指令开关对应功能) #I5YX3F

This commit is contained in:
pppscn 2023-02-14 15:11:11 +08:00
parent dd798e42cc
commit 6571775a0f
14 changed files with 864 additions and 519 deletions

View File

@ -22,11 +22,13 @@ class FrpcPagingAdapter(private val itemClickListener: OnItemClickListener) : Pa
return MyViewHolder(binding) return MyViewHolder(binding)
} }
@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: MyViewHolder, position: Int) { override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val item = getItem(position) val item = getItem(position)
if (item != null) { if (item != null) {
holder.binding.ivImage.setImageResource(R.drawable.ic_menu_frpc) holder.binding.ivImage.setImageResource(R.drawable.ic_menu_frpc)
holder.binding.ivAutorun.setImageResource(item.autorunImageId) holder.binding.ivAutorun.setImageResource(item.autorunImageId)
holder.binding.tvUid.text = "UID:${item.uid}"
holder.binding.tvName.text = item.name holder.binding.tvName.text = item.name
if (item.connecting || Frpclib.isRunning(item.uid)) { if (item.connecting || Frpclib.isRunning(item.uid)) {
@ -41,9 +43,13 @@ class FrpcPagingAdapter(private val itemClickListener: OnItemClickListener) : Pa
} }
} }
holder.binding.ivCopy.setImageResource(R.drawable.ic_copy)
holder.binding.ivEdit.setImageResource(R.drawable.ic_edit) holder.binding.ivEdit.setImageResource(R.drawable.ic_edit)
holder.binding.ivDelete.setImageResource(R.drawable.ic_delete) holder.binding.ivDelete.setImageResource(R.drawable.ic_delete)
holder.binding.ivCopy.setOnClickListener { view: View? ->
itemClickListener.onItemClicked(view, item)
}
holder.binding.ivPlay.setOnClickListener { view: View? -> holder.binding.ivPlay.setOnClickListener { view: View? ->
itemClickListener.onItemClicked(view, item) itemClickListener.onItemClicked(view, item)
} }

View File

@ -24,6 +24,9 @@ interface FrpcDao {
fun get(uid: String): Single<Frpc> fun get(uid: String): Single<Frpc>
//TODO:允许主线程访问,后面再优化 //TODO:允许主线程访问,后面再优化
@Query("SELECT * FROM Frpc where uid=:uid")
fun getOne(uid: String): Frpc
@Query("SELECT * FROM Frpc where autorun=1") @Query("SELECT * FROM Frpc where autorun=1")
fun getAutorun(): List<Frpc> fun getAutorun(): List<Frpc>

View File

@ -9,84 +9,130 @@ import java.io.Serializable
data class CloneInfo( data class CloneInfo(
@SerializedName("version_code") @SerializedName("version_code")
var versionCode: Int = 0, var versionCode: Int = 0,
@SerializedName("version_name") @SerializedName("version_name")
var versionName: String? = null, var versionName: String? = null,
@SerializedName("enable_sms") @SerializedName("enable_sms")
var enableSms: Boolean = false, var enableSms: Boolean = false,
@SerializedName("enable_phone") @SerializedName("enable_phone")
var enablePhone: Boolean = false, var enablePhone: Boolean = false,
@SerializedName("call_type1") @SerializedName("call_type1")
var callType1: Boolean = false, var callType1: Boolean = false,
@SerializedName("call_type2") @SerializedName("call_type2")
var callType2: Boolean = false, var callType2: Boolean = false,
@SerializedName("call_type3") @SerializedName("call_type3")
var callType3: Boolean = false, var callType3: Boolean = false,
@SerializedName("call_type4") @SerializedName("call_type4")
var callType4: Boolean = false, var callType4: Boolean = false,
@SerializedName("call_type5") @SerializedName("call_type5")
var callType5: Boolean = false, var callType5: Boolean = false,
@SerializedName("call_type6") @SerializedName("call_type6")
var callType6: Boolean = false, var callType6: Boolean = false,
@SerializedName("enable_app_notify") @SerializedName("enable_app_notify")
var enableAppNotify: Boolean = false, var enableAppNotify: Boolean = false,
@SerializedName("cancel_app_notify") @SerializedName("cancel_app_notify")
var cancelAppNotify: Boolean = false, var cancelAppNotify: Boolean = false,
@SerializedName("cancel_extra_app_notify") @SerializedName("cancel_extra_app_notify")
var cancelExtraAppNotify: String? = null, var cancelExtraAppNotify: String? = null,
@SerializedName("enable_not_user_present") @SerializedName("enable_not_user_present")
var enableNotUserPresent: Boolean = false, var enableNotUserPresent: Boolean = false,
@SerializedName("enable_load_app_list") @SerializedName("enable_load_app_list")
var enableLoadAppList: Boolean = false, var enableLoadAppList: Boolean = false,
@SerializedName("enable_load_user_app_list") @SerializedName("enable_load_user_app_list")
var enableLoadUserAppList: Boolean = false, var enableLoadUserAppList: Boolean = false,
@SerializedName("enable_load_system_app_list") @SerializedName("enable_load_system_app_list")
var enableLoadSystemAppList: Boolean = false, var enableLoadSystemAppList: Boolean = false,
@SerializedName("duplicate_messages_limits") @SerializedName("duplicate_messages_limits")
var duplicateMessagesLimits: Int = 0, var duplicateMessagesLimits: Int = 0,
@SerializedName("enable_network_state_receiver") @SerializedName("enable_network_state_receiver")
var enableNetworkStateReceiver: Boolean = false, var enableNetworkStateReceiver: Boolean = false,
@SerializedName("enable_battery_receiver") @SerializedName("enable_battery_receiver")
var enableBatteryReceiver: Boolean = false, var enableBatteryReceiver: Boolean = false,
@SerializedName("battery_level_min") @SerializedName("battery_level_min")
var batteryLevelMin: Int = 0, var batteryLevelMin: Int = 0,
@SerializedName("battery_level_max") @SerializedName("battery_level_max")
var batteryLevelMax: Int = 0, var batteryLevelMax: Int = 0,
@SerializedName("battery_level_once") @SerializedName("battery_level_once")
var batteryLevelOnce: Boolean = false, var batteryLevelOnce: Boolean = false,
@SerializedName("enable_battery_cron") @SerializedName("enable_battery_cron")
var enableBatteryCron: Boolean = false, var enableBatteryCron: Boolean = false,
@SerializedName("battery_cron_start_time") @SerializedName("battery_cron_start_time")
var batteryCronStartTime: String? = null, var batteryCronStartTime: String? = null,
@SerializedName("battery_cron_interval") @SerializedName("battery_cron_interval")
var batteryCronInterval: Int = 0, var batteryCronInterval: Int = 0,
@SerializedName("enable_exclude_from_recents") @SerializedName("enable_exclude_from_recents")
var enableExcludeFromRecents: Boolean = false, var enableExcludeFromRecents: Boolean = false,
@SerializedName("enable_cactus") @SerializedName("enable_cactus")
var enableCactus: Boolean = false, var enableCactus: Boolean = false,
@SerializedName("enable_play_silence_music") @SerializedName("enable_play_silence_music")
var enablePlaySilenceMusic: Boolean = false, var enablePlaySilenceMusic: Boolean = false,
@SerializedName("enable_one_pixel_activity") @SerializedName("enable_one_pixel_activity")
var enableOnePixelActivity: Boolean = false, var enableOnePixelActivity: Boolean = false,
@SerializedName("request_retry_times") @SerializedName("request_retry_times")
var requestRetryTimes: Int = 0, var requestRetryTimes: Int = 0,
@SerializedName("request_delay_time") @SerializedName("request_delay_time")
var requestDelayTime: Int = 0, var requestDelayTime: Int = 0,
@SerializedName("request_timeout") @SerializedName("request_timeout")
var requestTimeout: Int = 0, var requestTimeout: Int = 0,
@SerializedName("notify_content") @SerializedName("notify_content")
var notifyContent: String? = null, var notifyContent: String? = null,
@SerializedName("enable_sms_template") @SerializedName("enable_sms_template")
var enableSmsTemplate: Boolean = false, var enableSmsTemplate: Boolean = false,
@SerializedName("sms_template") @SerializedName("sms_template")
var smsTemplate: String? = null, var smsTemplate: String? = null,
@SerializedName("enable_help_tip") @SerializedName("enable_help_tip")
var enableHelpTip: Boolean = false, var enableHelpTip: Boolean = false,
@SerializedName("enable_pure_client_mode") @SerializedName("enable_pure_client_mode")
var enablePureClientMode: Boolean = false, var enablePureClientMode: Boolean = false,
@SerializedName("enable_sms_command")
var enableSmsCommand: Boolean = false,
@SerializedName("sms_command_safe_phone")
var smsCommandSafePhone: String? = null,
@SerializedName("sender_list") @SerializedName("sender_list")
var senderList: List<Sender>? = null, var senderList: List<Sender>? = null,
@SerializedName("rule_list") @SerializedName("rule_list")
var ruleList: List<Rule>? = null, var ruleList: List<Rule>? = null,
@SerializedName("frpc_list") @SerializedName("frpc_list")
var frpcList: List<Frpc>? = null, var frpcList: List<Frpc>? = null,
) : Serializable ) : Serializable

View File

@ -28,6 +28,7 @@ import com.xuexiang.xui.utils.ThemeUtils
import com.xuexiang.xui.utils.WidgetUtils import com.xuexiang.xui.utils.WidgetUtils
import com.xuexiang.xui.widget.actionbar.TitleBar import com.xuexiang.xui.widget.actionbar.TitleBar
import com.xuexiang.xui.widget.dialog.LoadingDialog import com.xuexiang.xui.widget.dialog.LoadingDialog
import com.xuexiang.xutil.system.ClipboardUtils
import frpclib.Frpclib import frpclib.Frpclib
import io.reactivex.CompletableObserver import io.reactivex.CompletableObserver
import io.reactivex.Observer import io.reactivex.Observer
@ -60,10 +61,7 @@ class FrpcFragment : BaseFragment<FragmentFrpcsBinding?>(), FrpcPagingAdapter.On
titleBar!!.addAction(object : TitleBar.ImageAction(R.drawable.ic_add) { titleBar!!.addAction(object : TitleBar.ImageAction(R.drawable.ic_add) {
@SingleClick @SingleClick
override fun performAction(view: View) { override fun performAction(view: View) {
FrpcUtils.getStringFromRaw(context!!, R.raw.frpc) FrpcUtils.getStringFromRaw(context!!, R.raw.frpc).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : Observer<String?> {
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : Observer<String?> {
override fun onSubscribe(d: Disposable) {} override fun onSubscribe(d: Disposable) {}
override fun onNext(content: String) { override fun onNext(content: String) {
LiveEventBus.get<Frpc>(INTENT_FRPC_EDIT_FILE).post(Frpc(content)) LiveEventBus.get<Frpc>(INTENT_FRPC_EDIT_FILE).post(Frpc(content))
@ -118,7 +116,6 @@ class FrpcFragment : BaseFragment<FragmentFrpcsBinding?>(), FrpcPagingAdapter.On
//运行出错时间 //运行出错时间
LiveEventBus.get(EVENT_FRPC_RUNNING_ERROR, String::class.java).observe(this) { LiveEventBus.get(EVENT_FRPC_RUNNING_ERROR, String::class.java).observe(this) {
XToastUtils.error(getString(R.string.frpc_failed_to_run)) XToastUtils.error(getString(R.string.frpc_failed_to_run))
//FrpcUtils.checkAndStopService(requireContext())
adapter.refresh() adapter.refresh()
} }
@ -129,9 +126,12 @@ class FrpcFragment : BaseFragment<FragmentFrpcsBinding?>(), FrpcPagingAdapter.On
} }
override fun onItemClicked(view: View?, item: Frpc) { override fun onItemClicked(view: View?, item: Frpc) {
val id = view?.id when (val id = view?.id) {
if (id == R.id.iv_play) { R.id.iv_copy -> {
//if (!FrpcUtils.isServiceRunning(ForegroundService::class.java.name, requireContext())) { ClipboardUtils.copyText(item.uid)
XToastUtils.info(String.format(getString(R.string.copied_to_clipboard), item.uid))
}
R.id.iv_play -> {
if (!ForegroundService.isRunning) { if (!ForegroundService.isRunning) {
val intent = Intent(requireContext(), ForegroundService::class.java) val intent = Intent(requireContext(), ForegroundService::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@ -145,14 +145,10 @@ class FrpcFragment : BaseFragment<FragmentFrpcsBinding?>(), FrpcPagingAdapter.On
Frpclib.close(item.uid) Frpclib.close(item.uid)
item.setConnecting(false) item.setConnecting(false)
LiveEventBus.get<Frpc>(EVENT_FRPC_UPDATE_CONFIG).post(item) LiveEventBus.get<Frpc>(EVENT_FRPC_UPDATE_CONFIG).post(item)
//FrpcUtils.checkAndStopService(requireContext())
return return
} }
FrpcUtils.waitService(ForegroundService::class.java.name, requireContext()) FrpcUtils.waitService(ForegroundService::class.java.name, requireContext()).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : CompletableObserver {
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : CompletableObserver {
var mLoadingDialog: LoadingDialog = WidgetUtils.getLoadingDialog(context!!).setIconScale(0.4f).setLoadingSpeed(8) var mLoadingDialog: LoadingDialog = WidgetUtils.getLoadingDialog(context!!).setIconScale(0.4f).setLoadingSpeed(8)
override fun onSubscribe(d: Disposable) { override fun onSubscribe(d: Disposable) {
@ -177,16 +173,19 @@ class FrpcFragment : BaseFragment<FragmentFrpcsBinding?>(), FrpcPagingAdapter.On
LiveEventBus.get<Frpc>(EVENT_FRPC_UPDATE_CONFIG).post(item) LiveEventBus.get<Frpc>(EVENT_FRPC_UPDATE_CONFIG).post(item)
} }
}) })
} else { }
else -> {
//编辑或删除需要先停止客户端 //编辑或删除需要先停止客户端
if (Frpclib.isRunning(item.uid)) { if (Frpclib.isRunning(item.uid)) {
XToastUtils.warning(R.string.tipServiceRunning) XToastUtils.warning(R.string.tipServiceRunning)
return return
} }
if (id == R.id.iv_edit) { when (id) {
R.id.iv_edit -> {
LiveEventBus.get<Frpc>(INTENT_FRPC_EDIT_FILE).post(item) LiveEventBus.get<Frpc>(INTENT_FRPC_EDIT_FILE).post(item)
openNewPage(FrpcEditFragment::class.java) openNewPage(FrpcEditFragment::class.java)
} else if (id == R.id.iv_delete) { }
R.id.iv_delete -> {
try { try {
viewModel.delete(item) viewModel.delete(item)
LiveEventBus.get<Frpc>(EVENT_FRPC_DELETE_CONFIG).post(item) LiveEventBus.get<Frpc>(EVENT_FRPC_DELETE_CONFIG).post(item)
@ -197,6 +196,8 @@ class FrpcFragment : BaseFragment<FragmentFrpcsBinding?>(), FrpcPagingAdapter.On
} }
} }
} }
}
}
override fun onItemRemove(view: View?, id: Int) {} override fun onItemRemove(view: View?, id: Int) {}
} }

View File

@ -97,6 +97,10 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
switchEnableAppNotify( switchEnableAppNotify(
binding!!.sbEnableAppNotify, binding!!.scbCancelAppNotify, binding!!.scbNotUserPresent binding!!.sbEnableAppNotify, binding!!.scbCancelAppNotify, binding!!.scbNotUserPresent
) )
//短信指令
switchEnableSmsCommand(binding!!.sbEnableSmsCommand, binding!!.etSafePhone)
//设置自动消除额外APP通知 //设置自动消除额外APP通知
editExtraAppList(binding!!.etAppList) editExtraAppList(binding!!.etAppList)
//启动时异步获取已安装App信息 //启动时异步获取已安装App信息
@ -440,12 +444,12 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
val layoutOptionalAction: LinearLayout = binding!!.layoutOptionalAction val layoutOptionalAction: LinearLayout = binding!!.layoutOptionalAction
layoutOptionalAction.visibility = if (isEnable) View.VISIBLE else View.GONE layoutOptionalAction.visibility = if (isEnable) View.VISIBLE else View.GONE
val layoutAppList: LinearLayout = binding!!.layoutAppList //val layoutAppList: LinearLayout = binding!!.layoutAppList
layoutAppList.visibility = if (isEnable) View.VISIBLE else View.GONE //layoutAppList.visibility = if (isEnable) View.VISIBLE else View.GONE
sbEnableAppNotify.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean -> sbEnableAppNotify.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
layoutOptionalAction.visibility = if (isChecked) View.VISIBLE else View.GONE layoutOptionalAction.visibility = if (isChecked) View.VISIBLE else View.GONE
layoutAppList.visibility = if (isChecked) View.VISIBLE else View.GONE //layoutAppList.visibility = if (isChecked) View.VISIBLE else View.GONE
SettingUtils.enableAppNotify = isChecked SettingUtils.enableAppNotify = isChecked
if (isChecked) { if (isChecked) {
//检查权限是否获取 //检查权限是否获取
@ -473,6 +477,57 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
} }
} }
//接受短信指令
@SuppressLint("UseSwitchCompatOrMaterialCode")
fun switchEnableSmsCommand(sbEnableSmsCommand: SwitchButton, etSafePhone: EditText) {
sbEnableSmsCommand.isChecked = SettingUtils.enableSmsCommand
etSafePhone.visibility = if (SettingUtils.enableSmsCommand) View.VISIBLE else View.GONE
sbEnableSmsCommand.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
SettingUtils.enableSmsCommand = isChecked
etSafePhone.visibility = if (isChecked) View.VISIBLE else View.GONE
if (isChecked) {
//检查权限是否获取
XXPermissions.with(this)
// 接收短信
.permission(Permission.RECEIVE_SMS)
// 发送短信
//.permission(Permission.SEND_SMS)
// 读取短信
.permission(Permission.READ_SMS).request(object : OnPermissionCallback {
override fun onGranted(permissions: List<String>, all: Boolean) {
if (all) {
XToastUtils.info(R.string.toast_granted_all)
} else {
XToastUtils.info(R.string.toast_granted_part)
}
}
override fun onDenied(permissions: List<String>, never: Boolean) {
if (never) {
XToastUtils.info(R.string.toast_denied_never)
// 如果是被永久拒绝就跳转到应用权限系统设置页面
XXPermissions.startPermissionActivity(requireContext(), permissions)
} else {
XToastUtils.info(R.string.toast_denied)
}
SettingUtils.enableSmsCommand = false
sbEnableSmsCommand.isChecked = false
}
})
}
}
etSafePhone.setText(SettingUtils.smsCommandSafePhone)
etSafePhone.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) {
SettingUtils.smsCommandSafePhone = etSafePhone.text.toString().trim().removeSuffix("\n")
}
})
}
//设置自动消除额外APP通知 //设置自动消除额外APP通知
private fun editExtraAppList(textAppList: EditText) { private fun editExtraAppList(textAppList: EditText) {
textAppList.setText(SettingUtils.cancelExtraAppNotify) textAppList.setText(SettingUtils.cancelExtraAppNotify)

View File

@ -10,15 +10,25 @@ import androidx.work.WorkManager
import androidx.work.workDataOf import androidx.work.workDataOf
import com.google.gson.Gson import com.google.gson.Gson
import com.idormy.sms.forwarder.App import com.idormy.sms.forwarder.App
import com.idormy.sms.forwarder.database.AppDatabase
import com.idormy.sms.forwarder.entity.MsgInfo import com.idormy.sms.forwarder.entity.MsgInfo
import com.idormy.sms.forwarder.service.HttpService
import com.idormy.sms.forwarder.utils.PhoneUtils import com.idormy.sms.forwarder.utils.PhoneUtils
import com.idormy.sms.forwarder.utils.SettingUtils import com.idormy.sms.forwarder.utils.SettingUtils
import com.idormy.sms.forwarder.utils.Worker import com.idormy.sms.forwarder.utils.Worker
import com.idormy.sms.forwarder.workers.SendWorker import com.idormy.sms.forwarder.workers.SendWorker
import com.xuexiang.xrouter.utils.TextUtils
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.* import java.util.*
//短信广播 //短信广播
@Suppress("PrivatePropertyName", "DEPRECATION") @OptIn(DelicateCoroutinesApi::class)
@Suppress("PrivatePropertyName", "DEPRECATION", "DeferredResultUnused", "SENSELESS_COMPARISON")
class SmsReceiver : BroadcastReceiver() { class SmsReceiver : BroadcastReceiver() {
private var TAG = "SmsReceiver" private var TAG = "SmsReceiver"
@ -28,20 +38,25 @@ class SmsReceiver : BroadcastReceiver() {
//纯客户端模式 //纯客户端模式
if (SettingUtils.enablePureClientMode) return if (SettingUtils.enablePureClientMode) return
//总开关
if (!SettingUtils.enableSms) return
//过滤广播 //过滤广播
if (intent.action != Telephony.Sms.Intents.SMS_RECEIVED_ACTION && intent.action != Telephony.Sms.Intents.SMS_DELIVER_ACTION) return if (intent.action != Telephony.Sms.Intents.SMS_RECEIVED_ACTION && intent.action != Telephony.Sms.Intents.SMS_DELIVER_ACTION) return
var from = "" var from = ""
var content = "" var message = ""
for (smsMessage in Telephony.Sms.Intents.getMessagesFromIntent(intent)) { for (smsMessage in Telephony.Sms.Intents.getMessagesFromIntent(intent)) {
from = smsMessage.displayOriginatingAddress from = smsMessage.displayOriginatingAddress
content += smsMessage.messageBody message += smsMessage.messageBody
} }
Log.d(TAG, "from = $from") Log.d(TAG, "from = $from, message = $message")
Log.d(TAG, "content = $content")
//短信指令
if (SettingUtils.enableSmsCommand && message.startsWith("smsf#")) {
doSmsCommand(context, from, message)
return
}
//总开关
if (!SettingUtils.enableSms) return
//TODO准确获取卡槽信息目前测试结果只有 subscription 相对靠谱 //TODO准确获取卡槽信息目前测试结果只有 subscription 相对靠谱
val slot = intent.extras?.getInt("slot") ?: -1 val slot = intent.extras?.getInt("slot") ?: -1
@ -78,7 +93,7 @@ class SmsReceiver : BroadcastReceiver() {
else -> "" else -> ""
} }
val msgInfo = MsgInfo("sms", from, content, Date(), simInfo, simSlot, subscription) val msgInfo = MsgInfo("sms", from, message, Date(), simInfo, simSlot, subscription)
Log.d(TAG, "msgInfo = $msgInfo") Log.d(TAG, "msgInfo = $msgInfo")
val request = OneTimeWorkRequestBuilder<SendWorker>().setInputData( val request = OneTimeWorkRequestBuilder<SendWorker>().setInputData(
@ -93,4 +108,97 @@ class SmsReceiver : BroadcastReceiver() {
} }
} }
//处理短信指令
private fun doSmsCommand(context: Context, from: String, message: String) {
var safePhone = SettingUtils.smsCommandSafePhone
Log.d(TAG, "safePhone = $safePhone")
if (!TextUtils.isEmpty(safePhone)) {
var isSafePhone = false
safePhone = safePhone.replace(";", ",").replace("", ",").replace("", ",").trim()
for (phone in safePhone.split(",")) {
if (!TextUtils.isEmpty(phone.trim()) && from.endsWith(phone.trim())) {
isSafePhone = true
break
}
}
if (!isSafePhone) {
Log.d(TAG, "from = $from is not safePhone = $safePhone")
return
}
}
val smsCommand = message.substring(5)
val cmdList = smsCommand.split("#")
Log.d(TAG, "smsCommand = $smsCommand, cmdList = $cmdList")
if (cmdList.count() < 2) return
val function = cmdList[0]
val action = cmdList[1]
val param = if (cmdList.count() > 2) cmdList[2] else ""
when (function) {
"frpc" -> {
if (!FileUtils.isFileExists(context.filesDir?.absolutePath + "/libs/libgojni.so")) {
Log.d(TAG, "还未下载Frpc库")
return
}
if (TextUtils.isEmpty(param)) {
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 (action == "start") {
if (!Frpclib.isRunning(frpc.uid)) {
val error = Frpclib.runContent(frpc.uid, frpc.config)
if (!TextUtils.isEmpty(error)) {
Log.e(TAG, error)
}
}
} else if (action == "stop") {
if (Frpclib.isRunning(frpc.uid)) {
Frpclib.close(frpc.uid)
}
}
}
}
} else {
GlobalScope.async(Dispatchers.IO) {
val frpc = AppDatabase.getInstance(App.context).frpcDao().getOne(param)
if (frpc == null) {
Log.d(TAG, "没有找到指定的Frpc")
return@async
}
if (action == "start") {
if (!Frpclib.isRunning(frpc.uid)) {
val error = Frpclib.runContent(frpc.uid, frpc.config)
if (!TextUtils.isEmpty(error)) {
Log.e(TAG, error)
}
}
} else if (action == "stop") {
if (Frpclib.isRunning(frpc.uid)) {
Frpclib.close(frpc.uid)
}
}
}
}
}
"httpserver" -> {
if (action == "start") {
context.startService(Intent(context, HttpService::class.java))
} else if (action == "stop") {
context.stopService(Intent(context, HttpService::class.java))
}
}
}
}
} }

View File

@ -48,9 +48,6 @@ class NotifyService : NotificationListenerService() {
//纯客户端模式 //纯客户端模式
if (SettingUtils.enablePureClientMode) return if (SettingUtils.enablePureClientMode) return
//总开关
if (!SettingUtils.enableAppNotify) return
//异常通知跳过 //异常通知跳过
if (sbn!!.notification == null) return if (sbn!!.notification == null) return
if (sbn.notification.extras == null) return if (sbn.notification.extras == null) return
@ -70,6 +67,9 @@ class NotifyService : NotificationListenerService() {
} }
} }
//总开关
if (!SettingUtils.enableAppNotify) return
//仅锁屏状态转发APP通知 //仅锁屏状态转发APP通知
if (SettingUtils.enableNotUserPresent && !ScreenUtils.isScreenLock()) return if (SettingUtils.enableNotUserPresent && !ScreenUtils.isScreenLock()) return

View File

@ -41,6 +41,9 @@ const val SP_ENABLE_CANCEL_APP_NOTIFY = "enable_cancel_app_notify"
const val SP_CANCEL_EXTRA_APP_NOTIFY = "cancel_extra_app_notify_list" const val SP_CANCEL_EXTRA_APP_NOTIFY = "cancel_extra_app_notify_list"
const val SP_ENABLE_NOT_USER_PRESENT = "enable_not_user_present" const val SP_ENABLE_NOT_USER_PRESENT = "enable_not_user_present"
const val SP_ENABLE_SMS_COMMAND = "enable_sms_command"
const val SP_SMS_COMMAND_SAFE_PHONE = "sms_command_safe_phone"
const val ENABLE_LOAD_APP_LIST = "enable_load_app_list" const val ENABLE_LOAD_APP_LIST = "enable_load_app_list"
const val ENABLE_LOAD_USER_APP_LIST = "enable_load_user_app_list" const val ENABLE_LOAD_USER_APP_LIST = "enable_load_user_app_list"
const val ENABLE_LOAD_SYSTEM_APP_LIST = "enable_load_system_app_list" const val ENABLE_LOAD_SYSTEM_APP_LIST = "enable_load_system_app_list"

View File

@ -180,6 +180,8 @@ class HttpServerUtils private constructor() {
cloneInfo.smsTemplate = SettingUtils.smsTemplate cloneInfo.smsTemplate = SettingUtils.smsTemplate
cloneInfo.enableHelpTip = SettingUtils.enableHelpTip cloneInfo.enableHelpTip = SettingUtils.enableHelpTip
cloneInfo.enablePureClientMode = SettingUtils.enablePureClientMode cloneInfo.enablePureClientMode = SettingUtils.enablePureClientMode
cloneInfo.enableSmsCommand = SettingUtils.enableSmsCommand
cloneInfo.smsCommandSafePhone = SettingUtils.smsCommandSafePhone
cloneInfo.senderList = Core.sender.all cloneInfo.senderList = Core.sender.all
cloneInfo.ruleList = Core.rule.all cloneInfo.ruleList = Core.rule.all
cloneInfo.frpcList = Core.frpc.all cloneInfo.frpcList = Core.frpc.all
@ -227,6 +229,8 @@ class HttpServerUtils private constructor() {
SettingUtils.smsTemplate = cloneInfo.smsTemplate.toString() SettingUtils.smsTemplate = cloneInfo.smsTemplate.toString()
SettingUtils.enableHelpTip = cloneInfo.enableHelpTip SettingUtils.enableHelpTip = cloneInfo.enableHelpTip
SettingUtils.enablePureClientMode = cloneInfo.enablePureClientMode SettingUtils.enablePureClientMode = cloneInfo.enablePureClientMode
SettingUtils.enableSmsCommand = cloneInfo.enableSmsCommand
SettingUtils.smsCommandSafePhone = cloneInfo.smsCommandSafePhone.toString()
//删除发送通道、转发规则、转发日志 //删除发送通道、转发规则、转发日志
Core.sender.deleteAll() Core.sender.deleteAll()
//发送通道 //发送通道

View File

@ -39,6 +39,10 @@ class SettingUtils private constructor() {
//是否转发应用通知 //是否转发应用通知
var enableAppNotify: Boolean by SharedPreference(SP_ENABLE_APP_NOTIFY, false) var enableAppNotify: Boolean by SharedPreference(SP_ENABLE_APP_NOTIFY, false)
//是否接受短信指令
var enableSmsCommand: Boolean by SharedPreference(SP_ENABLE_SMS_COMMAND, false)
var smsCommandSafePhone: String by SharedPreference(SP_SMS_COMMAND_SAFE_PHONE, "")
//是否转发应用通知——自动消除通知 //是否转发应用通知——自动消除通知
var enableCancelAppNotify: Boolean by SharedPreference(SP_ENABLE_CANCEL_APP_NOTIFY, false) var enableCancelAppNotify: Boolean by SharedPreference(SP_ENABLE_CANCEL_APP_NOTIFY, false)

View File

@ -17,6 +17,8 @@
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:baselineAligned="false"
android:gravity="center_vertical"
android:orientation="horizontal"> android:orientation="horizontal">
<LinearLayout <LinearLayout
@ -41,6 +43,19 @@
</LinearLayout> </LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_weight="1"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView <TextView
android:id="@+id/tv_name" android:id="@+id/tv_name"
android:layout_width="0dp" android:layout_width="0dp"
@ -48,8 +63,8 @@
android:layout_weight="1" android:layout_weight="1"
android:gravity="center_vertical" android:gravity="center_vertical"
android:lines="1" android:lines="1"
android:paddingLeft="16dp" android:paddingEnd="15dp"
android:paddingRight="16dp" /> tools:ignore="RtlSymmetry" />
<ImageView <ImageView
android:id="@+id/iv_play" android:id="@+id/iv_play"
@ -77,4 +92,33 @@
</LinearLayout> </LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
tools:ignore="UseCompoundDrawables">
<ImageView
android:id="@+id/iv_copy"
android:layout_width="@dimen/config_padding_18dp"
android:layout_height="@dimen/config_padding_18dp"
app:tint="@color/colorStart"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/tv_uid"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:lines="1"
android:textSize="11sp"
tools:ignore="SmallSp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</com.xuexiang.xui.widget.layout.XUIFrameLayout> </com.xuexiang.xui.widget.layout.XUIFrameLayout>

View File

@ -8,6 +8,7 @@
android:orientation="vertical" android:orientation="vertical"
tools:ignore="TooManyViews"> tools:ignore="TooManyViews">
<androidx.core.widget.NestedScrollView style="@style/ScrollViewStyle"> <androidx.core.widget.NestedScrollView style="@style/ScrollViewStyle">
<LinearLayout <LinearLayout
@ -240,11 +241,6 @@
<LinearLayout <LinearLayout
style="@style/settingBarStyle" style="@style/settingBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal"> android:orientation="horizontal">
@ -325,58 +321,69 @@
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/layout_app_list"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginTop="5dp"
android:layout_marginEnd="5dp"
android:gravity="center_vertical" android:gravity="center_vertical"
android:orientation="vertical" android:orientation="horizontal">
android:paddingEnd="10dp"
android:visibility="gone"
tools:ignore="RtlSymmetry">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/extra_app"
android:textSize="12sp"
android:textStyle="bold" />
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
android:id="@+id/et_app_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/extra_app_hint"
android:inputType="textMultiLine"
app:met_clearButton="true" />
<LinearLayout
android:id="@+id/layout_sp_app"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:visibility="gone">
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/choose_app" android:text="@string/extra_function"
android:textSize="12sp"
android:textStyle="bold" /> android:textStyle="bold" />
<com.xuexiang.xui.widget.spinner.editspinner.EditSpinner <TextView
android:id="@+id/sp_app" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:text="@string/extra_function_tips"
android:textSize="10sp"
tools:ignore="SmallSp" />
</LinearLayout>
<LinearLayout
style="@style/settingBarStyle"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="5dp" android:gravity="center_vertical">
app:es_hint="@string/choose_app_hint"
app:es_maxLength="20" <LinearLayout
app:es_maxLine="1" /> android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/sms_command"
android:textStyle="bold"
tools:ignore="RelativeOverlap" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/sms_command_tips"
android:textSize="9sp"
tools:ignore="SmallSp" />
<com.xuexiang.xui.widget.edittext.ClearEditText
android:id="@+id/et_safe_phone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/safe_phone_tips"
android:visibility="gone" />
</LinearLayout> </LinearLayout>
</LinearLayout> <com.xuexiang.xui.widget.button.switchbutton.SwitchButton
android:id="@+id/sb_enable_sms_command"
style="@style/SwitchButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout> </LinearLayout>
@ -459,6 +466,58 @@
</LinearLayout> </LinearLayout>
<LinearLayout
android:id="@+id/layout_app_list"
style="@style/settingBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/extra_app"
android:textStyle="bold"
tools:ignore="RelativeOverlap" />
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
android:id="@+id/et_app_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/extra_app_hint"
android:inputType="textMultiLine"
app:met_clearButton="true" />
<LinearLayout
android:id="@+id/layout_sp_app"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:visibility="gone">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/choose_app"
android:textSize="12sp"
android:textStyle="bold" />
<com.xuexiang.xui.widget.spinner.editspinner.EditSpinner
android:id="@+id/sp_app"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
app:es_hint="@string/choose_app_hint"
app:es_maxLength="20"
app:es_maxLine="1" />
</LinearLayout>
</LinearLayout>
<LinearLayout <LinearLayout
style="@style/settingBarStyle" style="@style/settingBarStyle"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -353,6 +353,10 @@
<string name="filtering_duplicate_messages_tips">0=disabled, judge duplicate: type+source+content</string> <string name="filtering_duplicate_messages_tips">0=disabled, judge duplicate: type+source+content</string>
<string name="forward_sms">Forward Sms</string> <string name="forward_sms">Forward Sms</string>
<string name="forward_sms_tips">Main switch, requires permissions to read and sned SMS messages, especially verification SMS texts.</string> <string name="forward_sms_tips">Main switch, requires permissions to read and sned SMS messages, especially verification SMS texts.</string>
<string name="sms_command">Sms Command</string>
<string name="sms_command_tips">Open the HttpServer or FRPC by the SMS command</string>
<string name="safe_phone">Safe Phone</string>
<string name="safe_phone_tips">Only handle requests from specified phones</string>
<string name="forward_missed_calls">Forward Calls Log</string> <string name="forward_missed_calls">Forward Calls Log</string>
<string name="forward_missed_calls_tips">Main switch, requires permissions to read call log and contacts.</string> <string name="forward_missed_calls_tips">Main switch, requires permissions to read call log and contacts.</string>
<string name="forward_app_notify">Forward App Notify</string> <string name="forward_app_notify">Forward App Notify</string>
@ -524,6 +528,8 @@
<string name="todo">TODO</string> <string name="todo">TODO</string>
<string name="forwarding_function">Forwarding Function</string> <string name="forwarding_function">Forwarding Function</string>
<string name="forwarding_function_tips">Main switch: Enable the forwarding function as required</string> <string name="forwarding_function_tips">Main switch: Enable the forwarding function as required</string>
<string name="extra_function">Extra Function</string>
<string name="extra_function_tips">Enable the extra function as required</string>
<string name="call_date">Call date: </string> <string name="call_date">Call date: </string>
<string name="call_duration">Call duration: </string> <string name="call_duration">Call duration: </string>
<string name="ring_duration">Ring duration: </string> <string name="ring_duration">Ring duration: </string>

View File

@ -354,6 +354,10 @@
<string name="filtering_duplicate_messages_tips">0=禁用,判断重复:类型+来源+内容</string> <string name="filtering_duplicate_messages_tips">0=禁用,判断重复:类型+来源+内容</string>
<string name="forward_sms">转发短信广播</string> <string name="forward_sms">转发短信广播</string>
<string name="forward_sms_tips">请授予读取短信、通知类短信、发送短信等权限,关闭验证码保护</string> <string name="forward_sms_tips">请授予读取短信、通知类短信、发送短信等权限,关闭验证码保护</string>
<string name="sms_command">短信指令</string>
<string name="sms_command_tips">根据短信指令开关对应功能指令格式smsf#功能名#动作名</string>
<string name="safe_phone">安全手机</string>
<string name="safe_phone_tips">仅处理指定手机请求,多个手机以逗号分隔</string>
<string name="forward_missed_calls">转发通话记录</string> <string name="forward_missed_calls">转发通话记录</string>
<string name="forward_missed_calls_tips">请授予读取通话记录、联系人等权限,并选择转发类型,再开启</string> <string name="forward_missed_calls_tips">请授予读取通话记录、联系人等权限,并选择转发类型,再开启</string>
<string name="forward_app_notify">转发应用通知</string> <string name="forward_app_notify">转发应用通知</string>
@ -525,6 +529,8 @@
<string name="todo">TODO</string> <string name="todo">TODO</string>
<string name="forwarding_function">转发功能</string> <string name="forwarding_function">转发功能</string>
<string name="forwarding_function_tips">总开关,请根据实际需要,启用对应的转发功能</string> <string name="forwarding_function_tips">总开关,请根据实际需要,启用对应的转发功能</string>
<string name="extra_function">增强功能</string>
<string name="extra_function_tips">请根据实际需要,启用对应的增强设置</string>
<string name="call_date">通话时间:</string> <string name="call_date">通话时间:</string>
<string name="call_duration">通话时长:</string> <string name="call_duration">通话时长:</string>
<string name="ring_duration">响铃时长:</string> <string name="ring_duration">响铃时长:</string>
@ -544,11 +550,11 @@
<string name="httpserver">被动接收本地 HttpServer</string> <string name="httpserver">被动接收本地 HttpServer</string>
<string name="httpserver_tips">WiFi网络下可用启动后局域网内其他机器可直接调用本机接口</string> <string name="httpserver_tips">WiFi网络下可用启动后局域网内其他机器可直接调用本机接口</string>
<string name="network_state_monitor">网络状态监控</string> <string name="network_state_monitor">网络状态监控</string>
<string name="network_state_monitor_tips">【注意】需要手动创建APP转发规则包名77777777</string> <string name="network_state_monitor_tips">需要手动创建APP转发规则包名77777777</string>
<string name="network_state_change_remind">网络状态改变提醒</string> <string name="network_state_change_remind">网络状态改变提醒</string>
<string name="network_state_change_remind_tips">网络状态改变(连接方式/IP变化)时发出通知</string> <string name="network_state_change_remind_tips">网络状态改变(连接方式/IP变化)时发出通知</string>
<string name="battery_monitor">电池监控</string> <string name="battery_monitor">电池监控</string>
<string name="battery_monitor_tips">【注意】需要手动创建APP转发规则包名88888888</string> <string name="battery_monitor_tips">需要手动创建APP转发规则包名88888888</string>
<string name="keep_alive">保活措施</string> <string name="keep_alive">保活措施</string>
<string name="keep_alive_tips">建议开启前三项授权或设置不要禁用通知栏避免APP被杀</string> <string name="keep_alive_tips">建议开启前三项授权或设置不要禁用通知栏避免APP被杀</string>
<string name="custom_settings">个性设置</string> <string name="custom_settings">个性设置</string>