新增:自动消除额外APP通知 #232 #248

This commit is contained in:
pppscn 2023-02-05 15:29:56 +08:00
parent 04d8c9015a
commit 6ef83f131e
9 changed files with 350 additions and 185 deletions

View File

@ -37,10 +37,7 @@ import io.reactivex.SingleObserver
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.coroutines.*
import java.util.*
@Page(name = "转发规则·编辑器")
@ -411,6 +408,7 @@ class RulesEditFragment : BaseFragment<FragmentRulesEditBinding?>(), View.OnClic
}
//初始化APP下拉列表
@OptIn(DelicateCoroutinesApi::class)
private fun initAppSpinner() {
if (ruleType != "app") return

View File

@ -16,16 +16,15 @@ import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.CompoundButton
import android.widget.EditText
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.*
import androidx.annotation.RequiresApi
import com.hjq.permissions.OnPermissionCallback
import com.hjq.permissions.Permission
import com.hjq.permissions.XXPermissions
import com.idormy.sms.forwarder.App
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.core.BaseFragment
import com.idormy.sms.forwarder.databinding.FragmentSettingsBinding
import com.idormy.sms.forwarder.entity.SimInfo
@ -47,8 +46,10 @@ import com.xuexiang.xui.widget.picker.widget.builder.TimePickerBuilder
import com.xuexiang.xui.widget.picker.widget.listener.OnOptionsSelectListener
import com.xuexiang.xutil.XUtil
import com.xuexiang.xutil.XUtil.getPackageManager
import com.xuexiang.xutil.app.AppUtils
import com.xuexiang.xutil.app.AppUtils.getAppPackageName
import com.xuexiang.xutil.data.DateUtils
import kotlinx.coroutines.*
import java.util.*
@ -59,6 +60,10 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
val TAG: String = SettingsFragment::class.java.simpleName
private val mTimeOption = DataProvider.timePeriodOption
//已安装App信息列表
private val appListSpinnerList = ArrayList<AppListAdapterItem>()
private lateinit var appListSpinnerAdapter: AppListSpinnerAdapter<*>
override fun viewBindingInflate(
inflater: LayoutInflater,
container: ViewGroup,
@ -86,6 +91,8 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
switchEnableAppNotify(
binding!!.sbEnableAppNotify, binding!!.scbCancelAppNotify, binding!!.scbNotUserPresent
)
//设置自动消除额外APP通知
editExtraAppList(binding!!.etAppList)
//启动时异步获取已安装App信息
switchEnableLoadAppList(
binding!!.sbEnableLoadAppList, binding!!.scbLoadUserApp, binding!!.scbLoadSystemApp
@ -150,6 +157,9 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
//纯客户端模式
switchDirectlyToClient(binding!!.sbDirectlyToClient)
//初始化APP下拉列表
initAppSpinner()
}
override fun initListeners() {
@ -409,13 +419,17 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
fun switchEnableAppNotify(
sbEnableAppNotify: SwitchButton, scbCancelAppNotify: SmoothCheckBox, scbNotUserPresent: SmoothCheckBox
) {
val layoutOptionalAction: LinearLayout = binding!!.layoutOptionalAction
val isEnable: Boolean = SettingUtils.enableAppNotify
sbEnableAppNotify.isChecked = isEnable
val layoutOptionalAction: LinearLayout = binding!!.layoutOptionalAction
layoutOptionalAction.visibility = if (isEnable) View.VISIBLE else View.GONE
val layoutAppList: LinearLayout = binding!!.layoutAppList
layoutAppList.visibility = if (isEnable) View.VISIBLE else View.GONE
sbEnableAppNotify.setOnCheckedChangeListener { _: CompoundButton?, isChecked: Boolean ->
layoutOptionalAction.visibility = if (isChecked) View.VISIBLE else View.GONE
layoutAppList.visibility = if (isChecked) View.VISIBLE else View.GONE
SettingUtils.enableAppNotify = isChecked
if (isChecked) {
//检查权限是否获取
@ -454,7 +468,19 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
}
}
//启动时异步获取已安装App信息 (binding!!.sbEnableLoadAppList, binding!!.scbLoadUserApp, binding!!.scbLoadSystemApp)
//设置自动消除额外APP通知
private fun editExtraAppList(textAppList: EditText) {
textAppList.setText(SettingUtils.cancelExtraAppNotify)
textAppList.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.cancelExtraAppNotify = textAppList.text.toString().trim().removeSuffix("\n")
}
})
}
//启动时异步获取已安装App信息
@SuppressLint("UseSwitchCompatOrMaterialCode")
fun switchEnableLoadAppList(
sbEnableLoadAppList: SwitchButton, scbLoadUserApp: SmoothCheckBox, scbLoadSystemApp: SmoothCheckBox
@ -1059,4 +1085,69 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
}
}
//初始化APP下拉列表
@OptIn(DelicateCoroutinesApi::class)
private fun initAppSpinner() {
if (!SettingUtils.enableAppNotify) return
//未开启异步获取已安装App信息开关时规则编辑不显示已安装APP下拉框
if (!SettingUtils.enableLoadUserAppList && !SettingUtils.enableLoadSystemAppList) return
val get = GlobalScope.async(Dispatchers.IO) {
if ((SettingUtils.enableLoadUserAppList && App.UserAppList.isEmpty()) || (SettingUtils.enableLoadSystemAppList && App.SystemAppList.isEmpty())) {
App.UserAppList.clear()
App.SystemAppList.clear()
val appInfoList = AppUtils.getAppsInfo()
for (appInfo in appInfoList) {
if (appInfo.isSystem) {
App.SystemAppList.add(appInfo)
} else {
App.UserAppList.add(appInfo)
}
}
App.UserAppList.sortBy { appInfo -> appInfo.name }
App.SystemAppList.sortBy { appInfo -> appInfo.name }
}
}
GlobalScope.launch(Dispatchers.Main) {
runCatching {
get.await()
if (App.UserAppList.isEmpty() && App.SystemAppList.isEmpty()) return@runCatching
appListSpinnerList.clear()
if (SettingUtils.enableLoadUserAppList) {
for (appInfo in App.UserAppList) {
appListSpinnerList.add(AppListAdapterItem(appInfo.name, appInfo.icon, appInfo.packageName))
}
}
if (SettingUtils.enableLoadSystemAppList) {
for (appInfo in App.SystemAppList) {
appListSpinnerList.add(AppListAdapterItem(appInfo.name, appInfo.icon, appInfo.packageName))
}
}
//列表为空也不显示下拉框
if (appListSpinnerList.isEmpty()) return@runCatching
appListSpinnerAdapter = AppListSpinnerAdapter(appListSpinnerList)
//.setTextColor(ResUtils.getColor(R.color.green))
//.setTextSize(12F)
.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 = appListSpinnerList[position]
val appInfo = appListSpinnerAdapter.getItemSource(position) as AppListAdapterItem
CommonUtils.insertOrReplaceText2Cursor(binding!!.etAppList, appInfo.packageName.toString() + "\n")
} catch (e: Exception) {
XToastUtils.error(e.message.toString())
}
}
binding!!.spApp.visibility = View.VISIBLE
}.onFailure {
Log.e("GlobalScope", it.message.toString())
}
}
}
}

View File

@ -55,6 +55,21 @@ class NotifyService : NotificationListenerService() {
if (sbn!!.notification == null) return
if (sbn.notification.extras == null) return
//自动消除额外APP通知
if (!TextUtils.isEmpty(SettingUtils.cancelExtraAppNotify)) {
for (app in SettingUtils.cancelExtraAppNotify.split("\n")) {
if (sbn.packageName == app.trim()) {
Log.d(TAG, "自动消除额外APP通知$app")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
cancelNotification(sbn.key)
} else {
cancelNotification(sbn.packageName, sbn.tag, sbn.id)
}
break
}
}
}
//仅锁屏状态转发APP通知
if (SettingUtils.enableNotUserPresent && !ScreenUtils.isScreenLock()) return
@ -97,13 +112,11 @@ class NotifyService : NotificationListenerService() {
}
}
val request = OneTimeWorkRequestBuilder<SendWorker>()
.setInputData(
workDataOf(
Worker.sendMsgInfo to Gson().toJson(msgInfo),
)
val request = OneTimeWorkRequestBuilder<SendWorker>().setInputData(
workDataOf(
Worker.sendMsgInfo to Gson().toJson(msgInfo),
)
.build()
).build()
WorkManager.getInstance(applicationContext).enqueue(request)
} catch (e: Exception) {

View File

@ -38,6 +38,7 @@ const val SP_ENABLE_CALL_TYPE_6 = "enable_call_type_6"
const val SP_ENABLE_APP_NOTIFY = "enable_app_notify"
const val SP_ENABLE_CANCEL_APP_NOTIFY = "enable_cancel_app_notify"
const val SP_CANCEL_EXTRA_APP_NOTIFY = "cancel_extra_app_notify"
const val SP_ENABLE_NOT_USER_PRESENT = "enable_not_user_present"
const val ENABLE_LOAD_APP_LIST = "enable_load_app_list"

View File

@ -40,7 +40,10 @@ class SettingUtils private constructor() {
var enableAppNotify: Boolean by SharedPreference(SP_ENABLE_APP_NOTIFY, false)
//是否转发应用通知——自动消除通知
var enableCancelAppNotify: Boolean by SharedPreference(SP_ENABLE_CANCEL_APP_NOTIFY, false)
var enableCancelAppNotify: Boolean by SharedPreference(SP_CANCEL_EXTRA_APP_NOTIFY, false)
//是否转发应用通知——自动消除额外APP通知
var cancelExtraAppNotify: String by SharedPreference(SP_BATTERY_CRON_START_TIME, "")
//是否转发应用通知——仅锁屏状态
var enableNotUserPresent: Boolean by SharedPreference(SP_ENABLE_NOT_USER_PRESENT, false)

View File

@ -101,6 +101,7 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:gravity="center_vertical"
android:orientation="horizontal">
@ -240,81 +241,135 @@
<LinearLayout
style="@style/settingBarStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="0dp"
android:layout_width="match_parent"
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/forward_app_notify"
android:textStyle="bold"
tools:ignore="RelativeOverlap" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/forward_app_notify_tips"
android:textSize="9sp"
tools:ignore="SmallSp" />
android:orientation="horizontal">
<LinearLayout
android:id="@+id/layout_optional_action"
android:layout_width="match_parent"
android:layout_height="25dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:visibility="gone">
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/optional_action"
android:textSize="10sp"
android:text="@string/forward_app_notify"
android:textStyle="bold"
tools:ignore="SmallSp" />
<com.xuexiang.xui.widget.button.SmoothCheckBox
android:id="@+id/scb_cancel_app_notify"
android:layout_width="15dp"
android:layout_height="15dp"
app:scb_color_checked="@color/colorPrimary" />
tools:ignore="RelativeOverlap" />
<TextView
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/cancel_app_notify"
android:textSize="10sp"
android:text="@string/forward_app_notify_tips"
android:textSize="9sp"
tools:ignore="SmallSp" />
<com.xuexiang.xui.widget.button.SmoothCheckBox
android:id="@+id/scb_not_user_present"
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_marginStart="5dp"
app:scb_color_checked="@color/colorPrimary" />
<LinearLayout
android:id="@+id/layout_optional_action"
android:layout_width="match_parent"
android:layout_height="25dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:visibility="gone">
<TextView
android:layout_width="wrap_content"
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/optional_action"
android:textSize="10sp"
android:textStyle="bold"
tools:ignore="SmallSp" />
<com.xuexiang.xui.widget.button.SmoothCheckBox
android:id="@+id/scb_cancel_app_notify"
android:layout_width="15dp"
android:layout_height="15dp"
app:scb_color_checked="@color/colorPrimary" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cancel_app_notify"
android:textSize="10sp"
tools:ignore="SmallSp" />
<com.xuexiang.xui.widget.button.SmoothCheckBox
android:id="@+id/scb_not_user_present"
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_marginStart="5dp"
app:scb_color_checked="@color/colorPrimary" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/not_user_present"
android:textSize="10sp"
tools:ignore="SmallSp" />
</LinearLayout>
</LinearLayout>
<com.xuexiang.xui.widget.button.switchbutton.SwitchButton
android:id="@+id/sb_enable_app_notify"
style="@style/SwitchButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:id="@+id/layout_app_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingEnd="10dp"
android:visibility="gone">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="2"
android:text="@string/extra_app"
android:textSize="12sp"
android:textStyle="bold" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_weight="1"
android:orientation="vertical">
<com.xuexiang.xui.widget.edittext.materialedittext.MaterialEditText
android:id="@+id/et_app_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/not_user_present"
android:textSize="10sp"
tools:ignore="SmallSp" />
android:hint="@string/extra_app_hint"
android:inputType="textMultiLine"
app:met_clearButton="true" />
<com.xuexiang.xui.widget.spinner.editspinner.EditSpinner
android:id="@+id/sp_app"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:visibility="gone"
app:es_hint="@string/choose_app_hint"
app:es_maxLength="20"
app:es_maxLine="1" />
</LinearLayout>
</LinearLayout>
<com.xuexiang.xui.widget.button.switchbutton.SwitchButton
android:id="@+id/sb_enable_app_notify"
style="@style/SwitchButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout

View File

@ -721,7 +721,9 @@
<string name="feishu_secret_hint">Group Robot → Security Settings → Signature Verification</string>
<string name="pushplus_token_hint">Please go to the corresponding official website to obtain</string>
<string name="choose_sender">Drop-down selection, keyword fuzzy match</string>
<string name="choose_app">Installed apps</string>
<string name="choose_app">Installed Apps</string>
<string name="extra_app">Extra Apps</string>
<string name="extra_app_hint">One package name per line\nEnable async loading of the App list for selection.</string>
<string name="choose_app_hint">Drop-down selection to get package name, keyword fuzzy matching APP name</string>
<string name="regex_multi_match" tools:ignore="TypographyDashes">^\\s*(AND|OR)\\s(IS|NOTIS)\\s(PHONE_NUM|PACKAGE_NAME|MSG_CONTENT|INFORM_CONTENT|INFORM_TITLE|CARD_SLOT)\\s(EQUALS|CONTAIN|NOTCONTAIN|STARTWITH|ENDWITH|REGEX)\\s(.*)$</string>
<string name="privacy_content_1">Welcome to</string>

View File

@ -723,6 +723,8 @@
<string name="pushplus_token_hint">请前往对应的官网地址获取</string>
<string name="choose_sender">下拉选择,关键字模糊匹配</string>
<string name="choose_app">已装APP列表</string>
<string name="extra_app">额外消除应用通知</string>
<string name="extra_app_hint">一行一个包名\n开启异步加载App列表以便选择</string>
<string name="choose_app_hint">下拉选择获取包名关键字模糊匹配APP名称</string>
<string name="regex_multi_match" tools:ignore="TypographyDashes">^\\s*(并且|或者)\\s(是|不是)\\s(手机号|APP包名|短信内容|通知内容|通知标题|卡槽信息)\\s(相等|包含|不包含|开头|结尾|正则匹配)\\s(.*)$</string>
<string name="privacy_content_1">欢迎使用</string>

View File

@ -18,4 +18,4 @@ isUseBooster=false
android.precompileDependenciesResources=false
android.useAndroidX=true
android.enableJetifier=true
android.enableD8=true
#android.enableD8=true