45 Commits
1.15 ... 1.35

Author SHA1 Message Date
8f8c260069 Update version to 1.35,fix more bugs. 2022-02-08 00:49:22 +08:00
3461a28881 修复一个严重的判断问题,尝试修复 MIPUSH 图标不能 Hook 成功的问题 2022-02-08 00:45:34 +08:00
b1b99ccdfe 为 LSPosed 模块激活状态添加状态栏、通知栏图标 2022-02-08 00:21:46 +08:00
3aa7ee2a6a 为 LSPosed 模块激活状态添加状态栏、通知栏图标 2022-02-08 00:20:29 +08:00
1829a44eb3 预增加搜索功能 2022-02-07 23:46:40 +08:00
b5219a00cc 适配“虎牙直播”、“虎牙直播 Play版”、“云闪付”、“中国工商银行”、“中国农业银行”、“墨•状态栏歌词”、“车来了”、“腾讯微云”、“最右”、“学习通”、“波洞”、“哔哩哔哩漫画”、“航旅纵横”、“米游社”、“原神”、“崩坏3”通知优化图标 2022-02-07 23:40:19 +08:00
da81e12a60 修复 MIUI 12 MIPUSH 通知图标问题,修改文案 2022-02-07 22:55:02 +08:00
57a14fdaf1 预发布版本 2022-02-07 22:40:08 +08:00
be18502fd8 优化代码,加入适配说明 2022-02-07 22:38:31 +08:00
4914ae20b2 将 su 命令更换为 Magisk 的开源库 libsu 2022-02-07 21:54:28 +08:00
3b338214fc 修正文案 2022-02-07 21:44:44 +08:00
3a484e4a63 加入旧版状态栏小图标 Hook 方式日志记录 TAG 2022-02-07 21:36:23 +08:00
199ad9fc66 加入旧版状态栏小图标 Hook 方式日志记录 TAG 2022-02-07 21:34:38 +08:00
51e3eb8784 修复一个 Hook 异常疑似系统界面崩溃问题 2022-02-07 21:31:25 +08:00
e05d65e7e5 修正文案 2022-02-07 21:16:26 +08:00
2fb557afd8 Update version to 1.3,fix more bugs. 2022-02-07 00:46:59 +08:00
8737aaac30 Update version to 1.3,fix more bugs. 2022-02-07 00:30:34 +08:00
993ceb5050 Update version to 1.3,fix more bugs. 2022-02-07 00:13:22 +08:00
b1baaf4403 修复一个问题 2022-02-07 00:05:18 +08:00
db9f866178 修复一个可能的权限问题 2022-02-07 00:02:25 +08:00
f2bccafd92 修复一些问题 2022-02-07 00:01:15 +08:00
d798ca944d 改回去了😅 2022-02-06 23:54:29 +08:00
ca81a61aae 修正并更改一些文案 2022-02-06 23:48:23 +08:00
cd4f7be354 增加“京东”、“小爱同学”、“小米SIM激活服务”通知优化图标 2022-02-06 23:44:55 +08:00
6c961f044f 彻底修复 MIUI 12 通知图标的问题 2022-02-06 23:29:30 +08:00
485f85873c Update version to 1.25,fix more bugs. 2022-02-05 22:57:04 +08:00
8202239f57 通知优化图标展示界面顶部增加适配的图标个数展示 2022-02-05 22:39:19 +08:00
7e4cd7f71a 增加“下载管理程序”、“MIUI天气”、“米家”、“和平精英”、“起点读书”、“高德地图”、“百度地图”、“招商银行”、“人民日报”、“即可”通知优化图标 2022-02-05 22:30:53 +08:00
f6c4448eed 适配 MIUI 12,修复在 MIUI 12 上不生效的问题,加入最低 MIUI 版本判断 2022-02-05 21:42:35 +08:00
45dde844b7 Update version to 1.2,fix more bugs. 2022-02-03 22:04:09 +08:00
8e987897fc 增加帮助文案 2022-02-03 21:58:27 +08:00
60e2a5b6ea 增加模块设置缓存功能,防止通知图标过多造成下拉通知栏卡顿 2022-02-03 21:34:02 +08:00
8a31373ebd 优化代码 2022-02-03 21:27:18 +08:00
963933f168 修改“微信”通知优化小图标配置 2022-02-03 21:23:51 +08:00
a72e89e57c 增加“QQ邮箱”通知优化小图标 2022-02-03 21:23:17 +08:00
c40b1bf3ee 增加“多看阅读”、“闲鱼”、“美团”、“美团外卖”通知优化小图标 2022-02-03 21:19:19 +08:00
3045c90580 优化淘宝、抖音通知优化图标大小 2022-02-03 21:06:22 +08:00
8e9c0127fa 待发布版本 2022-02-02 15:59:47 +08:00
7da1949de3 默认关闭模块调试日志输出 2022-02-02 15:53:08 +08:00
1bbacad3d2 默认关闭模块调试日志输出 2022-02-02 15:52:46 +08:00
6e6b566ea1 优化 lamprose 提交的通知优化图标,增加“大众点评”、“小米视频”、“腾讯视频”、“QQ音乐”、“酷狗音乐”、“滴滴出行”、“菜鸟”通知优化图标 2022-02-02 15:51:57 +08:00
bf5cd8de2b 修复 2022-02-02 15:07:26 +08:00
Fankesyooni
ec5796f37e Merge pull request #2 from lamprose/master
增加”小米商城“,”饿了么“,”小米有品“,”携程“,”App分享“,”小米社区“,”网易云音乐“,”什么值得买“,”王者荣耀“通知优化图标
2022-02-02 02:50:39 +08:00
lamprose
51353caec2 增加”小米商城“,”饿了么“,”小米有品“,”携程“,”App分享“,”小米社区“,”网易云音乐“,”什么值得买“,”王者荣耀“通知优化图标 2022-02-02 02:28:17 +08:00
f3ca453a9a Fix a commit 2022-02-02 00:40:24 +08:00
15 changed files with 2309 additions and 314 deletions

View File

@@ -21,8 +21,8 @@
```kotlin
IconDataBean(
isEnabled = true, // 是否默认启用替换
isEnabledAll = false, // 是否默认启用完全替换
isEnabled = true, // 是否默认启用替换彩色图标 - 关闭后将全部停止替换
isEnabledAll = false, // 是否默认启用替换全部图标
appName = "", // APP 名称
packageName = "", // APP 包名
iconBitmap = ("").bitmap, // 位图数据 Base64

View File

@@ -2,7 +2,7 @@
![Eclipse Marketplace](https://img.shields.io/badge/build-passing-brightgreen)
![Eclipse Marketplace](https://img.shields.io/badge/license-GPL3.0-blue)
![Eclipse Marketplace](https://img.shields.io/badge/version-v1.15-green)
![Eclipse Marketplace](https://img.shields.io/badge/version-v1.35-green)
<br/><br/>
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/app/src/main/ic_launcher-playstore.png" width = "100" height = "100"/>
<br/>
@@ -12,12 +12,13 @@ Fix the native notification bar icon function abandoned by the MIUI development
# 开始使用
点击下载最新版本
<a href='https://github.com/fankes/MIUINativeNotifyIcon/releases'>![Eclipse Marketplace](https://img.shields.io/badge/download-v1.15-green)</a>
<a href='https://github.com/fankes/MIUINativeNotifyIcon/releases'>![Eclipse Marketplace](https://img.shields.io/badge/download-v1.35-green)</a>
<br/><br/>
⚠️适配说明<br/>
⚠️ 适配说明<br/>
- 此模块仅支持 Lsposed(作用域“系统界面”)、EdXposed(不推荐)、不支持太极无极(阴)
- 目前最低支持基于 Android 9 版本的 MIUI12 或 MIUI12.5(建议)
- 此模块仅支持 LSPosed(作用域“系统界面”)、~~EdXposed(随时停止支持)~~、不支持太极无极
- 目前最低支持基于 Android 9 版本的 MIUI 12 或 MIUI 12.5(最低建议)
- 请始终保持最新版本的 LSPosed旧版本可能会出现 Hook 不生效的问题
# 禁止任何商业用途
@@ -59,7 +60,7 @@ com.android.internal.util.ContrastColorUtil
- 这个类中有一个方法可以拿出来判断图标的灰度效果
```java
```
ContrastColorUtil.getInstance().isGrayscaleIcon(drawable);
```
@@ -68,6 +69,12 @@ ContrastColorUtil.getInstance().isGrayscaleIcon(drawable);
- 后来一想,也是啊,被国内生态毒害的用户,怎么可能会去想到这些问题呢,最后只能是我自作多情,还对 MIUI 留有一点情怀吧。
- ——来自一个无可奈何的 MIUI 老用户
# 后记
- 近期重新适配了 MIUI 12、12.5、13 版本,每个版本的图标设置方法都不一样,而且改的乱七八糟的,我都要无语了,只能用了很多折中方案,毕竟我也没有那么大精力每个版本去修复,实在是累了
- 特地的把自己能有的小米手机刷成各种 MIUI 版本去为酷友做专项适配,我也是很累了,也希望你们能够多多支持,也能让 MIUI 做得更好
- MIUI 再不重写,怕是永远会变成安卓之光。雷军,金凡!!
# 许可证
- [GPL-3.0](https://www.gnu.org/licenses/gpl-3.0.html)

View File

@@ -21,15 +21,15 @@ android {
applicationId "com.fankes.miui.notify"
minSdk 26
targetSdk 26
versionCode 3
versionName "1.15"
versionCode 7
versionName "1.35"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
minifyEnabled true
signingConfig signingConfigs.debug
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
@@ -45,6 +45,7 @@ android {
dependencies {
compileOnly 'de.robv.android.xposed:api:82'
implementation "com.github.topjohnwu.libsu:core:3.1.2"
// 基础依赖包
implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
// Fragment 快速实现

View File

@@ -30,8 +30,8 @@ import java.io.Serializable
* @param packageName 包名
* @param iconBitmap 图标位图
* @param contributorName 贡献者昵称
* @param isEnabled 是否默认启用替换
* @param isEnabledAll 是否默认启用完全替换
* @param isEnabled 是否默认启用替换彩色图标 - 关闭后将全部停止替换
* @param isEnabledAll 是否默认启用替换全部图标
*/
data class IconDataBean(
var appName: String,

View File

@@ -18,10 +18,11 @@
*
* This file is Created by fankes on 2022/01/24.
*/
@file:Suppress("SameParameterValue")
@file:Suppress("SameParameterValue", "DEPRECATION")
package com.fankes.miui.notify.hook
import android.app.Notification
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Color
@@ -47,18 +48,41 @@ class HookMain : IXposedHookLoadPackage {
companion object {
private const val NotificationUtilClass =
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.NotificationUtil"
/** 一直存在的类 */
private const val SystemUIApplicationClass = "$SYSTEMUI_PACKAGE_NAME.SystemUIApplication"
/** MIUI 新版本存在的类 */
private const val NotificationHeaderViewWrapperInjectorClass =
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.row.wrapper.NotificationHeaderViewWrapperInjector"
private const val ExpandedNotificationClass =
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.ExpandedNotification"
/** 一直存在的类 */
private const val NotificationHeaderViewWrapperClass =
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.NotificationHeaderViewWrapper"
private const val SystemUIApplicationClass = "$SYSTEMUI_PACKAGE_NAME.SystemUIApplication"
/** 一直存在的类 */
private const val NotificationViewWrapperClass =
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.NotificationViewWrapper"
/** 原生存在的类 */
private const val StatusBarIconViewClass = "$SYSTEMUI_PACKAGE_NAME.statusbar.StatusBarIconView"
/** 原生存在的类 */
private const val ContrastColorUtilClass = "com.android.internal.util.ContrastColorUtil"
/** 未确定是否只有旧版本存在的类 */
private const val ExpandableNotificationRowClass = "$SYSTEMUI_PACKAGE_NAME.statusbar.ExpandableNotificationRow"
/** 根据多个版本存在不同的包名相同的类 */
private val NotificationUtilClass = Pair(
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.NotificationUtil",
"$SYSTEMUI_PACKAGE_NAME.miui.statusbar.notification.NotificationUtil"
)
/** 根据多个版本存在不同的包名相同的类 */
private val ExpandedNotificationClass = Pair(
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.ExpandedNotification",
"$SYSTEMUI_PACKAGE_NAME.miui.statusbar.ExpandedNotification"
)
}
/** 仅作用于替换的 Hook 方法体 */
@@ -75,13 +99,6 @@ class HookMain : IXposedHookLoadPackage {
}
}
/** 仅作用于替换的 Hook 方法体 */
private val replaceToFalse = object : XC_MethodReplacement() {
override fun replaceHookedMethod(param: MethodHookParam?): Any {
return false
}
}
/**
* 忽略异常运行
* @param error 错误信息
@@ -102,7 +119,7 @@ class HookMain : IXposedHookLoadPackage {
*/
private fun logD(content: String, it: () -> Unit = {}) {
it()
if (!HookMedium.getBoolean(HookMedium.ENABLE_MODULE_LOG, default = true)) return
if (!HookMedium.getBoolean(HookMedium.ENABLE_MODULE_LOG, default = false)) return
XposedBridge.log("[MIUINativeNotifyIcon][D]>$content")
Log.d("MIUINativeNotifyIcon", content)
}
@@ -114,7 +131,7 @@ class HookMain : IXposedHookLoadPackage {
*/
private fun logW(content: String, it: () -> Unit = {}) {
it()
if (!HookMedium.getBoolean(HookMedium.ENABLE_MODULE_LOG, default = true)) return
if (!HookMedium.getBoolean(HookMedium.ENABLE_MODULE_LOG, default = false)) return
XposedBridge.log("[MIUINativeNotifyIcon][W]>$content")
Log.d("MIUINativeNotifyIcon", content)
}
@@ -132,6 +149,62 @@ class HookMain : IXposedHookLoadPackage {
Log.e("MIUINativeNotifyIcon", content, e)
}
/**
* 目标类是否存在
* @param name 类名
* @return [Boolean]
*/
private fun XC_LoadPackage.LoadPackageParam.isClassExist(name: String) = try {
classLoader.loadClass(name)
true
} catch (_: Throwable) {
false
}
/**
* 目标方法是否存在
* @param classPair 类数组
* @param name 方法名
* @param param 方法参数类型数组
* @return [Boolean]
*/
private fun XC_LoadPackage.LoadPackageParam.isMethodExist(
classPair: Pair<String, String>,
name: String, vararg param: Class<*>
) = try {
(try {
classLoader.loadClass(classPair.first)
} catch (_: Throwable) {
try {
classLoader.loadClass(classPair.second)
} catch (_: Throwable) {
null
}
})?.getDeclaredMethod(name, *param)
true
} catch (_: Throwable) {
false
}
/**
* 目标方法是否存在
* @param className 类名
* @param name 方法名
* @param param 方法参数类型数组
* @return [Boolean]
*/
private fun XC_LoadPackage.LoadPackageParam.isMethodExist(className: String, name: String, vararg param: Class<*>) =
try {
(try {
classLoader.loadClass(className)
} catch (_: Throwable) {
null
})?.getDeclaredMethod(name, *param)
true
} catch (_: Throwable) {
false
}
/**
* 查找目标类
* @param name 类名
@@ -141,7 +214,42 @@ class HookMain : IXposedHookLoadPackage {
classLoader.loadClass(name)
/**
* ⚠️ 这个是修复彩色图标的关键核心代码判断
* 查找目标类 - 两个类都没找到才会报错
* @param pair 类名数组
* @return [Class]
*/
private fun XC_LoadPackage.LoadPackageParam.findClass(pair: Pair<String, String>) = try {
classLoader.loadClass(pair.first)
} catch (_: Throwable) {
try {
classLoader.loadClass(pair.second)
} catch (e: Throwable) {
logE(content = "Cannot find Class ${pair.first} and ${pair.second}", e)
error("[Throwable] Cannot find Class ${pair.first} and ${pair.second}")
}
}
/**
* 存在目标类的类名 - 两个类都没找到会抛出异常
* @param pair 类名数组
* @return [String] 目标类名
*/
private fun XC_LoadPackage.LoadPackageParam.existClass(pair: Pair<String, String>) = try {
classLoader.loadClass(pair.first)
pair.first
} catch (_: Throwable) {
try {
classLoader.loadClass(pair.second)
pair.second
} catch (_: Throwable) {
logE(content = "Cannot find Class ${pair.first} and ${pair.second}")
error("[Throwable] Cannot find Class ${pair.first} and ${pair.second}")
}
}
/**
* - 这个是修复彩色图标的关键核心代码判断
*
* 判断是否为灰度图标 - 反射执行系统方法
* @param context 实例
* @param icon 要判断的图标
@@ -155,6 +263,31 @@ class HookMain : IXposedHookLoadPackage {
.apply { isAccessible = true }.invoke(instance, icon) as Boolean
}
/**
* 获取当前通知栏的样式
* @return [Boolean]
*/
private fun XC_LoadPackage.LoadPackageParam.isShowMiuiStyle() = try {
findClass(NotificationUtilClass).let {
it.getDeclaredMethod("showMiuiStyle")
.apply { isAccessible = true }.invoke(null) as Boolean
}
} catch (_: Throwable) {
false
}
/**
* 是否为新版本 MIUI 方案
*
* 拥有状态栏图标颜色检查功能
* @return [Boolean]
*/
private fun XC_LoadPackage.LoadPackageParam.hasIgnoreStatusBarIconColor() = try {
isMethodExist(NotificationUtilClass, name = "ignoreStatusBarIconColor", findClass(ExpandedNotificationClass))
} catch (_: Throwable) {
false
}
/**
* 获取 [ExpandedNotificationClass] 的应用名称
* @param instance 通知实例
@@ -163,46 +296,64 @@ class HookMain : IXposedHookLoadPackage {
private fun XC_LoadPackage.LoadPackageParam.findAppName(instance: Any?) = try {
findClass(ExpandedNotificationClass).getDeclaredMethod("getAppName").let {
it.isAccessible = true
it.invoke(instance) as? String ?: ""
it.invoke(instance) as? String ?: "<empty>"
}
} catch (_: Throwable) {
"unknown"
} catch (e: Throwable) {
"<unknown>"
}
/**
* 获取全局上下文
* @return [Context]
* @return [Context] or null
*/
private val XC_LoadPackage.LoadPackageParam.globalContext
get() = findClass(SystemUIApplicationClass)
.getDeclaredMethod("getContext").apply { isAccessible = true }
.invoke(null) as Context
get() = try {
findClass(SystemUIApplicationClass)
.getDeclaredMethod("getContext").apply { isAccessible = true }
.invoke(null) as? Context?
} catch (_: Throwable) {
null
}
/**
* Hook 状态栏小图标
*
* 区分系统版本 - 由于每个系统版本的方法不一样这里单独拿出来进行 Hook
* @param param Hook Param
* @param context 实例
* @param expandedNf 通知实例
* @param iconDrawable 小图标 [Drawable]
* @param isLegacyWay 旧版本 Hook 方式
* @param it 回调小图标 - ([Bitmap] 小图标)
*/
private fun XC_LoadPackage.LoadPackageParam.hookSmallIconOnSet(param: XC_MethodHook.MethodHookParam) =
private fun XC_LoadPackage.LoadPackageParam.hookSmallIconOnSet(
context: Context,
expandedNf: StatusBarNotification?,
iconDrawable: Drawable,
isLegacyWay: Boolean,
it: (Bitmap) -> Unit
) {
runWithoutError(error = "GetSmallIconOnSet") {
/** 获取通知小图标 */
val iconDrawable = (param.result as Icon).loadDrawable(globalContext)
/** 判断是否不是灰度图标 */
val isNotGrayscaleIcon = !isGrayscaleIcon(globalContext, iconDrawable)
val isNotGrayscaleIcon = !isGrayscaleIcon(context, iconDrawable)
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
(param.args?.get(0) as? StatusBarNotification?)?.also { notifyInstance ->
expandedNf?.also { notifyInstance ->
/** 目标彩色通知 APP 图标 */
var customIcon: Icon? = null
var customIcon: Bitmap? = null
if (HookMedium.getBoolean(HookMedium.ENABLE_COLOR_ICON_HOOK, default = true))
run {
IconPackParams.iconDatas.forEach {
if (findAppName(notifyInstance).startsWith("Android") &&
(notifyInstance.notification.extras.getCharSequence(Notification.EXTRA_TITLE)
?.startsWith("Xposed 模块") == true ||
notifyInstance.notification.extras.getCharSequence(Notification.EXTRA_TITLE)
?.startsWith("Xposed Module") == true)
) customIcon = IconPackParams.lsposedIcon
else IconPackParams.iconDatas.forEach {
if ((notifyInstance.opPkgName == it.packageName ||
findAppName(notifyInstance) == it.appName) &&
HookMedium.isAppNotifyHookOf(it)
) {
if (isNotGrayscaleIcon || HookMedium.isAppNotifyHookAllOf(it))
customIcon = Icon.createWithBitmap(it.iconBitmap)
customIcon = it.iconBitmap
return@run
}
}
@@ -213,47 +364,48 @@ class HookMain : IXposedHookLoadPackage {
logD(
content = "GetSmallIconOnSet -> " +
"hook Custom AppIcon [pkgName] ${notifyInstance.opPkgName} " +
"[appName] ${findAppName(notifyInstance)}"
) { param.result = customIcon }
"[appName] ${findAppName(notifyInstance)} " +
"[legacyWay] $isLegacyWay"
) { it(customIcon!!) }
/** 若不是灰度图标自动处理为圆角 */
isNotGrayscaleIcon ->
logD(
content = "GetSmallIconOnSet -> " +
"hook Color AppIcon [pkgName] ${notifyInstance.opPkgName} " +
"[appName] ${findAppName(notifyInstance)}"
"[appName] ${findAppName(notifyInstance)} " +
"[legacyWay] $isLegacyWay"
) {
param.result = Icon.createWithBitmap(
iconDrawable.toBitmap().round(15.dp(globalContext))
)
it(iconDrawable.toBitmap().round(15.dp(context)))
}
}
} ?: logW(content = "GetSmallIconOnSet -> StatusBarNotification got null")
} ?: logW(content = "GetSmallIconOnSet -> StatusBarNotification got null [legacyWay] $isLegacyWay")
}
}
/**
* Hook 通知栏小图标
*
* 区分系统版本 - 由于每个系统版本的方法不一样这里单独拿出来进行 Hook
* @param param Hook Param
* @param isNew 是否为新版方式
* @param context 实例
* @param expandedNf 通知实例
* @param iconImageView 通知图标实例
*/
private fun XC_LoadPackage.LoadPackageParam.hookNotifyIconOnSet(param: XC_MethodHook.MethodHookParam, isNew: Boolean) =
private fun XC_LoadPackage.LoadPackageParam.hookNotifyIconOnSet(
context: Context,
expandedNf: StatusBarNotification?,
iconImageView: ImageView
) {
runWithoutError(error = "AutoSetAppIconOnSet") {
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
(param.args?.get(if (isNew) 2 else 1) as? StatusBarNotification?)?.let { notifyInstance ->
expandedNf?.let { notifyInstance ->
/** 是否 Hook 彩色通知图标 */
val isHookColorIcon = HookMedium.getBoolean(HookMedium.ENABLE_COLOR_ICON_HOOK, default = true)
/** 获取 [Context] */
val context = if (isNew) param.args[0] as Context else globalContext
/** 新版风格反色 */
val newStyle = if (context.isSystemInDarkMode) 0xFF2D2D2D.toInt() else Color.WHITE
/** 旧版风格反色 */
val oldStyle = if (context.isNotSystemInDarkMode) 0xFF515151.toInt() else Color.WHITE
/** 获取图标框 */
val iconImageView = param.args[if (isNew) 1 else 0] as ImageView
val oldStyle = if (context.isNotSystemInDarkMode) 0xFF707070.toInt() else Color.WHITE
/** 获取通知小图标 */
val iconDrawable = notifyInstance.notification.smallIcon.loadDrawable(context)
@@ -263,19 +415,24 @@ class HookMain : IXposedHookLoadPackage {
/** 自定义默认小图标 */
var customIcon: Bitmap? = null
if (isHookColorIcon)
run {
IconPackParams.iconDatas.forEach {
if ((notifyInstance.opPkgName == it.packageName ||
findAppName(notifyInstance) == it.appName) &&
HookMedium.isAppNotifyHookOf(it)
) {
if (!isGrayscaleIcon || HookMedium.isAppNotifyHookAllOf(it))
customIcon = it.iconBitmap
return@run
}
if (isHookColorIcon) run {
if (findAppName(notifyInstance).startsWith("Android") &&
(notifyInstance.notification.extras.getCharSequence(Notification.EXTRA_TITLE)
?.startsWith("Xposed 模块") == true ||
notifyInstance.notification.extras.getCharSequence(Notification.EXTRA_TITLE)
?.startsWith("Xposed Module") == true)
) customIcon = IconPackParams.lsposedIcon
else IconPackParams.iconDatas.forEach {
if ((notifyInstance.opPkgName == it.packageName ||
findAppName(notifyInstance) == it.appName) &&
HookMedium.isAppNotifyHookOf(it)
) {
if (!isGrayscaleIcon || HookMedium.isAppNotifyHookAllOf(it))
customIcon = it.iconBitmap
return@run
}
}
}
/** 如果开启了修复 APP 的彩色图标 */
if (customIcon != null && HookMedium.getBoolean(HookMedium.ENABLE_NOTIFY_ICON_HOOK, default = true))
iconImageView.apply {
@@ -309,11 +466,8 @@ class HookMain : IXposedHookLoadPackage {
outlineProvider = object : ViewOutlineProvider() {
override fun getOutline(view: View, out: Outline) {
out.setRoundRect(
0,
0,
view.width,
view.height,
5.dp(context)
0, 0,
view.width, view.height, 5.dp(context)
)
}
}
@@ -338,6 +492,75 @@ class HookMain : IXposedHookLoadPackage {
}
} ?: logW(content = "AutoSetAppIconOnSet -> StatusBarNotification got null")
}
}
/**
* Hook 通知栏小图标颜色
*
* 区分系统版本 - 由于每个系统版本的方法不一样这里单独拿出来进行 Hook
* @param context 实例
* @param expandedNf 状态栏实例
* @return [Boolean] 是否忽略通知图标颜色
*/
private fun XC_LoadPackage.LoadPackageParam.hookIgnoreStatusBarIconColor(
context: Context,
expandedNf: StatusBarNotification?
) = if (HookMedium.getBoolean(HookMedium.ENABLE_COLOR_ICON_HOOK, default = true))
try {
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
expandedNf?.let { notifyInstance ->
/** 获取通知小图标 */
val iconDrawable =
notifyInstance.notification.smallIcon.loadDrawable(context)
/** 判断是否不是灰度图标 */
val isNotGrayscaleIcon = !isGrayscaleIcon(context, iconDrawable)
/** 获取目标修复彩色图标的 APP */
var isTargetApp = false
run {
IconPackParams.iconDatas.forEach {
if ((notifyInstance.opPkgName == it.packageName ||
findAppName(notifyInstance) == it.appName) &&
HookMedium.isAppNotifyHookOf(it)
) {
if (isNotGrayscaleIcon || HookMedium.isAppNotifyHookAllOf(it)) isTargetApp = true
return@run
}
}
}
/** 如果开启了修复 APP 的彩色图标 */
if (isTargetApp && HookMedium.getBoolean(HookMedium.ENABLE_NOTIFY_ICON_HOOK, default = true)) let {
logD(
content = "IgnoreStatusBarIconColor -> " +
"hook Color AppIcon [pkgName] ${notifyInstance.opPkgName} " +
"[appName] ${findAppName(notifyInstance)}"
)
false
}
else let {
logD(
content = "IgnoreStatusBarIconColor -> " +
"hook Grayscale[${!isNotGrayscaleIcon}] AppIcon " +
"[pkgName] ${notifyInstance.opPkgName} " +
"[appName] ${findAppName(notifyInstance)}"
)
/** 只要不是灰度就返回彩色图标 */
isNotGrayscaleIcon
}
} ?: let {
logW(content = "IgnoreStatusBarIconColor -> StatusBarNotification got null")
/** 否则不对颜色进行反色处理防止一些系统图标出现异常 */
true
}
} catch (e: Exception) {
logE("Failed to hook ignoreStatusBarIconColor", e)
false
}
else let {
logD(content = "IgnoreStatusBarIconColor -> hook NonColor AppIcon")
false
}
override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) {
if (lpparam == null) return
@@ -361,6 +584,9 @@ class HookMain : IXposedHookLoadPackage {
/** 系统版本低于 Android P 停止 Hook */
isLowerAndroidP ->
logW(content = "Aborted Hook -> This System is lower than Android P")
/** 不是支持的 MIUI 系统停止 Hook */
isNotSupportMiuiVersion ->
logW(content = "Aborted Hook -> This MIUI Version $miuiVersion not supported")
/** Hook 被手动关闭停止 Hook */
!HookMedium.getBoolean(HookMedium.ENABLE_MODULE, default = true) ->
logW(content = "Aborted Hook -> Hook Closed")
@@ -368,91 +594,91 @@ class HookMain : IXposedHookLoadPackage {
/** 强制回写系统的状态栏图标样式为原生 */
runWithoutError(error = "SubstituteSmallIcon") {
XposedHelpers.findAndHookMethod(
NotificationUtilClass,
lpparam.existClass(NotificationUtilClass),
lpparam.classLoader,
"shouldSubstituteSmallIcon",
lpparam.findClass(ExpandedNotificationClass),
replaceToFalse
object : XC_MethodReplacement() {
override fun replaceHookedMethod(param: MethodHookParam) =
/**
* 因为之前的 MIUI 版本的状态栏图标颜色会全部设置为白色的 - 找不到修复的地方就直接判断版本了
* 对于之前没有通知图标色彩判断功能的版本判断是 MIUI 样式就停止 Hook
*/
if (lpparam.hasIgnoreStatusBarIconColor()) false else lpparam.isShowMiuiStyle()
}
)
}
/** 修复通知图标为彩色 */
runWithoutError(error = "IgnoreStatusBarIconColor") {
if (lpparam.hasIgnoreStatusBarIconColor())
runWithoutError(error = "IgnoreStatusBarIconColor") {
XposedHelpers.findAndHookMethod(
lpparam.existClass(NotificationUtilClass),
lpparam.classLoader,
"ignoreStatusBarIconColor",
lpparam.findClass(ExpandedNotificationClass),
object : XC_MethodReplacement() {
override fun replaceHookedMethod(param: MethodHookParam) =
lpparam.hookIgnoreStatusBarIconColor(
context = lpparam.globalContext ?: error("GlobalContext got null"),
param.args?.get(0) as? StatusBarNotification?
)
}
)
}
/** 修复通知图标为彩色 - MIPUSH 修复 */
runWithoutError(error = "UpdateIconColor") {
XposedHelpers.findAndHookMethod(
NotificationUtilClass,
lpparam.classLoader,
"ignoreStatusBarIconColor",
lpparam.findClass(ExpandedNotificationClass),
object : XC_MethodReplacement() {
override fun replaceHookedMethod(param: MethodHookParam) =
if (HookMedium.getBoolean(HookMedium.ENABLE_COLOR_ICON_HOOK, default = true))
try {
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
(param.args?.get(0) as? StatusBarNotification?)?.let { notifyInstance ->
/** 获取通知小图标 */
val iconDrawable =
notifyInstance.notification.smallIcon.loadDrawable(lpparam.globalContext)
StatusBarIconViewClass,
lpparam.classLoader, "updateIconColor",
object : XC_MethodHook() {
override fun afterHookedMethod(param: MethodHookParam) =
runWithoutError(error = "UpdateIconColorOnSet") hook@{
/** 获取自身 */
val iconImageView = param.thisObject as ImageView
/** 判断是否不是灰度图标 */
val isNotGrayscaleIcon =
!lpparam.isGrayscaleIcon(lpparam.globalContext, iconDrawable)
/** 获取通知实例 */
val expandedNf =
param.thisObject.javaClass.getDeclaredField("mNotification").apply {
isAccessible = true
}[param.thisObject] as? StatusBarNotification?
/** 获取目标修复彩色图标的 APP */
var isTargetApp = false
run {
IconPackParams.iconDatas.forEach {
if ((notifyInstance.opPkgName == it.packageName ||
lpparam.findAppName(notifyInstance) == it.appName) &&
HookMedium.isAppNotifyHookOf(it)
) {
if (isNotGrayscaleIcon || HookMedium.isAppNotifyHookAllOf(it))
isTargetApp = true
return@run
}
}
}
/** 如果开启了修复 APP 的彩色图标 */
if (isTargetApp &&
HookMedium.getBoolean(
HookMedium.ENABLE_NOTIFY_ICON_HOOK,
default = true
)
) let {
logD(
content = "IgnoreStatusBarIconColor -> " +
"hook Color AppIcon [pkgName] ${notifyInstance.opPkgName} " +
"[appName] ${lpparam.findAppName(notifyInstance)}"
)
false
}
else let {
logD(
content = "IgnoreStatusBarIconColor -> " +
"hook Grayscale[${!isNotGrayscaleIcon}] AppIcon " +
"[pkgName] ${notifyInstance.opPkgName} " +
"[appName] ${lpparam.findAppName(notifyInstance)}"
)
/** 只要不是灰度就返回彩色图标 */
isNotGrayscaleIcon
}
} ?: let {
logW(content = "IgnoreStatusBarIconColor -> StatusBarNotification got null")
/** 否则不对颜色进行反色处理防止一些系统图标出现异常 */
true
}
} catch (e: Exception) {
logE("Failed to hook ignoreStatusBarIconColor", e)
false
}
else let {
logD(content = "IgnoreStatusBarIconColor -> hook NonColor AppIcon")
false
/** 强制设置图标 - 防止 MIPUSH 不生效 */
lpparam.hookSmallIconOnSet(
context = iconImageView.context,
expandedNf,
iconImageView.drawable,
isLegacyWay = true
) { icon -> iconImageView.setImageBitmap(icon) }
/**
* 对于之前没有通知图标色彩判断功能的版本判断是 MIUI 样式就停止 Hook
* 新版本不需要下面的代码设置颜色 - 同样停止 Hook
*/
if (lpparam.hasIgnoreStatusBarIconColor() || lpparam.isShowMiuiStyle()) return@hook
/** 是否忽略图标颜色 */
val isIgnoredColor =
lpparam.hookIgnoreStatusBarIconColor(iconImageView.context, expandedNf)
/** 当前着色颜色 */
val currentColor =
param.thisObject.javaClass.getDeclaredField("mCurrentSetColor").apply {
isAccessible = true
}[param.thisObject] as? Int ?: Color.WHITE
/** 判断并设置颜色 */
if (isIgnoredColor)
iconImageView.colorFilter = null
else iconImageView.setColorFilter(currentColor)
logD(content = "IgnoreStatusBarIconColor[UseOldWay] -> isIgnored[$isIgnoredColor]")
}
}
)
}
/** 强制回写系统的状态栏图标样式为原生 */
runWithoutError(error = "GetSmallIcon") {
var isTooOld: Boolean
try {
isTooOld = false
/** 新版方法 */
lpparam.findClass(NotificationUtilClass)
.getDeclaredMethod(
@@ -461,62 +687,141 @@ class HookMain : IXposedHookLoadPackage {
Int::class.java
).apply { isAccessible = true }
} catch (_: Throwable) {
/** 旧版方法 */
lpparam.findClass(NotificationUtilClass)
.getDeclaredMethod("getSmallIcon", lpparam.findClass(ExpandedNotificationClass))
.apply { isAccessible = true }
try {
isTooOld = false
/** 旧版方法 */
lpparam.findClass(NotificationUtilClass)
.getDeclaredMethod("getSmallIcon", lpparam.findClass(ExpandedNotificationClass))
.apply { isAccessible = true }
} catch (_: Throwable) {
isTooOld = true
/** 超旧版方法 */
lpparam.findClass(NotificationUtilClass)
.getDeclaredMethod(
"getSmallIcon",
Context::class.java,
lpparam.findClass(ExpandedNotificationClass)
).apply { isAccessible = true }
}
}.also {
XposedBridge.hookMethod(it, object : XC_MethodHook() {
override fun afterHookedMethod(param: MethodHookParam) {
lpparam.hookSmallIconOnSet(param)
/** 对于之前没有通知图标色彩判断功能的版本判断是 MIUI 样式就停止 Hook */
if (!lpparam.hasIgnoreStatusBarIconColor() && lpparam.isShowMiuiStyle()) return
runWithoutError(error = "GetSmallIconDoing") {
(lpparam.globalContext ?: param.args[0] as Context).also { context ->
lpparam.hookSmallIconOnSet(
context = context,
param.args?.get(if (isTooOld) 1 else 0) as? StatusBarNotification?,
(param.result as Icon).loadDrawable(context),
isLegacyWay = isTooOld
) { icon -> param.result = Icon.createWithBitmap(icon) }
}
}
}
})
}
}
/** 修复下拉通知图标自动设置回 APP 图标的方法 */
runWithoutError(error = "AutoSetAppIcon") {
var isNewWay = true
try {
/** 新版方法 */
lpparam.findClass(NotificationHeaderViewWrapperInjectorClass)
.getDeclaredMethod(
"setAppIcon",
Context::class.java,
ImageView::class.java,
lpparam.findClass(ExpandedNotificationClass)
).apply { isAccessible = true }
} catch (_: Throwable) {
isNewWay = false
/** 旧版方法 */
lpparam.findClass(NotificationHeaderViewWrapperInjectorClass)
.getDeclaredMethod(
"setAppIcon",
ImageView::class.java,
lpparam.findClass(ExpandedNotificationClass)
).apply { isAccessible = true }
}.also {
XposedBridge.hookMethod(it, object : XC_MethodReplacement() {
override fun replaceHookedMethod(param: MethodHookParam): Any? {
lpparam.hookNotifyIconOnSet(param, isNew = isNewWay)
return null
}
})
if (lpparam.isClassExist(NotificationHeaderViewWrapperInjectorClass))
runWithoutError(error = "AutoSetAppIcon") {
var isNewWay = true
try {
/** 新版方法 */
lpparam.findClass(NotificationHeaderViewWrapperInjectorClass)
.getDeclaredMethod(
"setAppIcon",
Context::class.java,
ImageView::class.java,
lpparam.findClass(ExpandedNotificationClass)
).apply { isAccessible = true }
} catch (_: Throwable) {
isNewWay = false
/** 旧版方法 */
lpparam.findClass(NotificationHeaderViewWrapperInjectorClass)
.getDeclaredMethod(
"setAppIcon",
ImageView::class.java,
lpparam.findClass(ExpandedNotificationClass)
).apply { isAccessible = true }
}.also {
XposedBridge.hookMethod(it, object : XC_MethodReplacement() {
override fun replaceHookedMethod(param: MethodHookParam): Any? {
runWithoutError(error = "AutoSetAppIconDoing") {
if (isNewWay)
lpparam.hookNotifyIconOnSet(
context = param.args?.get(0) as? Context ?: lpparam.globalContext
?: error("GlobalContext got null"),
param.args?.get(2) as? StatusBarNotification?,
param.args?.get(1) as ImageView
)
else
lpparam.hookNotifyIconOnSet(
context = lpparam.globalContext ?: error("GlobalContext got null"),
param.args?.get(1) as? StatusBarNotification?,
param.args?.get(0) as ImageView
)
}
return null
}
})
}
}
/** 之前的版本解决方案 */
else runWithoutError(error = "AutoSetAppIconOldWay") {
XposedHelpers.findAndHookMethod(
NotificationHeaderViewWrapperClass,
lpparam.classLoader, "handleHeaderViews",
object : XC_MethodHook() {
override fun afterHookedMethod(param: MethodHookParam) {
runWithoutError(error = "AutoSetAppIconOldWayOnSet") hook@{
/** 对于之前没有通知图标色彩判断功能的版本判断是 MIUI 样式就停止 Hook */
if (!lpparam.hasIgnoreStatusBarIconColor() && lpparam.isShowMiuiStyle()) return@hook
/** 从父类中得到 mRow 变量 - [ExpandableNotificationRowClass] */
lpparam.findClass(NotificationViewWrapperClass).getDeclaredField("mRow")
.apply {
isAccessible = true
}[param.thisObject].apply {
/** 获取小图标 */
val iconImageView = lpparam.findClass(NotificationHeaderViewWrapperClass)
.getDeclaredField("mIcon")
.apply {
isAccessible = true
}[param.thisObject] as ImageView
/** 获取其中的得到通知方法 */
val expandedNf =
javaClass.getDeclaredMethod("getStatusBarNotification").apply {
isAccessible = true
}.invoke(this) as? StatusBarNotification?
/** 执行 Hook */
lpparam.hookNotifyIconOnSet(
iconImageView.context,
expandedNf, iconImageView
)
}
}
}
}
)
}
/** 干掉下拉通知图标自动设置回 APP 图标的方法 - Android 12 */
if (isUpperOfAndroidS)
runWithoutError(error = "ResetIconBgAndPaddings") {
XposedHelpers.findAndHookMethod(
NotificationHeaderViewWrapperInjectorClass,
lpparam.classLoader,
"resetIconBgAndPaddings",
ImageView::class.java,
lpparam.findClass(ExpandedNotificationClass),
replaceToNull
)
}
logD("hook Completed!")
if (isUpperOfAndroidS &&
lpparam.isMethodExist(
NotificationHeaderViewWrapperInjectorClass,
name = "resetIconBgAndPaddings"
)
) runWithoutError(error = "ResetIconBgAndPaddings") {
XposedHelpers.findAndHookMethod(
NotificationHeaderViewWrapperInjectorClass,
lpparam.classLoader,
"resetIconBgAndPaddings",
ImageView::class.java,
lpparam.findClass(ExpandedNotificationClass),
replaceToNull
)
}
logD(content = "hook Completed!")
}
}
}

View File

@@ -48,6 +48,7 @@ object HookMedium {
/**
* 判断模块是否激活
*
* 在 [HookMain] 中 Hook 掉此方法
* @return [Boolean] 激活状态
*/
@@ -115,6 +116,7 @@ object HookMedium {
/**
* 强制设置 Sp 存储为全局可读可写
*
* 以供模块使用
* @param context 实例
*/

View File

@@ -46,6 +46,12 @@ class ConfigureActivity : BaseActivity() {
setContentView(R.layout.activity_config)
/** 返回按钮点击事件 */
findViewById<View>(R.id.title_back_icon).setOnClickListener { onBackPressed() }
/** 设置标题个数文本 */
findViewById<TextView>(R.id.config_title_count_text).text = "已适配 ${IconPackParams.iconDatas.size} 个 APP 的通知图标"
/** 设置搜索按钮点击事件 */
findViewById<View>(R.id.config_title_search).setOnClickListener {
Toast.makeText(this, "后期开放", Toast.LENGTH_SHORT).show()
}
/** 设置列表元素和 Adapter */
findViewById<ListView>(R.id.config_list_view).apply {
adapter = object : BaseAdapter() {

View File

@@ -48,12 +48,14 @@ class MainActivity : BaseActivity() {
private const val moduleVersion = BuildConfig.VERSION_NAME
}
private var isWarnDialogShowing = false // 警告对话框是否显示
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
/** 设置文本 */
findViewById<TextView>(R.id.main_text_version).text = "当前版本:$moduleVersion"
findViewById<TextView>(R.id.main_text_miui_version).text = "MIUI 版本:$miuiVersion"
findViewById<TextView>(R.id.main_text_miui_version).text = "MIUI 版本:$miuiFullVersion"
when {
/** 判断是否为 MIUI 系统 */
isNotMIUI ->
@@ -64,15 +66,24 @@ class MainActivity : BaseActivity() {
confirmButton(text = "退出") { finish() }
noCancelable()
}
/** 判断最低系统版本 */
/** 判断最低 Android 系统版本 */
isLowerAndroidP ->
showDialog {
title = "系统版本过低"
title = "Android 系统版本过低"
msg = "此模块最低支持基于 Android 9 的 MIUI 系统,你的系统版本过低不再进行适配。\n" +
"如有问题请联系 酷安 @星夜不荟"
confirmButton(text = "退出") { finish() }
noCancelable()
}
/** 判断最低 MIUI 版本 */
isNotSupportMiuiVersion ->
showDialog {
title = "MIUI 版本过低"
msg = "此模块最低支持 MIUI 12 系统,你的 MIUI 版本为 ${miuiVersion},不再进行适配。\n" +
"如有问题请联系 酷安 @星夜不荟"
confirmButton(text = "退出") { finish() }
noCancelable()
}
/** 判断是否 Hook */
isHooked() -> {
findViewById<LinearLayout>(R.id.main_lin_status).setBackgroundResource(R.drawable.green_round)
@@ -101,7 +112,7 @@ class MainActivity : BaseActivity() {
notifyIconConfigItem.isVisible = getBoolean(HookMedium.ENABLE_COLOR_ICON_HOOK, default = true)
moduleEnableLogSwitch.isVisible = getBoolean(HookMedium.ENABLE_MODULE, default = true)
moduleEnableSwitch.isChecked = getBoolean(HookMedium.ENABLE_MODULE, default = true)
moduleEnableLogSwitch.isChecked = getBoolean(HookMedium.ENABLE_MODULE_LOG, default = true)
moduleEnableLogSwitch.isChecked = getBoolean(HookMedium.ENABLE_MODULE_LOG, default = false)
hideIconInLauncherSwitch.isChecked = getBoolean(HookMedium.ENABLE_HIDE_ICON)
colorIconHookSwitch.isChecked = getBoolean(HookMedium.ENABLE_COLOR_ICON_HOOK, default = true)
notifyIconHookSwitch.isChecked = getBoolean(HookMedium.ENABLE_NOTIFY_ICON_HOOK, default = true)
@@ -175,6 +186,20 @@ class MainActivity : BaseActivity() {
}
}
override fun onResume() {
super.onResume()
/** MIUI 12 的版本特殊 - 所以给出提示 */
if (!isWarnDialogShowing && isHooked() && miuiVersion == "12" && isMiuiNotifyStyle)
showDialog {
isWarnDialogShowing = true
title = "经典通知栏样式已启用"
msg = "在 MIUI 12 中启用了经典通知栏样式后状态栏图标将不再做原生处理,模块停止工作," +
"这取决于系统设置,你应当在 设置>通知管理>通知显示设置 中将样式设置为“原生样式”。"
confirmButton(text = "我知道了") { isWarnDialogShowing = false }
noCancelable()
}
}
/**
* 判断模块是否激活
* @return [Boolean] 激活状态
@@ -183,9 +208,9 @@ class MainActivity : BaseActivity() {
/** 重启系统界面 */
private fun restartSystemUI() =
execShellCmd(cmd = "pgrep systemui").also { pid ->
execShellSu(cmd = "pgrep systemui").also { pid ->
if (pid.isNotBlank())
execShellCmd(cmd = "kill -9 $pid")
execShellSu(cmd = "kill -9 $pid")
else Toast.makeText(this, "ROOT 权限获取失败", Toast.LENGTH_SHORT).show()
}

View File

@@ -29,11 +29,11 @@ import android.content.res.Configuration
import android.graphics.*
import android.graphics.Bitmap.createBitmap
import android.os.Build
import android.provider.Settings
import android.service.notification.StatusBarNotification
import android.util.Base64
import com.fankes.miui.notify.application.MNNApplication.Companion.appContext
import java.io.DataInputStream
import java.io.DataOutputStream
import com.topjohnwu.superuser.Shell
/**
* 系统深色模式是否开启
@@ -54,6 +54,17 @@ inline val isNotSystemInDarkMode get() = !isSystemInDarkMode
*/
val Context.isSystemInDarkMode get() = (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
/**
* 通知栏是否为 MIUI 样式
* @return [Boolean] 是否符合条件
*/
val Context.isMiuiNotifyStyle
get() = try {
Settings.System.getInt(contentResolver, "status_bar_notification_style") == 0
} catch (_: Throwable) {
false
}
/**
* 系统深色模式是否没开启
* @return [Boolean] 是否开启
@@ -91,6 +102,24 @@ val isMIUI by lazy {
*/
inline val isNotMIUI get() = !isMIUI
/**
* 是否为支持的 MIUI 版本
* @return [Boolean]
*/
val isSupportMiuiVersion
get() = when (miuiVersion) {
"12" -> true
"12.5" -> true
"13" -> true
else -> false
}
/**
* 是否不为支持的 MIUI 版本
* @return [Boolean]
*/
inline val isNotSupportMiuiVersion get() = !isSupportMiuiVersion
/**
* 获取 MIUI 版本
* @return [String]
@@ -109,8 +138,16 @@ val miuiVersion
"V13" -> "13"
else -> it.replace(oldValue = "V", newValue = "")
}
} + " " + findPropString(key = "ro.system.build.version.incremental")
else "不是 MIUI 系统"
}.trim()
else "NULL"
/**
* 获取 MIUI 完全版本
* @return [String]
*/
val miuiFullVersion
get() = if (isMIUI) (miuiVersion + " " + findPropString(key = "ro.system.build.version.incremental"))
else "不是 MIUI 系统"
/**
* 获取推送通知的包名
@@ -230,28 +267,10 @@ fun findPropString(key: String, default: String = "") =
* @param cmd 命令
* @return [String] 执行结果
*/
fun execShellCmd(cmd: String): String {
var result = ""
var dos: DataOutputStream? = null
var dis: DataInputStream? = null
try {
val p = Runtime.getRuntime().exec("su")
dos = DataOutputStream(p.outputStream)
dis = DataInputStream(p.inputStream)
dos.writeBytes("$cmd\n")
dos.flush()
dos.writeBytes("exit\n")
dos.flush()
var line: String
while (dis.readLine().also { line = it } != null) result += line
p.waitFor()
} catch (_: Exception) {
} finally {
try {
dos?.close()
dis?.close()
} catch (_: Exception) {
}
fun execShellSu(cmd: String) = try {
Shell.su(cmd).exec().out.let {
if (it.isNotEmpty()) it[0].trim() else ""
}
return result.trim()
} catch (_: Throwable) {
""
}

View File

@@ -25,7 +25,15 @@ import de.robv.android.xposed.XSharedPreferences
object XPrefUtils {
fun getBoolean(key: String, default: Boolean = false) = pref.getBoolean(key, default)
private var xPrefCacheKeyValueBooleans = HashMap<String, Boolean>()
fun getBoolean(key: String, default: Boolean = false) =
xPrefCacheKeyValueBooleans[key].let {
it ?: pref.getBoolean(key, default).let { e ->
xPrefCacheKeyValueBooleans[key] = e
e
}
}
private val pref: XSharedPreferences
get() {

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#777777">
<item>
<shape android:shape="rectangle">
<solid android:color="#66DAD9D9" />
<corners android:radius="15dp" />
</shape>
</item>
</ripple>

View File

@@ -28,15 +28,40 @@
android:src="@mipmap/back"
android:tint="@color/colorTextGray" />
<TextView
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:singleLine="true"
android:text="通知图标优化名单"
android:textColor="@color/colorTextGray"
android:textSize="25sp"
android:textStyle="bold" />
android:gravity="center|start"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:singleLine="true"
android:text="通知图标优化名单"
android:textColor="@color/colorTextGray"
android:textSize="19sp"
android:textStyle="bold" />
<TextView
android:id="@+id/config_title_count_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:text="..."
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
</LinearLayout>
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/config_title_search"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginEnd="10dp"
android:src="@mipmap/icon_search"
android:tint="@color/colorTextGray" />
</LinearLayout>
<LinearLayout
@@ -64,7 +89,7 @@
android:layout_height="wrap_content"
android:alpha="0.6"
android:lineSpacingExtra="5dp"
android:text="启用替换后 APP 的彩色通知图标将被替换为预设的小图标。\n启用全替换将忽略 APP 非彩色图标,强制将全部通知图标替换为列表中预设的小图标。"
android:text="启用替换后 APP 的彩色通知图标将被替换为预设的小图标。\n启用全替换将忽略 APP 非彩色图标,强制将全部通知图标替换为列表中预设的小图标。"
android:textColor="@color/colorTextGray"
android:textSize="11sp"
tools:ignore="SmallSp" />

View File

@@ -296,7 +296,7 @@
android:layout_marginBottom="10dp"
android:alpha="0.6"
android:lineSpacingExtra="6dp"
android:text="隐藏模块图标后界面可能会被关闭,将不会再在桌面显示,你可以在 EdXposed、LsPosed 中找到模块设置并打开。"
android:text="隐藏模块图标后界面可能会被关闭,将不会再在桌面显示,你可以在 EdXposed、LSPosed 中找到模块设置并打开。"
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
</LinearLayout>
@@ -353,7 +353,7 @@
android:layout_marginBottom="10dp"
android:alpha="0.8"
android:lineSpacingExtra="6dp"
android:text="Q.如何使用?\nA.模块仅支持 EdXposed、LsPosed,由于涉及到修改系统应用,不支持太极(阴)框架,在 LsPosed 的作用域中,只需勾选“系统界面”即可,应用设置后需要重启系统界面。"
android:text="Q.如何使用?\nA.模块仅支持 LSPosedEdXposed 也可以使用但随时停止支持,由于模块涉及到修改系统应用,不支持其它 Hook 框架,在 LSPosed 的作用域中,只需勾选“系统界面”(旧版本为“系统 UI”)即可,应用设置后需要重启系统界面。"
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
@@ -363,7 +363,7 @@
android:layout_marginBottom="10dp"
android:alpha="0.8"
android:lineSpacingExtra="6dp"
android:text="Q.哪些是已知问题?\nA.MIUI 自己的系统应用的通知图标仍然可能出现黑白块的情况,可使用通知图标优化暂时修复其图标问题,后期只能等官方修复(基本上没什么可能性)。动态小图标可能会在高版本系统中闪烁,这是 MIUI 的问题,后期仍在想解决办法。"
android:text="Q.哪些是已知问题?\nA.以下是问题描述列表:\n(1) 动态小图标可能会在高版本系统中闪烁,这是 MIUI 自身就存在的问题,后期只能等官方修复。\n(2) 请始终保持最新版本的 LSPosed旧版本可能会出现 Hook 不生效的问题。"
android:textColor="@color/colorTextDark"
android:textSize="12sp" />

View File

@@ -80,7 +80,7 @@
android:id="@+id/adp_app_all_switch"
android:layout_width="wrap_content"
android:layout_height="30dp"
android:text="全替换 "
android:text="全替换 "
android:textColor="@color/colorTextGray"
android:textSize="13sp" />
</LinearLayout>