From e03a9b8198d9237a12862701d26f996b67b65ffb Mon Sep 17 00:00:00 2001 From: pppscn <35696959@qq.com> Date: Tue, 12 Dec 2023 13:42:04 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9A=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=C2=B7=E5=BF=AB=E6=8D=B7=E6=8C=87=E4=BB=A4=20?= =?UTF-8?q?=E2=80=94=E2=80=94=20=E9=80=9A=E9=81=93=E6=8E=A8=E9=80=81?= =?UTF-8?q?=E5=8A=A8=E4=BD=9C=EF=BC=88=E5=BC=80=E5=8F=91=E4=B8=AD=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fragment/action/NotificationFragment.kt | 519 +++--------------- .../fragment/action/SendSmsFragment.kt | 2 + .../sms/forwarder/workers/ActionWorker.kt | 27 +- .../sms/forwarder/workers/CronWorker.kt | 12 +- .../res/layout/adapter_task_setting_item.xml | 3 + .../fragment_tasks_action_notification.xml | 355 ++++++++++++ 6 files changed, 475 insertions(+), 443 deletions(-) create mode 100644 app/src/main/res/layout/fragment_tasks_action_notification.xml diff --git a/app/src/main/java/com/idormy/sms/forwarder/fragment/action/NotificationFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/fragment/action/NotificationFragment.kt index c2cab18c..a1ab4839 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/fragment/action/NotificationFragment.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/fragment/action/NotificationFragment.kt @@ -1,46 +1,34 @@ package com.idormy.sms.forwarder.fragment.action import android.annotation.SuppressLint -import android.os.Looper +import android.content.Intent import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.* -import androidx.fragment.app.viewModels -import androidx.lifecycle.Observer -import androidx.work.OneTimeWorkRequestBuilder -import androidx.work.WorkManager -import com.idormy.sms.forwarder.App +import com.google.gson.Gson import com.idormy.sms.forwarder.R -import com.idormy.sms.forwarder.adapter.spinner.AppListAdapterItem -import com.idormy.sms.forwarder.adapter.spinner.AppListSpinnerAdapter import com.idormy.sms.forwarder.adapter.spinner.SenderAdapterItem import com.idormy.sms.forwarder.adapter.spinner.SenderSpinnerAdapter import com.idormy.sms.forwarder.core.BaseFragment import com.idormy.sms.forwarder.database.AppDatabase import com.idormy.sms.forwarder.database.entity.Rule import com.idormy.sms.forwarder.database.entity.Sender -import com.idormy.sms.forwarder.database.viewmodel.BaseViewModelFactory -import com.idormy.sms.forwarder.database.viewmodel.RuleViewModel -import com.idormy.sms.forwarder.databinding.FragmentRulesEditBinding +import com.idormy.sms.forwarder.databinding.FragmentTasksActionNotificationBinding import com.idormy.sms.forwarder.entity.MsgInfo import com.idormy.sms.forwarder.utils.* -import com.idormy.sms.forwarder.workers.LoadAppListWorker import com.jeremyliao.liveeventbus.LiveEventBus import com.xuexiang.xaop.annotation.SingleClick import com.xuexiang.xpage.annotation.Page import com.xuexiang.xrouter.annotation.AutoWired import com.xuexiang.xrouter.launcher.XRouter import com.xuexiang.xrouter.utils.TextUtils +import com.xuexiang.xui.utils.CountDownButtonHelper import com.xuexiang.xui.utils.ResUtils import com.xuexiang.xui.widget.actionbar.TitleBar -import com.xuexiang.xui.widget.dialog.materialdialog.DialogAction -import com.xuexiang.xui.widget.dialog.materialdialog.MaterialDialog import com.xuexiang.xui.widget.picker.widget.builder.OptionsPickerBuilder import com.xuexiang.xui.widget.picker.widget.listener.OnOptionsSelectListener -import com.xuexiang.xui.widget.spinner.materialspinner.MaterialSpinner -import com.xuexiang.xutil.XUtil import io.reactivex.SingleObserver import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable @@ -50,14 +38,15 @@ import java.util.* @Page(name = "Notification") @Suppress("PrivatePropertyName", "DEPRECATION") -class NotificationFragment : BaseFragment(), View.OnClickListener, CompoundButton.OnCheckedChangeListener { +class NotificationFragment : BaseFragment(), View.OnClickListener, CompoundButton.OnCheckedChangeListener { private val TAG: String = NotificationFragment::class.java.simpleName var titleBar: TitleBar? = null - private val viewModel by viewModels { BaseViewModelFactory(context) } + private var mCountDownHelper: CountDownButtonHelper? = null - var callType = 1 - var callTypeIndex = 0 + @JvmField + @AutoWired(name = KEY_EVENT_DATA_ACTION) + var eventData: String? = null //免打扰(禁用转发)时间段 private val mTimeOption = DataProvider.timePeriodOption @@ -74,25 +63,8 @@ class NotificationFragment : BaseFragment(), View.OnC private val senderSpinnerList = ArrayList() private lateinit var senderSpinnerAdapter: SenderSpinnerAdapter<*> - //已安装App信息列表 - private val appListSpinnerList = ArrayList() - private lateinit var appListSpinnerAdapter: AppListSpinnerAdapter<*> - private val appListObserver = Observer { it: String -> - Log.d(TAG, "EVENT_LOAD_APP_LIST: $it") - initAppSpinner() - } - - @JvmField - @AutoWired(name = KEY_RULE_ID) - var ruleId: Long = 0 - - @JvmField - @AutoWired(name = KEY_RULE_TYPE) - var ruleType: String = "sms" - - @JvmField - @AutoWired(name = KEY_RULE_CLONE) - var isClone: Boolean = false + private var ruleId: Long = 0 + private var ruleType: String = "app" override fun initArgs() { XRouter.getInstance().inject(this) @@ -101,8 +73,8 @@ class NotificationFragment : BaseFragment(), View.OnC override fun viewBindingInflate( inflater: LayoutInflater, container: ViewGroup, - ): FragmentRulesEditBinding { - return FragmentRulesEditBinding.inflate(inflater, container, false) + ): FragmentTasksActionNotificationBinding { + return FragmentTasksActionNotificationBinding.inflate(inflater, container, false) } override fun initTitle(): TitleBar? { @@ -115,74 +87,46 @@ class NotificationFragment : BaseFragment(), View.OnC * 初始化控件 */ override fun initViews() { - when (ruleType) { - "app" -> { - titleBar?.setTitle(R.string.app_rule) - binding!!.layoutSimSlot.visibility = View.GONE - binding!!.rbPhone.visibility = View.GONE - binding!!.rbCallType.visibility = View.GONE - binding!!.rbContent.visibility = View.GONE - binding!!.tvMuRuleTips.setText(R.string.mu_rule_app_tips) - binding!!.btInsertExtra.visibility = View.GONE - binding!!.btInsertSender.visibility = View.GONE - binding!!.btInsertContent.visibility = View.GONE - //初始化APP下拉列表 - initAppSpinner() - //监听已安装App信息列表加载完成事件 - LiveEventBus.get(EVENT_LOAD_APP_LIST, String::class.java).observeStickyForever(appListObserver) + //测试按钮增加倒计时,避免重复点击 + 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) } - "call" -> { - titleBar?.setTitle(R.string.call_rule) - binding!!.rbContent.visibility = View.GONE - binding!!.rbPackageName.visibility = View.GONE - binding!!.rbUid.visibility = View.GONE - binding!!.rbInformContent.visibility = View.GONE - //binding!!.rbMultiMatch.visibility = View.GONE - binding!!.tvMuRuleTips.setText(R.string.mu_rule_call_tips) - binding!!.btInsertContent.visibility = View.GONE - binding!!.btInsertSenderApp.visibility = View.GONE - binding!!.btInsertUid.visibility = View.GONE - binding!!.btInsertTitleApp.visibility = View.GONE - binding!!.btInsertContentApp.visibility = View.GONE + override fun onFinished() { + binding!!.btnTest.text = getString(R.string.test) + } + }) - //通话类型:1.来电挂机 2.去电挂机 3.未接来电 4.来电提醒 5.来电接通 6.去电拨出 - binding!!.spCallType.setItems(CALL_TYPE_MAP.values.toList()) - binding!!.spCallType.setOnItemSelectedListener { _: MaterialSpinner?, _: Int, _: Long, item: Any -> - CALL_TYPE_MAP.forEach { - if (it.value == item) callType = it.key.toInt() - } - } - binding!!.spCallType.setOnNothingSelectedListener { - callType = 1 - callTypeIndex = 0 - binding!!.spCallType.selectedIndex = callTypeIndex - } - binding!!.spCallType.selectedIndex = callTypeIndex + Log.d(TAG, "initViews eventData:$eventData") + if (eventData != null) { + val settingVo = Gson().fromJson(eventData, Rule::class.java) + Log.d(TAG, "initViews settingVo:$settingVo") + + Log.d(TAG, settingVo.senderList.toString()) + settingVo.senderList.forEach { + senderId = it.id + senderListSelected.add(it) } - else -> { - titleBar?.setTitle(R.string.sms_rule) - binding!!.rbCallType.visibility = View.GONE - binding!!.rbPackageName.visibility = View.GONE - binding!!.rbUid.visibility = View.GONE - binding!!.rbInformContent.visibility = View.GONE - binding!!.btInsertSenderApp.visibility = View.GONE - binding!!.btInsertUid.visibility = View.GONE - binding!!.btInsertTitleApp.visibility = View.GONE - binding!!.btInsertContentApp.visibility = View.GONE + binding!!.rgSenderLogic.check(settingVo.getSenderLogicCheckId()) + if (!TextUtils.isEmpty(settingVo.smsTemplate.trim())) { + binding!!.sbSmsTemplate.isChecked = true + binding!!.layoutSmsTemplate.visibility = View.VISIBLE + binding!!.etSmsTemplate.setText(settingVo.smsTemplate.trim()) } + if (!TextUtils.isEmpty(settingVo.regexReplace.trim())) { + binding!!.sbRegexReplace.isChecked = true + binding!!.layoutRegexReplace.visibility = View.VISIBLE + binding!!.etRegexReplace.setText(settingVo.regexReplace.trim()) + } + silentPeriodStart = settingVo.silentPeriodStart + silentPeriodEnd = settingVo.silentPeriodEnd } - if (ruleId <= 0) { //新增 - titleBar?.setSubTitle(getString(R.string.add_rule)) - binding!!.btnDel.setText(R.string.discard) - initSenderSpinner() - } else { //编辑 & 克隆 - binding!!.btnDel.setText(R.string.del) - initForm() - } - + //初始化发送通道下拉框 + initSenderSpinner() } override fun initListeners() { @@ -200,64 +144,8 @@ class NotificationFragment : BaseFragment(), View.OnC binding!!.btnDel.setOnClickListener(this) binding!!.btnSave.setOnClickListener(this) - binding!!.sbStatus.setOnCheckedChangeListener(this) binding!!.sbSmsTemplate.setOnCheckedChangeListener(this) binding!!.sbRegexReplace.setOnCheckedChangeListener(this) - - binding!!.rgFiled.setOnCheckedChangeListener { _: RadioGroup?, checkedId: Int -> - if (ruleType == "app" && appListSpinnerList.isNotEmpty()) { - binding!!.layoutAppList.visibility = if (checkedId == R.id.rb_inform_content) View.GONE else View.VISIBLE - } - when (checkedId) { - R.id.rb_transpond_all -> { - binding!!.rgCheck.check(R.id.rb_is) - binding!!.spCallType.visibility = View.GONE - binding!!.tvMuRuleTips.visibility = View.GONE - binding!!.layoutMatchType.visibility = View.GONE - binding!!.layoutMatchValue.visibility = View.GONE - } - - R.id.rb_multi_match -> { - binding!!.rgCheck.check(R.id.rb_is) - binding!!.spCallType.visibility = View.GONE - binding!!.tvMuRuleTips.visibility = View.VISIBLE - binding!!.layoutMatchType.visibility = View.GONE - binding!!.layoutMatchValue.visibility = View.VISIBLE - binding!!.etValue.visibility = View.VISIBLE - } - - R.id.rb_call_type -> { - binding!!.rgCheck.check(R.id.rb_is) - binding!!.tvMuRuleTips.visibility = View.GONE - binding!!.layoutMatchType.visibility = View.GONE - binding!!.layoutMatchValue.visibility = View.VISIBLE - binding!!.etValue.visibility = View.GONE - binding!!.spCallType.visibility = View.VISIBLE - } - - else -> { - binding!!.spCallType.visibility = View.GONE - binding!!.tvMuRuleTips.visibility = View.GONE - binding!!.layoutMatchType.visibility = View.VISIBLE - binding!!.layoutMatchValue.visibility = View.VISIBLE - binding!!.etValue.visibility = View.VISIBLE - } - } - } - - binding!!.rgCheck.setOnCheckedChangeListener { group: RadioGroup?, checkedId: Int -> - if (group != null && checkedId > 0) { - binding!!.rgCheck2.clearCheck() - group.check(checkedId) - } - } - - binding!!.rgCheck2.setOnCheckedChangeListener { group: RadioGroup?, checkedId: Int -> - if (group != null && checkedId > 0) { - binding!!.rgCheck.clearCheck() - group.check(checkedId) - } - } } override fun onCheckedChanged(buttonView: CompoundButton?, isChecked: Boolean) { @@ -353,31 +241,46 @@ class NotificationFragment : BaseFragment(), View.OnC } R.id.btn_test -> { - val ruleNew = checkForm() - testRule(ruleNew) + val settingVo = checkSetting() + val from = "测试号码" + val content = "测试内容" + val simInfo = "SIM1_123456789" + val msgInfo = MsgInfo(ruleType, from, content, Date(), simInfo) + if (!settingVo.checkMsg(msgInfo)) { + throw Exception(getString(R.string.unmatched_rule)) + } + + Thread { + try { + SendUtils.sendMsgSender(msgInfo, settingVo) + } catch (e: Exception) { + e.printStackTrace() + LiveEventBus.get(EVENT_TOAST_ERROR, String::class.java).post(e.message.toString()) + } + }.start() return } R.id.btn_del -> { - if (ruleId <= 0 || isClone) { - popToBack() - return - } - - MaterialDialog.Builder(requireContext()).title(R.string.delete_rule_title).content(R.string.delete_rule_tips).positiveText(R.string.lab_yes).negativeText(R.string.lab_no).onPositive { _: MaterialDialog?, _: DialogAction? -> - viewModel.delete(ruleId) - XToastUtils.success(R.string.delete_rule_toast) - popToBack() - }.show() + popToBack() return } R.id.btn_save -> { - val ruleNew = checkForm() - if (isClone) ruleNew.id = 0 - Log.d(TAG, ruleNew.toString()) - viewModel.insertOrUpdate(ruleNew) - XToastUtils.success(R.string.tipSaveSuccess) + val settingVo = checkSetting() + var description = getString(R.string.select_sender) + ": " + description += settingVo.senderList.joinToString(",") { it.name } + if (settingVo.senderList.size > 1) { + description += "; " + getString(R.string.sender_logic) + ": " + when (settingVo.senderLogic) { + SENDER_LOGIC_UNTIL_FAIL -> getString(R.string.sender_logic_until_fail) + SENDER_LOGIC_UNTIL_SUCCESS -> getString(R.string.sender_logic_until_success) + else -> getString(R.string.sender_logic_all) + } + } + val intent = Intent() + intent.putExtra(KEY_BACK_DESCRIPTION_ACTION, description) + intent.putExtra(KEY_BACK_DATA_ACTION, Gson().toJson(settingVo)) + setFragmentResult(TASK_ACTION_NOTIFICATION, intent) popToBack() return } @@ -511,148 +414,23 @@ class NotificationFragment : BaseFragment(), View.OnC } } - //初始化APP下拉列表 - private fun initAppSpinner() { - if (ruleType != "app") return - - //未开启异步获取已安装App信息开关时,规则编辑不显示已安装APP下拉框 - if (!SettingUtils.enableLoadUserAppList && !SettingUtils.enableLoadSystemAppList) return - - if (App.UserAppList.isEmpty() && App.SystemAppList.isEmpty()) { - XToastUtils.info(getString(R.string.loading_app_list)) - val request = OneTimeWorkRequestBuilder().build() - WorkManager.getInstance(XUtil.getContext()).enqueue(request) - return - } - - appListSpinnerList.clear() - if (SettingUtils.enableLoadUserAppList) { - for (appInfo in App.UserAppList) { - if (TextUtils.isEmpty(appInfo.packageName)) continue - appListSpinnerList.add(AppListAdapterItem(appInfo.name, appInfo.icon, appInfo.packageName)) - } - } - if (SettingUtils.enableLoadSystemAppList) { - for (appInfo in App.SystemAppList) { - if (TextUtils.isEmpty(appInfo.packageName)) continue - appListSpinnerList.add(AppListAdapterItem(appInfo.name, appInfo.icon, appInfo.packageName)) - } - } - - //列表为空也不显示下拉框 - if (appListSpinnerList.isEmpty()) return - - appListSpinnerAdapter = AppListSpinnerAdapter(appListSpinnerList).setIsFilterKey(true).setFilterColor("#EF5362").setBackgroundSelector(R.drawable.selector_custom_spinner_bg) - binding!!.spApp.setAdapter(appListSpinnerAdapter) - binding!!.spApp.setOnItemClickListener { _: AdapterView<*>, _: View, position: Int, _: Long -> - try { - val appInfo = appListSpinnerAdapter.getItemSource(position) as AppListAdapterItem - CommonUtils.insertOrReplaceText2Cursor(binding!!.etValue, appInfo.packageName.toString()) - } catch (e: Exception) { - XToastUtils.error(e.message.toString()) - } - } - binding!!.layoutAppList.visibility = View.VISIBLE - - } - - //初始化表单 - private fun initForm() { - AppDatabase.getInstance(requireContext()).ruleDao().get(ruleId).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(object : SingleObserver { - override fun onSubscribe(d: Disposable) {} - - override fun onError(e: Throwable) { - e.printStackTrace() - } - - override fun onSuccess(rule: Rule) { - Log.d(TAG, rule.senderList.toString()) - rule.senderList.forEach { - senderId = it.id - senderListSelected.add(it) - } - - if (isClone) { - titleBar?.setSubTitle(getString(R.string.clone_rule)) - binding!!.btnDel.setText(R.string.discard) - } else { - titleBar?.setSubTitle(getString(R.string.edit_rule)) - } - Log.d(TAG, rule.toString()) - - binding!!.rgSenderLogic.check(rule.getSenderLogicCheckId()) - binding!!.rgSimSlot.check(rule.getSimSlotCheckId()) - binding!!.rgFiled.check(rule.getFiledCheckId()) - val checkId = rule.getCheckCheckId() - if (checkId == R.id.rb_is || checkId == R.id.rb_contain || checkId == R.id.rb_not_contain) { - binding!!.rgCheck.check(checkId) - } else { - binding!!.rgCheck2.check(checkId) - } - binding!!.etValue.setText(rule.value) - if (ruleType == "call" && rule.filed == FILED_CALL_TYPE) { - callType = rule.value.toInt() - callTypeIndex = callType - 1 - binding!!.spCallType.selectedIndex = callTypeIndex - } - binding!!.sbSmsTemplate.isChecked = !TextUtils.isEmpty(rule.smsTemplate.trim()) - binding!!.etSmsTemplate.setText(rule.smsTemplate.trim()) - binding!!.sbRegexReplace.isChecked = !TextUtils.isEmpty(rule.regexReplace.trim()) - binding!!.etRegexReplace.setText(rule.regexReplace.trim()) - binding!!.sbStatus.isChecked = rule.statusChecked - silentPeriodStart = rule.silentPeriodStart - silentPeriodEnd = rule.silentPeriodEnd - //初始化发送通道下拉框 - initSenderSpinner() - } - }) - } - //提交前检查表单 - private fun checkForm(): Rule { + private fun checkSetting(): Rule { if (senderListSelected.isEmpty() || senderId == 0L) { throw Exception(getString(R.string.new_sender_first)) } - val filed = when (binding!!.rgFiled.checkedRadioButtonId) { - R.id.rb_content -> FILED_MSG_CONTENT - R.id.rb_phone -> FILED_PHONE_NUM - R.id.rb_call_type -> FILED_CALL_TYPE - R.id.rb_package_name -> FILED_PACKAGE_NAME - R.id.rb_uid -> FILED_UID - R.id.rb_inform_content -> FILED_INFORM_CONTENT - R.id.rb_multi_match -> FILED_MULTI_MATCH - else -> FILED_TRANSPOND_ALL - } - val check = when (kotlin.math.max(binding!!.rgCheck.checkedRadioButtonId, binding!!.rgCheck2.checkedRadioButtonId)) { - R.id.rb_contain -> CHECK_CONTAIN - R.id.rb_not_contain -> CHECK_NOT_CONTAIN - R.id.rb_start_with -> CHECK_START_WITH - R.id.rb_end_with -> CHECK_END_WITH - R.id.rb_regex -> CHECK_REGEX - else -> CHECK_IS - } - var value = binding!!.etValue.text.toString().trim() - if (FILED_CALL_TYPE == filed) { - value = callType.toString() - if (callType !in 1..6) { - throw Exception(getString(R.string.invalid_call_type)) - } - } else if (FILED_TRANSPOND_ALL != filed && TextUtils.isEmpty(value)) { - throw Exception(getString(R.string.invalid_match_value)) - } - if (FILED_MULTI_MATCH == filed) { - val lineError = checkMultiMatch(value) - if (lineError > 0) { - throw Exception(String.format(getString(R.string.invalid_multi_match), lineError)) - } - } + val filed = FILED_TRANSPOND_ALL + val check = CHECK_IS + val value = "" val smsTemplate = binding!!.etSmsTemplate.text.toString().trim() val regexReplace = binding!!.etRegexReplace.text.toString().trim() val lineNum = checkRegexReplace(regexReplace) if (lineNum > 0) { throw Exception(String.format(getString(R.string.invalid_regex_replace), lineNum)) } + val simSlot = CHECK_SIM_SLOT_ALL + val status = STATUS_ON val senderLogic = when (binding!!.rgSenderLogic.checkedRadioButtonId) { R.id.rb_sender_logic_until_fail -> SENDER_LOGIC_UNTIL_FAIL @@ -660,15 +438,6 @@ class NotificationFragment : BaseFragment(), View.OnC else -> SENDER_LOGIC_ALL } - val simSlot = when (binding!!.rgSimSlot.checkedRadioButtonId) { - R.id.rb_sim_slot_1 -> CHECK_SIM_SLOT_1 - R.id.rb_sim_slot_2 -> CHECK_SIM_SLOT_2 - else -> CHECK_SIM_SLOT_ALL - } - val status = if (binding!!.sbStatus.isChecked) STATUS_ON else STATUS_OFF - //if (status == STATUS_OFF) { - // throw Exception(getString(R.string.invalid_rule_status)) - //} return Rule( ruleId, ruleType, @@ -688,23 +457,6 @@ class NotificationFragment : BaseFragment(), View.OnC ) } - //检查多重匹配规则是否正确 - private fun checkMultiMatch(ruleStr: String?): Int { - if (TextUtils.isEmpty(ruleStr)) return 0 - - //Log.d(TAG, getString(R.string.regex_multi_match)) - val regex = Regex(pattern = getString(R.string.regex_multi_match)) - var lineNum = 1 - val lineArray = ruleStr?.split("\\n".toRegex())?.toTypedArray() - for (line in lineArray!!) { - Log.d(TAG, line) - if (!line.matches(regex)) return lineNum - lineNum++ - } - - return 0 - } - //检查正则替换填写是否正确 private fun checkRegexReplace(regexReplace: String?): Int { if (TextUtils.isEmpty(regexReplace)) return 0 @@ -719,109 +471,4 @@ class NotificationFragment : BaseFragment(), View.OnC return 0 } - private fun testRule(rule: Rule) { - val dialogTest = View.inflate(requireContext(), R.layout.dialog_rule_test, null) - val tvSimSlot = dialogTest.findViewById(R.id.tv_sim_slot) - val rgSimSlot = dialogTest.findViewById(R.id.rg_sim_slot) - val tvFrom = dialogTest.findViewById(R.id.tv_from) - val etFrom = dialogTest.findViewById(R.id.et_from) - val tvTitle = dialogTest.findViewById(R.id.tv_title) - val etTitle = dialogTest.findViewById(R.id.et_title) - val tvContent = dialogTest.findViewById(R.id.tv_content) - val etContent = dialogTest.findViewById(R.id.et_content) - //通话类型 - val tvCallType = dialogTest.findViewById(R.id.tv_call_type) - val spCallType = dialogTest.findViewById(R.id.sp_call_type) - var callTypeTest = callType - var callTypeIndexTest = callTypeIndex - - if ("app" == ruleType) { - tvSimSlot.visibility = View.GONE - rgSimSlot.visibility = View.GONE - tvTitle.visibility = View.VISIBLE - etTitle.visibility = View.VISIBLE - tvFrom.setText(R.string.test_package_name) - tvContent.setText(R.string.test_inform_content) - tvCallType.visibility = View.GONE - spCallType.visibility = View.GONE - } else if ("call" == ruleType) { - tvContent.visibility = View.GONE - etContent.visibility = View.GONE - tvCallType.visibility = View.VISIBLE - spCallType.visibility = View.VISIBLE - spCallType.setItems(CALL_TYPE_MAP.values.toList()) - spCallType.setOnItemSelectedListener { _: MaterialSpinner?, _: Int, _: Long, item: Any -> - CALL_TYPE_MAP.forEach { - if (it.value == item) callTypeTest = it.key.toInt() - } - } - spCallType.setOnNothingSelectedListener { - callTypeTest = callType - callTypeIndexTest = callTypeIndex - spCallType.selectedIndex = callTypeIndexTest - } - spCallType.selectedIndex = callTypeIndexTest - } - - MaterialDialog.Builder(requireContext()).iconRes(android.R.drawable.ic_dialog_email).title(R.string.rule_tester).customView(dialogTest, true).cancelable(false).autoDismiss(false).neutralText(R.string.action_back).neutralColor(ResUtils.getColors(R.color.darkGrey)).onNeutral { dialog: MaterialDialog?, _: DialogAction? -> - dialog?.dismiss() - }.positiveText(R.string.action_test).onPositive { _: MaterialDialog?, _: DialogAction? -> - try { - val simSlot = when (if (ruleType == "app") -1 else rgSimSlot.checkedRadioButtonId) { - R.id.rb_sim_slot_1 -> 0 - R.id.rb_sim_slot_2 -> 1 - else -> -1 - } - - val testSim = "SIM" + (simSlot + 1) - val ruleSim: String = rule.simSlot - if (ruleSim != "ALL" && ruleSim != testSim) { - throw Exception(getString(R.string.card_slot_does_not_match)) - } - - //获取卡槽信息 - val simInfo = when (simSlot) { - 0 -> "SIM1_" + SettingUtils.extraSim1 - 1 -> "SIM2_" + SettingUtils.extraSim2 - else -> etTitle.text.toString() - } - val subId = when (simSlot) { - 0 -> SettingUtils.subidSim1 - 1 -> SettingUtils.subidSim2 - else -> 0 - } - - val msg = StringBuilder() - if (ruleType == "call") { - val phoneNumber = etFrom.text.toString() - val contacts = PhoneUtils.getContactByNumber(phoneNumber) - val contactName = if (contacts.isNotEmpty()) contacts[0].name else ResUtils.getString(R.string.unknown_number) - msg.append(ResUtils.getString(R.string.contact)).append(contactName).append("\n") - msg.append(ResUtils.getString(R.string.mandatory_type)) - msg.append(CALL_TYPE_MAP[callType.toString()] ?: ResUtils.getString(R.string.unknown_call)) - } else { - msg.append(etContent.text.toString()) - } - - val msgInfo = MsgInfo(ruleType, etFrom.text.toString(), msg.toString(), Date(), simInfo, simSlot, subId, callTypeTest) - if (!rule.checkMsg(msgInfo)) { - throw Exception(getString(R.string.unmatched_rule)) - } - - Thread { - try { - SendUtils.sendMsgSender(msgInfo, rule) - } catch (e: Exception) { - e.printStackTrace() - if (Looper.myLooper() == null) Looper.prepare() - XToastUtils.error(e.message.toString()) - Looper.loop() - } - }.start() - - } catch (e: Exception) { - XToastUtils.error(e.message.toString()) - } - }.show() - } } \ No newline at end of file diff --git a/app/src/main/java/com/idormy/sms/forwarder/fragment/action/SendSmsFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/fragment/action/SendSmsFragment.kt index 3cf3bcbe..1401ad2b 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/fragment/action/SendSmsFragment.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/fragment/action/SendSmsFragment.kt @@ -24,6 +24,7 @@ import com.idormy.sms.forwarder.utils.EVENT_KEY_PHONE_NUMBERS import com.idormy.sms.forwarder.utils.EVENT_KEY_SIM_SLOT import com.idormy.sms.forwarder.utils.HttpServerUtils 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.PhoneUtils @@ -191,6 +192,7 @@ class SendSmsFragment : BaseFragment(), View R.id.btn_save -> { val settingVo = checkSetting() val intent = Intent() + intent.putExtra(KEY_BACK_DESCRIPTION_ACTION, description) intent.putExtra(KEY_BACK_DATA_ACTION, Gson().toJson(settingVo)) setFragmentResult(TASK_ACTION_SENDSMS, intent) popToBack() diff --git a/app/src/main/java/com/idormy/sms/forwarder/workers/ActionWorker.kt b/app/src/main/java/com/idormy/sms/forwarder/workers/ActionWorker.kt index 2c87714e..2f682352 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/workers/ActionWorker.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/workers/ActionWorker.kt @@ -10,9 +10,14 @@ 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.database.entity.Rule +import com.idormy.sms.forwarder.entity.MsgInfo import com.idormy.sms.forwarder.entity.task.SmsSetting 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.xuexiang.xui.utils.ResUtils import com.xuexiang.xutil.XUtil @@ -22,14 +27,16 @@ class ActionWorker(context: Context, params: WorkerParameters) : CoroutineWorker private val TAG: String = ActionWorker::class.java.simpleName override suspend fun doWork(): Result { - val taskId = inputData.getLong("taskId", -1L) - val actionType = inputData.getInt("actionType", -1) - val actionSetting = inputData.getString("actionSetting") - Log.d(TAG, "taskId: $taskId, actionSetting: $actionSetting") + 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) { Log.d(TAG, "taskId is -1L or actionSetting is null") return Result.failure() } + val msgInfo = Gson().fromJson(msgInfoJson, MsgInfo::class.java) when (actionType) { TASK_ACTION_SENDSMS -> { @@ -59,6 +66,18 @@ class ActionWorker(context: Context, params: WorkerParameters) : CoroutineWorker return Result.success() } + TASK_ACTION_NOTIFICATION -> { + return try { + val settingVo = Gson().fromJson(actionSetting, Rule::class.java) + //自动任务的不需要吐司或者更新日志,特殊处理 logId = -1,msgId = -1 + SendUtils.sendMsgSender(msgInfo, settingVo, 0, -1L, -1L) + Result.success() + } catch (e: Exception) { + e.printStackTrace() + Result.failure() + } + } + else -> { Log.d(TAG, "任务$taskId:action.type is $actionType") return Result.failure() diff --git a/app/src/main/java/com/idormy/sms/forwarder/workers/CronWorker.kt b/app/src/main/java/com/idormy/sms/forwarder/workers/CronWorker.kt index 8bad1a48..dc89184e 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/workers/CronWorker.kt +++ b/app/src/main/java/com/idormy/sms/forwarder/workers/CronWorker.kt @@ -10,8 +10,10 @@ 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.CronSetting import com.idormy.sms.forwarder.entity.task.TaskSetting +import com.idormy.sms.forwarder.utils.Worker import com.idormy.sms.forwarder.utils.task.CronJobScheduler import gatewayapps.crondroid.CronExpression import java.util.Date @@ -80,6 +82,9 @@ class CronWorker(context: Context, params: WorkerParameters) : CoroutineWorker(c return Result.success() } + //组装消息体 + val msgInfo = MsgInfo("task", task.name, task.description, Date(), task.name) + // TODO: 执行具体任务 val actionList = Gson().fromJson(task.actions, Array::class.java).toMutableList() if (actionList.isEmpty()) { @@ -88,9 +93,10 @@ class CronWorker(context: Context, params: WorkerParameters) : CoroutineWorker(c } for (action in actionList) { val actionData = Data.Builder() - .putLong("taskId", task.id) - .putInt("actionType", action.type) - .putString("actionSetting", action.setting) + .putLong(Worker.taskId, task.id) + .putInt(Worker.actionType, action.type) + .putString(Worker.actionSetting, action.setting) + .putString(Worker.sendMsgInfo, Gson().toJson(msgInfo)) .build() val actionRequest = OneTimeWorkRequestBuilder().setInputData(actionData).build() WorkManager.getInstance().enqueue(actionRequest) diff --git a/app/src/main/res/layout/adapter_task_setting_item.xml b/app/src/main/res/layout/adapter_task_setting_item.xml index 5c7d5ff1..ab369831 100644 --- a/app/src/main/res/layout/adapter_task_setting_item.xml +++ b/app/src/main/res/layout/adapter_task_setting_item.xml @@ -42,6 +42,9 @@ android:id="@+id/tv_description" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:ellipsize="end" + android:gravity="start" + android:maxLines="2" android:text="@string/add_action_tips" android:textSize="12sp" /> diff --git a/app/src/main/res/layout/fragment_tasks_action_notification.xml b/app/src/main/res/layout/fragment_tasks_action_notification.xml new file mode 100644 index 00000000..f27813a8 --- /dev/null +++ b/app/src/main/res/layout/fragment_tasks_action_notification.xml @@ -0,0 +1,355 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file