mirror of
https://github.com/fankes/ColorOSNotifyIcon.git
synced 2025-09-07 19:14:20 +08:00
Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
3c1a4798d0 | |||
9faab60aa8 | |||
74eb55ab39 | |||
f7e75931ed | |||
856c1c5cab | |||
fcbf3b0565 | |||
fa3cddd75f | |||
d11dfe5167 | |||
b3be2789a9 | |||
ea962e1520 | |||
3e2b8247c8 | |||
e529e75bc2 | |||
cd5f9806a3 |
2
.idea/gradle.xml
generated
2
.idea/gradle.xml
generated
@@ -7,13 +7,13 @@
|
||||
<option name="testRunner" value="GRADLE" />
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="gradleJvm" value="Embedded JDK" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/app" />
|
||||
</set>
|
||||
</option>
|
||||
<option name="resolveModulePerSourceSet" value="false" />
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
|
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -13,7 +13,7 @@
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="Android Studio default JDK" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="11" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
<br/><br/>
|
||||
<img src="https://github.com/fankes/ColorOSNotifyIcon/blob/master/app/src/main/ic_launcher-playstore.png" width = "100" height = "100"/>
|
||||
<br/>
|
||||
@@ -12,7 +12,7 @@ Optimize notification icons for ColorOS and adapt to native notification icon sp
|
||||
# 开始使用
|
||||
|
||||
点击下载最新版本
|
||||
<a href='https://github.com/fankes/ColorOSNotifyIcon/releases'></a>
|
||||
<a href='https://github.com/fankes/ColorOSNotifyIcon/releases'></a>
|
||||
<br/><br/>
|
||||
⚠️ 适配说明<br/>
|
||||
|
||||
|
@@ -60,14 +60,12 @@ tasks.whenTaskAdded {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly 'de.robv.android.xposed:api:82'
|
||||
implementation 'com.highcapable.yukihookapi:api:1.0.4'
|
||||
ksp 'com.highcapable.yukihookapi:ksp-xposed:1.0.4'
|
||||
implementation 'com.github.tiann:FreeReflection:3.1.0'
|
||||
implementation "com.github.topjohnwu.libsu:core:3.1.2"
|
||||
implementation 'androidx.annotation:annotation:1.3.0'
|
||||
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1'
|
||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
|
||||
compileOnly 'de.robv.android.xposed:api:82'
|
||||
implementation 'com.highcapable.yukihookapi:api:1.0.3'
|
||||
ksp 'com.highcapable.yukihookapi:ksp-xposed:1.0.3'
|
||||
implementation 'com.geyifeng.immersionbar:immersionbar:3.2.0'
|
||||
implementation 'com.geyifeng.immersionbar:immersionbar-ktx:3.2.0'
|
||||
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
|
||||
|
@@ -23,7 +23,7 @@
|
||||
package com.fankes.coloros.notify.bean
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import com.fankes.coloros.notify.utils.base64
|
||||
import com.fankes.coloros.notify.utils.factory.base64
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
|
@@ -31,6 +31,7 @@ object HookConst {
|
||||
const val ENABLE_NOTIFY_ICON_FIX = "_notify_icon_fix"
|
||||
const val REMOVE_DEV_NOTIFY = "_remove_dev_notify"
|
||||
const val REMOVE_CHANGECP_NOTIFY = "_remove_charge_complete_notify"
|
||||
const val REMOVE_DNDALERT_NOTIFY = "_remove_dndalert_notify"
|
||||
const val NOTIFY_ICON_DATAS = "_notify_icon_datas"
|
||||
|
||||
const val SOURCE_SYNC_WAY = "_source_sync_way"
|
||||
|
@@ -38,12 +38,13 @@ import com.fankes.coloros.notify.hook.HookConst.ENABLE_MODULE_LOG
|
||||
import com.fankes.coloros.notify.hook.HookConst.ENABLE_NOTIFY_ICON_FIX
|
||||
import com.fankes.coloros.notify.hook.HookConst.REMOVE_CHANGECP_NOTIFY
|
||||
import com.fankes.coloros.notify.hook.HookConst.REMOVE_DEV_NOTIFY
|
||||
import com.fankes.coloros.notify.hook.HookConst.REMOVE_DNDALERT_NOTIFY
|
||||
import com.fankes.coloros.notify.hook.HookConst.SYSTEMUI_PACKAGE_NAME
|
||||
import com.fankes.coloros.notify.hook.factory.isAppNotifyHookAllOf
|
||||
import com.fankes.coloros.notify.hook.factory.isAppNotifyHookOf
|
||||
import com.fankes.coloros.notify.param.IconPackParams
|
||||
import com.fankes.coloros.notify.utils.*
|
||||
import com.fankes.coloros.notify.utils.drawable.drawabletoolbox.DrawableBuilder
|
||||
import com.fankes.coloros.notify.utils.factory.*
|
||||
import com.highcapable.yukihookapi.annotation.xposed.InjectYukiHookWithXposed
|
||||
import com.highcapable.yukihookapi.hook.bean.VariousClass
|
||||
import com.highcapable.yukihookapi.hook.factory.configs
|
||||
@@ -59,6 +60,7 @@ import com.highcapable.yukihookapi.hook.type.android.IconClass
|
||||
import com.highcapable.yukihookapi.hook.type.android.ImageViewClass
|
||||
import com.highcapable.yukihookapi.hook.type.java.BooleanType
|
||||
import com.highcapable.yukihookapi.hook.type.java.IntType
|
||||
import com.highcapable.yukihookapi.hook.type.java.LongType
|
||||
import com.highcapable.yukihookapi.hook.xposed.proxy.YukiHookXposedInitProxy
|
||||
|
||||
@InjectYukiHookWithXposed
|
||||
@@ -87,8 +89,17 @@ class HookEntry : YukiHookXposedInitProxy {
|
||||
/** ColorOS 存在的类 - 旧版本不存在 */
|
||||
private const val OplusContrastColorUtilClass = "com.oplusos.util.OplusContrastColorUtil"
|
||||
|
||||
/** ColorOS 存在的类 */
|
||||
private const val SystemPromptControllerClass = "com.oplusos.systemui.statusbar.policy.SystemPromptController"
|
||||
/** 根据多个版本存在不同的包名相同的类 */
|
||||
private val SystemPromptControllerClass = VariousClass(
|
||||
"com.oplusos.systemui.statusbar.policy.SystemPromptController",
|
||||
"com.coloros.systemui.statusbar.policy.SystemPromptController"
|
||||
)
|
||||
|
||||
/** 根据多个版本存在不同的包名相同的类 */
|
||||
private val DndAlertHelperClass = VariousClass(
|
||||
"com.oplusos.systemui.notification.helper.DndAlertHelper",
|
||||
"com.coloros.systemui.notification.helper.DndAlertHelper"
|
||||
)
|
||||
|
||||
/** 根据多个版本存在不同的包名相同的类 */
|
||||
private val OplusPowerNotificationWarningsClass = VariousClass(
|
||||
@@ -267,11 +278,19 @@ class HookEntry : YukiHookXposedInitProxy {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onHook() = encase {
|
||||
configs {
|
||||
debugTag = "ColorOSNotify"
|
||||
isDebug = false
|
||||
}
|
||||
override fun onHook() {
|
||||
runConfig()
|
||||
runHook()
|
||||
}
|
||||
|
||||
/** 配置 Hook */
|
||||
private fun runConfig() = configs {
|
||||
debugTag = "ColorOSNotify"
|
||||
isDebug = false
|
||||
}
|
||||
|
||||
/** 开始 Hook */
|
||||
private fun runHook() = encase {
|
||||
loadApp(SYSTEMUI_PACKAGE_NAME) {
|
||||
when {
|
||||
/** 不是 ColorOS 系统停止 Hook */
|
||||
@@ -305,6 +324,19 @@ class HookEntry : YukiHookXposedInitProxy {
|
||||
}
|
||||
}
|
||||
}
|
||||
/** 移除免打扰通知 */
|
||||
DndAlertHelperClass.hook {
|
||||
injectMember {
|
||||
method {
|
||||
name = "sendNotificationWithEndtime"
|
||||
param(LongType)
|
||||
}
|
||||
beforeHook {
|
||||
/** 是否移除 */
|
||||
if (prefs.getBoolean(REMOVE_DNDALERT_NOTIFY, default = false)) resultNull()
|
||||
}
|
||||
}
|
||||
}
|
||||
/** 修复并替换新版本 ColorOS 原生灰度图标色彩判断*/
|
||||
NotificationUtilsClass.hook {
|
||||
injectMember {
|
||||
|
@@ -20,6 +20,8 @@
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/24.
|
||||
*/
|
||||
@file:Suppress("MemberVisibilityCanBePrivate")
|
||||
|
||||
package com.fankes.coloros.notify.param
|
||||
|
||||
import android.content.Context
|
||||
@@ -27,9 +29,7 @@ import android.graphics.Bitmap
|
||||
import android.graphics.Color
|
||||
import com.fankes.coloros.notify.bean.IconDataBean
|
||||
import com.fankes.coloros.notify.hook.HookConst.NOTIFY_ICON_DATAS
|
||||
import com.fankes.coloros.notify.utils.bitmap
|
||||
import com.fankes.coloros.notify.utils.safeOf
|
||||
import com.fankes.coloros.notify.utils.safeOfNan
|
||||
import com.fankes.coloros.notify.utils.factory.*
|
||||
import com.highcapable.yukihookapi.hook.factory.modulePrefs
|
||||
import com.highcapable.yukihookapi.hook.param.PackageParam
|
||||
import org.json.JSONArray
|
||||
@@ -101,7 +101,7 @@ class IconPackParams(private val context: Context? = null, private val param: Pa
|
||||
* 已存储的 JSON 数据
|
||||
* @return [String]
|
||||
*/
|
||||
private val storageDataJson get() = (context?.modulePrefs ?: param?.prefs)?.getString(NOTIFY_ICON_DATAS)
|
||||
internal val storageDataJson get() = (context?.modulePrefs ?: param?.prefs)?.getString(NOTIFY_ICON_DATAS)
|
||||
|
||||
/**
|
||||
* 获取图标数据
|
||||
@@ -113,25 +113,32 @@ class IconPackParams(private val context: Context? = null, private val param: Pa
|
||||
if (it.isNotBlank()) runCatching {
|
||||
JSONArray(it).also { array ->
|
||||
for (i in 0 until array.length()) runCatching {
|
||||
(array.get(i) as JSONObject).apply {
|
||||
add(
|
||||
IconDataBean(
|
||||
appName = getString("appName"),
|
||||
packageName = getString("packageName"),
|
||||
isEnabled = getBoolean("isEnabled"),
|
||||
isEnabledAll = getBoolean("isEnabledAll"),
|
||||
iconBitmap = getString("iconBitmap").bitmap,
|
||||
iconColor = safeOfNan { Color.parseColor(getString("iconColor")) },
|
||||
contributorName = getString("contributorName")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
add(convertToBean(array.get(i) as JSONObject)!!)
|
||||
}.onFailure { context?.snake(msg = "部分规则加载失败") }
|
||||
}
|
||||
}
|
||||
}.onFailure { context?.snake(msg = "规则加载发生错误") }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为 [IconDataBean]
|
||||
* @param jsonObject Json 实例
|
||||
* @return [IconDataBean] or null
|
||||
*/
|
||||
private fun convertToBean(jsonObject: JSONObject) = safeOfNull {
|
||||
jsonObject.let {
|
||||
IconDataBean(
|
||||
appName = it.getString("appName"),
|
||||
packageName = it.getString("packageName"),
|
||||
isEnabled = it.getBoolean("isEnabled"),
|
||||
isEnabledAll = it.getBoolean("isEnabledAll"),
|
||||
iconBitmap = it.getString("iconBitmap").bitmap,
|
||||
iconColor = safeOfNan { Color.parseColor(it.getString("iconColor")) },
|
||||
contributorName = it.getString("contributorName")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼接图标数组数据
|
||||
* @param dataJson1 图标数据 JSON
|
||||
@@ -147,7 +154,21 @@ class IconPackParams(private val context: Context? = null, private val param: Pa
|
||||
* @param json 数据
|
||||
* @return [Boolean]
|
||||
*/
|
||||
fun isNotVaildJson(json: String) = json.trim().let { !it.startsWith("[") || !it.endsWith("]") }
|
||||
fun isNotVaildJson(json: String) = !isJsonArray(json) && !isJsonObject(json)
|
||||
|
||||
/**
|
||||
* 是否为 JSON 数组
|
||||
* @param json 数据
|
||||
* @return [Boolean]
|
||||
*/
|
||||
fun isJsonArray(json: String) = json.trim().let { it.startsWith("[") && it.endsWith("]") }
|
||||
|
||||
/**
|
||||
* 是否为 JSON 实例
|
||||
* @param json 数据
|
||||
* @return [Boolean]
|
||||
*/
|
||||
fun isJsonObject(json: String) = json.trim().let { it.startsWith("{") && it.endsWith("}") }
|
||||
|
||||
/**
|
||||
* 是否为异常地址
|
||||
|
@@ -48,7 +48,9 @@ import com.fankes.coloros.notify.hook.factory.putAppNotifyHookAllOf
|
||||
import com.fankes.coloros.notify.hook.factory.putAppNotifyHookOf
|
||||
import com.fankes.coloros.notify.param.IconPackParams
|
||||
import com.fankes.coloros.notify.ui.base.BaseActivity
|
||||
import com.fankes.coloros.notify.utils.*
|
||||
import com.fankes.coloros.notify.utils.factory.*
|
||||
import com.fankes.coloros.notify.utils.tool.ClientRequestTool
|
||||
import com.fankes.coloros.notify.utils.tool.SystemUITool
|
||||
import com.fankes.coloros.notify.view.MaterialSwitch
|
||||
import com.google.android.material.radiobutton.MaterialRadioButton
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
@@ -294,22 +296,42 @@ class ConfigureActivity : BaseActivity() {
|
||||
invalidate()
|
||||
}
|
||||
}
|
||||
confirmButton {
|
||||
IconPackParams(context = this@ConfigureActivity).also { params ->
|
||||
when {
|
||||
editText.text.toString().isNotBlank() && params.isNotVaildJson(editText.text.toString()) ->
|
||||
snake(msg = "不是有效的 JSON 数据")
|
||||
editText.text.toString().isNotBlank() -> {
|
||||
params.save(editText.text.toString())
|
||||
filterText = ""
|
||||
mockLocalData()
|
||||
SystemUITool.showNeedUpdateApplySnake(context = this@ConfigureActivity)
|
||||
IconPackParams(context = this@ConfigureActivity).also { params ->
|
||||
confirmButton(text = "合并") {
|
||||
editText.text.toString().also { jsonString ->
|
||||
when {
|
||||
jsonString.isNotBlank() && params.isNotVaildJson(jsonString) -> snake(msg = "不是有效的 JSON 数据")
|
||||
jsonString.isNotBlank() -> {
|
||||
params.save(
|
||||
params.splicingJsonArray(
|
||||
dataJson1 = params.storageDataJson ?: "[]",
|
||||
dataJson2 = jsonString.takeIf { params.isJsonArray(it) } ?: "[$jsonString]"
|
||||
)
|
||||
)
|
||||
filterText = ""
|
||||
mockLocalData()
|
||||
SystemUITool.showNeedUpdateApplySnake(context = this@ConfigureActivity)
|
||||
}
|
||||
else -> snake(msg = "请输入有效内容")
|
||||
}
|
||||
}
|
||||
}
|
||||
cancelButton(text = "覆盖") {
|
||||
editText.text.toString().also { jsonString ->
|
||||
when {
|
||||
jsonString.isNotBlank() && params.isNotVaildJson(jsonString) -> snake(msg = "不是有效的 JSON 数据")
|
||||
jsonString.isNotBlank() -> {
|
||||
params.save(dataJson = jsonString.takeIf { params.isJsonArray(it) } ?: "[$jsonString]")
|
||||
filterText = ""
|
||||
mockLocalData()
|
||||
SystemUITool.showNeedUpdateApplySnake(context = this@ConfigureActivity)
|
||||
}
|
||||
else -> snake(msg = "请输入有效内容")
|
||||
}
|
||||
else -> snake(msg = "规则数组内容为空")
|
||||
}
|
||||
}
|
||||
}
|
||||
cancelButton()
|
||||
neutralButton(text = "取消")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -43,8 +43,10 @@ import com.fankes.coloros.notify.hook.HookConst.ENABLE_MODULE_LOG
|
||||
import com.fankes.coloros.notify.hook.HookConst.ENABLE_NOTIFY_ICON_FIX
|
||||
import com.fankes.coloros.notify.hook.HookConst.REMOVE_CHANGECP_NOTIFY
|
||||
import com.fankes.coloros.notify.hook.HookConst.REMOVE_DEV_NOTIFY
|
||||
import com.fankes.coloros.notify.hook.HookConst.REMOVE_DNDALERT_NOTIFY
|
||||
import com.fankes.coloros.notify.ui.base.BaseActivity
|
||||
import com.fankes.coloros.notify.utils.*
|
||||
import com.fankes.coloros.notify.utils.factory.*
|
||||
import com.fankes.coloros.notify.utils.tool.SystemUITool
|
||||
import com.highcapable.yukihookapi.hook.factory.modulePrefs
|
||||
import com.highcapable.yukihookapi.hook.xposed.YukiHookModuleStatus
|
||||
|
||||
@@ -97,6 +99,7 @@ class MainActivity : BaseActivity() {
|
||||
val notifyIconConfigItem = findViewById<View>(R.id.config_item_notify)
|
||||
val devNotifyConfigSwitch = findViewById<SwitchCompat>(R.id.remove_dev_n_enable_switch)
|
||||
val crcpNotifyConfigSwitch = findViewById<SwitchCompat>(R.id.remove_chargecp_n_enable_switch)
|
||||
val dndNotifyConfigSwitch = findViewById<SwitchCompat>(R.id.remove_dndalert_n_enable_switch)
|
||||
val a12StyleConfigSwitch = findViewById<SwitchCompat>(R.id.a12_style_enable_switch)
|
||||
val hideIconInLauncherSwitch = findViewById<SwitchCompat>(R.id.hide_icon_in_launcher_switch)
|
||||
val notifyIconFixSwitch = findViewById<SwitchCompat>(R.id.notify_icon_fix_switch)
|
||||
@@ -109,6 +112,7 @@ class MainActivity : BaseActivity() {
|
||||
notifyIconFixButton.isVisible = modulePrefs.getBoolean(ENABLE_NOTIFY_ICON_FIX, default = true)
|
||||
devNotifyConfigSwitch.isChecked = modulePrefs.getBoolean(REMOVE_DEV_NOTIFY, default = true)
|
||||
crcpNotifyConfigSwitch.isChecked = modulePrefs.getBoolean(REMOVE_CHANGECP_NOTIFY, default = false)
|
||||
dndNotifyConfigSwitch.isChecked = modulePrefs.getBoolean(REMOVE_DNDALERT_NOTIFY, default = false)
|
||||
a12StyleConfigSwitch.isChecked = modulePrefs.getBoolean(ENABLE_ANDROID12_STYLE, isUpperOfAndroidS)
|
||||
moduleEnableSwitch.isChecked = modulePrefs.getBoolean(ENABLE_MODULE, default = true)
|
||||
moduleEnableLogSwitch.isChecked = modulePrefs.getBoolean(ENABLE_MODULE_LOG, default = false)
|
||||
@@ -153,6 +157,11 @@ class MainActivity : BaseActivity() {
|
||||
modulePrefs.putBoolean(REMOVE_CHANGECP_NOTIFY, b)
|
||||
SystemUITool.showNeedRestartSnake(context = this)
|
||||
}
|
||||
dndNotifyConfigSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
if (!btn.isPressed) return@setOnCheckedChangeListener
|
||||
modulePrefs.putBoolean(REMOVE_DNDALERT_NOTIFY, b)
|
||||
SystemUITool.showNeedRestartSnake(context = this)
|
||||
}
|
||||
a12StyleConfigSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
if (!btn.isPressed) return@setOnCheckedChangeListener
|
||||
modulePrefs.putBoolean(ENABLE_ANDROID12_STYLE, b)
|
||||
|
@@ -25,7 +25,7 @@ package com.fankes.coloros.notify.ui.base
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.fankes.coloros.notify.R
|
||||
import com.fankes.coloros.notify.utils.isNotSystemInDarkMode
|
||||
import com.fankes.coloros.notify.utils.factory.isNotSystemInDarkMode
|
||||
import com.gyf.immersionbar.ktx.immersionBar
|
||||
|
||||
abstract class BaseActivity : AppCompatActivity() {
|
||||
|
@@ -22,7 +22,7 @@
|
||||
*/
|
||||
@file:Suppress("unused", "DEPRECATION")
|
||||
|
||||
package com.fankes.coloros.notify.utils
|
||||
package com.fankes.coloros.notify.utils.factory
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.content.Context
|
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* ColorOSNotifyIcon - Optimize notification icons for ColorOS and adapt to native notification icon specifications.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/ColorOSNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/3/13.
|
||||
*/
|
||||
@file:Suppress("unused")
|
||||
|
||||
package com.fankes.coloros.notify.utils.factory
|
||||
|
||||
import com.highcapable.yukihookapi.hook.log.loggerE
|
||||
|
||||
/**
|
||||
* 忽略异常返回值
|
||||
* @param result 回调 - 如果异常为空
|
||||
* @return [T] 发生异常时返回设定值否则返回正常值
|
||||
*/
|
||||
inline fun <T> safeOfNull(result: () -> T): T? = safeOf(default = null, result)
|
||||
|
||||
/**
|
||||
* 忽略异常返回值
|
||||
* @param result 回调 - 如果异常为 false
|
||||
* @return [Boolean] 发生异常时返回设定值否则返回正常值
|
||||
*/
|
||||
inline fun safeOfFalse(result: () -> Boolean) = safeOf(default = false, result)
|
||||
|
||||
/**
|
||||
* 忽略异常返回值
|
||||
* @param result 回调 - 如果异常为 true
|
||||
* @return [Boolean] 发生异常时返回设定值否则返回正常值
|
||||
*/
|
||||
inline fun safeOfTrue(result: () -> Boolean) = safeOf(default = true, result)
|
||||
|
||||
/**
|
||||
* 忽略异常返回值
|
||||
* @param result 回调 - 如果异常为 false
|
||||
* @return [String] 发生异常时返回设定值否则返回正常值
|
||||
*/
|
||||
inline fun safeOfNothing(result: () -> String) = safeOf(default = "", result)
|
||||
|
||||
/**
|
||||
* 忽略异常返回值
|
||||
* @param result 回调 - 如果异常为 false
|
||||
* @return [Int] 发生异常时返回设定值否则返回正常值
|
||||
*/
|
||||
inline fun safeOfNan(result: () -> Int) = safeOf(default = 0, result)
|
||||
|
||||
/**
|
||||
* 忽略异常返回值
|
||||
* @param default 异常返回值
|
||||
* @param result 正常回调值
|
||||
* @return [T] 发生异常时返回设定值否则返回正常值
|
||||
*/
|
||||
inline fun <T> safeOf(default: T, result: () -> T) = try {
|
||||
result()
|
||||
} catch (_: Throwable) {
|
||||
default
|
||||
}
|
||||
|
||||
/**
|
||||
* 忽略异常运行
|
||||
* @param msg 出错输出的消息 - 默认为空
|
||||
* @param block 正常回调
|
||||
*/
|
||||
inline fun <T> T.runSafe(msg: String = "", block: () -> Unit) {
|
||||
runCatching(block).onFailure { if (msg.isNotBlank()) loggerE(msg = msg, e = it) }
|
||||
}
|
@@ -22,7 +22,7 @@
|
||||
*/
|
||||
@file:Suppress("DEPRECATION", "PrivateApi", "unused", "ObsoleteSdkInt")
|
||||
|
||||
package com.fankes.coloros.notify.utils
|
||||
package com.fankes.coloros.notify.utils.factory
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.AlertDialog
|
||||
@@ -47,7 +47,6 @@ import com.highcapable.yukihookapi.hook.factory.classOf
|
||||
import com.highcapable.yukihookapi.hook.factory.field
|
||||
import com.highcapable.yukihookapi.hook.factory.hasClass
|
||||
import com.highcapable.yukihookapi.hook.factory.method
|
||||
import com.highcapable.yukihookapi.hook.log.loggerE
|
||||
import com.highcapable.yukihookapi.hook.type.java.StringType
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import java.io.ByteArrayOutputStream
|
||||
@@ -110,9 +109,9 @@ val colorOSVersion
|
||||
(classOf(name = "com.oplus.os.OplusBuild").let {
|
||||
it.field { name = "VERSIONS" }.ignoredError().of<Array<String>>()
|
||||
?.get((it.method { name = "getOplusOSVERSION" }.ignoredError().get().invoke<Int>() ?: 23) - 1)
|
||||
} ?: findPropString(key = "ro.system.build.fingerprint", default = "无法获取")
|
||||
.split("ssi:")[1]
|
||||
.split("/")[0].trim()) + " ${Build.DISPLAY}"
|
||||
} ?: findPropString(
|
||||
key = "ro.system.build.fingerprint", default = "无法获取"
|
||||
).split("ssi:")[1].split("/")[0].trim()) + " ${Build.DISPLAY}"
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,8 +127,7 @@ val Context.packageInfo get() = packageManager?.getPackageInfo(packageName, 0) ?
|
||||
val String.isInstall
|
||||
get() = safeOfFalse {
|
||||
appContext.packageManager.getPackageInfo(
|
||||
this,
|
||||
PackageManager.GET_UNINSTALLED_PACKAGES
|
||||
this, PackageManager.GET_UNINSTALLED_PACKAGES
|
||||
)
|
||||
true
|
||||
}
|
||||
@@ -198,16 +196,13 @@ val String.bitmap: Bitmap get() = unbase64.bitmap
|
||||
* 设置对话框默认风格
|
||||
* @param context 使用的实例
|
||||
*/
|
||||
fun AlertDialog.setDefaultStyle(context: Context) =
|
||||
window?.setBackgroundDrawable(
|
||||
GradientDrawable(
|
||||
GradientDrawable.Orientation.TOP_BOTTOM,
|
||||
intArrayOf(Color.WHITE, Color.WHITE)
|
||||
).apply {
|
||||
shape = GradientDrawable.RECTANGLE
|
||||
gradientType = GradientDrawable.LINEAR_GRADIENT
|
||||
cornerRadius = 15.dp(context).toFloat()
|
||||
})
|
||||
fun AlertDialog.setDefaultStyle(context: Context) = window?.setBackgroundDrawable(GradientDrawable(
|
||||
GradientDrawable.Orientation.TOP_BOTTOM, intArrayOf(Color.WHITE, Color.WHITE)
|
||||
).apply {
|
||||
shape = GradientDrawable.RECTANGLE
|
||||
gradientType = GradientDrawable.LINEAR_GRADIENT
|
||||
cornerRadius = 15.dp(context).toFloat()
|
||||
})
|
||||
|
||||
/**
|
||||
* 获取系统 Prop 值
|
||||
@@ -246,139 +241,39 @@ fun toast(msg: String) = Toast.makeText(appContext, msg, Toast.LENGTH_SHORT).sho
|
||||
* @param it 按钮事件回调
|
||||
*/
|
||||
fun Context.snake(msg: String, actionText: String = "", it: () -> Unit = {}) =
|
||||
Snackbar.make((this as Activity).findViewById(android.R.id.content), msg, Snackbar.LENGTH_LONG)
|
||||
.apply {
|
||||
if (actionText.isBlank()) return@apply
|
||||
setActionTextColor(Color.WHITE)
|
||||
setAction(actionText) { it() }
|
||||
}.show()
|
||||
Snackbar.make((this as Activity).findViewById(android.R.id.content), msg, Snackbar.LENGTH_LONG).apply {
|
||||
if (actionText.isBlank()) return@apply
|
||||
setActionTextColor(Color.WHITE)
|
||||
setAction(actionText) { it() }
|
||||
}.show()
|
||||
|
||||
/**
|
||||
* 启动系统浏览器
|
||||
* @param url 网址
|
||||
* @param packageName 指定包名 - 可不填
|
||||
*/
|
||||
fun Context.openBrowser(url: String, packageName: String = "") =
|
||||
runCatching {
|
||||
startActivity(Intent().apply {
|
||||
if (packageName.isNotBlank()) setPackage(packageName)
|
||||
action = Intent.ACTION_VIEW
|
||||
data = Uri.parse(url)
|
||||
/** 防止顶栈一样重叠在自己的 APP 中 */
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
})
|
||||
}.onFailure {
|
||||
if (packageName.isNotBlank())
|
||||
snake(msg = "启动 $packageName 失败")
|
||||
else snake(msg = "启动系统浏览器失败")
|
||||
}
|
||||
fun Context.openBrowser(url: String, packageName: String = "") = runCatching {
|
||||
startActivity(Intent().apply {
|
||||
if (packageName.isNotBlank()) setPackage(packageName)
|
||||
action = Intent.ACTION_VIEW
|
||||
data = Uri.parse(url)
|
||||
/** 防止顶栈一样重叠在自己的 APP 中 */
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
})
|
||||
}.onFailure {
|
||||
if (packageName.isNotBlank()) snake(msg = "启动 $packageName 失败")
|
||||
else snake(msg = "启动系统浏览器失败")
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制到剪贴板
|
||||
* @param content 要复制的文本
|
||||
*/
|
||||
fun Context.copyToClipboard(content: String) = runCatching {
|
||||
fun Context.copyToClipboard(content: String) = runSafe {
|
||||
(getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager).apply {
|
||||
setPrimaryClip(ClipData.newPlainText(null, content))
|
||||
(primaryClip?.getItemAt(0)?.text ?: "").also {
|
||||
if (it != content) snake(msg = "复制失败") else snake(msg = "已复制")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 忽略异常返回值
|
||||
* @param it 回调 - 如果异常为空
|
||||
* @return [T] 发生异常时返回设定值否则返回正常值
|
||||
*/
|
||||
inline fun <T> safeOfNull(it: () -> T): T? = safeOf(null, it)
|
||||
|
||||
/**
|
||||
* 忽略异常返回值
|
||||
* @param it 回调 - 如果异常为 false
|
||||
* @return [Boolean] 发生异常时返回设定值否则返回正常值
|
||||
*/
|
||||
inline fun safeOfFalse(it: () -> Boolean) = safeOf(default = false, it)
|
||||
|
||||
/**
|
||||
* 忽略异常返回值
|
||||
* @param it 回调 - 如果异常为 true
|
||||
* @return [Boolean] 发生异常时返回设定值否则返回正常值
|
||||
*/
|
||||
inline fun safeOfTrue(it: () -> Boolean) = safeOf(default = true, it)
|
||||
|
||||
/**
|
||||
* 忽略异常返回值
|
||||
* @param it 回调 - 如果异常为 false
|
||||
* @return [String] 发生异常时返回设定值否则返回正常值
|
||||
*/
|
||||
inline fun safeOfNothing(it: () -> String) = safeOf(default = "", it)
|
||||
|
||||
/**
|
||||
* 忽略异常返回值
|
||||
* @param it 回调 - 如果异常为 false
|
||||
* @return [Int] 发生异常时返回设定值否则返回正常值
|
||||
*/
|
||||
inline fun safeOfNan(it: () -> Int) = safeOf(default = 0, it)
|
||||
|
||||
/**
|
||||
* 忽略异常返回值
|
||||
* @param default 异常返回值
|
||||
* @param it 正常回调值
|
||||
* @return [T] 发生异常时返回设定值否则返回正常值
|
||||
*/
|
||||
inline fun <T> safeOf(default: T, it: () -> T): T {
|
||||
return try {
|
||||
it()
|
||||
} catch (t: NullPointerException) {
|
||||
default
|
||||
} catch (t: UnsatisfiedLinkError) {
|
||||
default
|
||||
} catch (t: UnsupportedOperationException) {
|
||||
default
|
||||
} catch (t: ClassNotFoundException) {
|
||||
default
|
||||
} catch (t: IllegalStateException) {
|
||||
default
|
||||
} catch (t: NoSuchMethodError) {
|
||||
default
|
||||
} catch (t: NoSuchFieldError) {
|
||||
default
|
||||
} catch (t: Error) {
|
||||
default
|
||||
} catch (t: Exception) {
|
||||
default
|
||||
} catch (t: Throwable) {
|
||||
default
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 忽略异常运行
|
||||
* @param msg 出错输出的消息 - 默认为空
|
||||
* @param it 正常回调
|
||||
*/
|
||||
inline fun safeRun(msg: String = "", it: () -> Unit) {
|
||||
try {
|
||||
it()
|
||||
} catch (e: NullPointerException) {
|
||||
if (msg.isNotBlank()) loggerE(msg = msg, e = e)
|
||||
} catch (e: UnsatisfiedLinkError) {
|
||||
if (msg.isNotBlank()) loggerE(msg = msg, e = e)
|
||||
} catch (e: UnsupportedOperationException) {
|
||||
if (msg.isNotBlank()) loggerE(msg = msg, e = e)
|
||||
} catch (e: ClassNotFoundException) {
|
||||
if (msg.isNotBlank()) loggerE(msg = msg, e = e)
|
||||
} catch (e: IllegalStateException) {
|
||||
if (msg.isNotBlank()) loggerE(msg = msg, e = e)
|
||||
} catch (e: NoSuchMethodError) {
|
||||
if (msg.isNotBlank()) loggerE(msg = msg, e = e)
|
||||
} catch (e: NoSuchFieldError) {
|
||||
if (msg.isNotBlank()) loggerE(msg = msg, e = e)
|
||||
} catch (e: Error) {
|
||||
if (msg.isNotBlank()) loggerE(msg = msg, e = e)
|
||||
} catch (e: Exception) {
|
||||
if (msg.isNotBlank()) loggerE(msg = msg, e = e)
|
||||
} catch (e: Throwable) {
|
||||
}
|
||||
}
|
@@ -22,13 +22,17 @@
|
||||
*/
|
||||
@file:Suppress("TrustAllX509TrustManager", "CustomX509TrustManager", "DEPRECATION")
|
||||
|
||||
package com.fankes.coloros.notify.utils
|
||||
package com.fankes.coloros.notify.utils.tool
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.ProgressDialog
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.provider.Settings
|
||||
import com.fankes.coloros.notify.utils.factory.safeOfNull
|
||||
import com.fankes.coloros.notify.utils.factory.setDefaultStyle
|
||||
import com.fankes.coloros.notify.utils.factory.showDialog
|
||||
import com.fankes.coloros.notify.utils.factory.snake
|
||||
import com.highcapable.yukihookapi.hook.log.loggerD
|
||||
import okhttp3.*
|
||||
import java.io.IOException
|
@@ -20,9 +20,13 @@
|
||||
*
|
||||
* This file is Created by fankes on 2022/2/8.
|
||||
*/
|
||||
package com.fankes.coloros.notify.utils
|
||||
package com.fankes.coloros.notify.utils.tool
|
||||
|
||||
import android.content.Context
|
||||
import com.fankes.coloros.notify.utils.factory.execShellSu
|
||||
import com.fankes.coloros.notify.utils.factory.showDialog
|
||||
import com.fankes.coloros.notify.utils.factory.snake
|
||||
import com.fankes.coloros.notify.utils.factory.toast
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.highcapable.yukihookapi.hook.xposed.YukiHookModuleStatus
|
||||
|
@@ -29,7 +29,7 @@ import android.content.res.ColorStateList
|
||||
import android.graphics.Color
|
||||
import android.util.AttributeSet
|
||||
import androidx.appcompat.widget.SwitchCompat
|
||||
import com.fankes.coloros.notify.utils.dp
|
||||
import com.fankes.coloros.notify.utils.factory.dp
|
||||
import com.fankes.coloros.notify.utils.drawable.drawabletoolbox.DrawableBuilder
|
||||
|
||||
class MaterialSwitch(context: Context, attrs: AttributeSet?) : SwitchCompat(context, attrs) {
|
||||
|
@@ -233,7 +233,6 @@
|
||||
android:textSize="15sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/color_icon_compat_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
@@ -242,6 +241,25 @@
|
||||
android:text="充电完成后总是会推送一条通知,有时候甚至还不是静音状态,开启后将直接移除这个“你在教我做事”的通知功能。"
|
||||
android:textColor="@color/colorTextDark"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<com.fankes.coloros.notify.view.MaterialSwitch
|
||||
android:id="@+id/remove_dndalert_n_enable_switch"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="35dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:text="移除免打扰通知"
|
||||
android:textColor="@color/colorTextGray"
|
||||
android:textSize="15sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:alpha="0.6"
|
||||
android:lineSpacingExtra="6dp"
|
||||
android:text="开启免打扰后无论任何时长,总是会推送一条通知,开启后将直接移除这个“你在教我做事”的通知功能。"
|
||||
android:textColor="@color/colorTextDark"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
|
@@ -19,7 +19,7 @@
|
||||
android:layout_height="150dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center|start|top"
|
||||
android:hint="请粘贴 JSON 规则数组到此处"
|
||||
android:hint="请粘贴 JSON 规则到此处"
|
||||
android:textSize="14sp" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
</LinearLayout>
|
@@ -5,8 +5,8 @@ plugins {
|
||||
}
|
||||
|
||||
ext {
|
||||
appVersionName = "1.3"
|
||||
appVersionCode = 4
|
||||
appVersionName = "1.36"
|
||||
appVersionCode = 6
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
|
Reference in New Issue
Block a user