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

View File

@ -16,16 +16,15 @@ import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.CompoundButton import android.widget.*
import android.widget.EditText
import android.widget.LinearLayout
import android.widget.TextView
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import com.hjq.permissions.OnPermissionCallback import com.hjq.permissions.OnPermissionCallback
import com.hjq.permissions.Permission import com.hjq.permissions.Permission
import com.hjq.permissions.XXPermissions import com.hjq.permissions.XXPermissions
import com.idormy.sms.forwarder.App import com.idormy.sms.forwarder.App
import com.idormy.sms.forwarder.R 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.core.BaseFragment
import com.idormy.sms.forwarder.databinding.FragmentSettingsBinding import com.idormy.sms.forwarder.databinding.FragmentSettingsBinding
import com.idormy.sms.forwarder.entity.SimInfo 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.xui.widget.picker.widget.listener.OnOptionsSelectListener
import com.xuexiang.xutil.XUtil import com.xuexiang.xutil.XUtil
import com.xuexiang.xutil.XUtil.getPackageManager import com.xuexiang.xutil.XUtil.getPackageManager
import com.xuexiang.xutil.app.AppUtils
import com.xuexiang.xutil.app.AppUtils.getAppPackageName import com.xuexiang.xutil.app.AppUtils.getAppPackageName
import com.xuexiang.xutil.data.DateUtils import com.xuexiang.xutil.data.DateUtils
import kotlinx.coroutines.*
import java.util.* import java.util.*
@ -59,6 +60,10 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
val TAG: String = SettingsFragment::class.java.simpleName val TAG: String = SettingsFragment::class.java.simpleName
private val mTimeOption = DataProvider.timePeriodOption private val mTimeOption = DataProvider.timePeriodOption
//已安装App信息列表
private val appListSpinnerList = ArrayList<AppListAdapterItem>()
private lateinit var appListSpinnerAdapter: AppListSpinnerAdapter<*>
override fun viewBindingInflate( override fun viewBindingInflate(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup, container: ViewGroup,
@ -86,6 +91,8 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
switchEnableAppNotify( switchEnableAppNotify(
binding!!.sbEnableAppNotify, binding!!.scbCancelAppNotify, binding!!.scbNotUserPresent binding!!.sbEnableAppNotify, binding!!.scbCancelAppNotify, binding!!.scbNotUserPresent
) )
//设置自动消除额外APP通知
editExtraAppList(binding!!.etAppList)
//启动时异步获取已安装App信息 //启动时异步获取已安装App信息
switchEnableLoadAppList( switchEnableLoadAppList(
binding!!.sbEnableLoadAppList, binding!!.scbLoadUserApp, binding!!.scbLoadSystemApp binding!!.sbEnableLoadAppList, binding!!.scbLoadUserApp, binding!!.scbLoadSystemApp
@ -150,6 +157,9 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
//纯客户端模式 //纯客户端模式
switchDirectlyToClient(binding!!.sbDirectlyToClient) switchDirectlyToClient(binding!!.sbDirectlyToClient)
//初始化APP下拉列表
initAppSpinner()
} }
override fun initListeners() { override fun initListeners() {
@ -409,13 +419,17 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding?>(), View.OnClickL
fun switchEnableAppNotify( fun switchEnableAppNotify(
sbEnableAppNotify: SwitchButton, scbCancelAppNotify: SmoothCheckBox, scbNotUserPresent: SmoothCheckBox sbEnableAppNotify: SwitchButton, scbCancelAppNotify: SmoothCheckBox, scbNotUserPresent: SmoothCheckBox
) { ) {
val layoutOptionalAction: LinearLayout = binding!!.layoutOptionalAction
val isEnable: Boolean = SettingUtils.enableAppNotify val isEnable: Boolean = SettingUtils.enableAppNotify
sbEnableAppNotify.isChecked = isEnable sbEnableAppNotify.isChecked = isEnable
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
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
SettingUtils.enableAppNotify = isChecked SettingUtils.enableAppNotify = isChecked
if (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") @SuppressLint("UseSwitchCompatOrMaterialCode")
fun switchEnableLoadAppList( fun switchEnableLoadAppList(
sbEnableLoadAppList: SwitchButton, scbLoadUserApp: SmoothCheckBox, scbLoadSystemApp: SmoothCheckBox 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 == null) return
if (sbn.notification.extras == 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通知 //仅锁屏状态转发APP通知
if (SettingUtils.enableNotUserPresent && !ScreenUtils.isScreenLock()) return if (SettingUtils.enableNotUserPresent && !ScreenUtils.isScreenLock()) return
@ -97,13 +112,11 @@ class NotifyService : NotificationListenerService() {
} }
} }
val request = OneTimeWorkRequestBuilder<SendWorker>() val request = OneTimeWorkRequestBuilder<SendWorker>().setInputData(
.setInputData( workDataOf(
workDataOf( Worker.sendMsgInfo to Gson().toJson(msgInfo),
Worker.sendMsgInfo to Gson().toJson(msgInfo),
)
) )
.build() ).build()
WorkManager.getInstance(applicationContext).enqueue(request) WorkManager.getInstance(applicationContext).enqueue(request)
} catch (e: Exception) { } 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_APP_NOTIFY = "enable_app_notify"
const val SP_ENABLE_CANCEL_APP_NOTIFY = "enable_cancel_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 SP_ENABLE_NOT_USER_PRESENT = "enable_not_user_present"
const val ENABLE_LOAD_APP_LIST = "enable_load_app_list" 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 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) var enableNotUserPresent: Boolean by SharedPreference(SP_ENABLE_NOT_USER_PRESENT, false)

View File

@ -101,6 +101,7 @@
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:gravity="center_vertical" android:gravity="center_vertical"
android:orientation="horizontal"> android:orientation="horizontal">
@ -240,81 +241,135 @@
<LinearLayout <LinearLayout
style="@style/settingBarStyle" style="@style/settingBarStyle"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout <LinearLayout
android:layout_width="0dp" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:orientation="horizontal">
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" />
<LinearLayout <LinearLayout
android:id="@+id/layout_optional_action" android:layout_width="0dp"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_height="25dp" android:layout_weight="1"
android:gravity="center_vertical" android:orientation="vertical">
android:orientation="horizontal"
android:visibility="gone">
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/optional_action" android:text="@string/forward_app_notify"
android:textSize="10sp"
android:textStyle="bold" android:textStyle="bold"
tools:ignore="SmallSp" /> tools:ignore="RelativeOverlap" />
<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 <TextView
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/cancel_app_notify" android:text="@string/forward_app_notify_tips"
android:textSize="10sp" android:textSize="9sp"
tools:ignore="SmallSp" /> tools:ignore="SmallSp" />
<com.xuexiang.xui.widget.button.SmoothCheckBox <LinearLayout
android:id="@+id/scb_not_user_present" android:id="@+id/layout_optional_action"
android:layout_width="15dp" android:layout_width="match_parent"
android:layout_height="15dp" android:layout_height="25dp"
android:layout_marginStart="5dp" android:gravity="center_vertical"
app:scb_color_checked="@color/colorPrimary" /> android:orientation="horizontal"
android:visibility="gone">
<TextView <TextView
android:layout_width="wrap_content" 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:layout_height="wrap_content"
android:text="@string/not_user_present" android:hint="@string/extra_app_hint"
android:textSize="10sp" android:inputType="textMultiLine"
tools:ignore="SmallSp" /> 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>
</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>
<LinearLayout <LinearLayout

View File

@ -721,7 +721,9 @@
<string name="feishu_secret_hint">Group Robot → Security Settings → Signature Verification</string> <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="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_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="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="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> <string name="privacy_content_1">Welcome to</string>

View File

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

View File

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