彻底修复 MIUI 12 通知图标的问题

This commit is contained in:
2022-02-06 23:29:30 +08:00
parent 485f85873c
commit 6c961f044f
6 changed files with 259 additions and 112 deletions

View File

@@ -69,6 +69,12 @@ ContrastColorUtil.getInstance().isGrayscaleIcon(drawable);
- 后来一想,也是啊,被国内生态毒害的用户,怎么可能会去想到这些问题呢,最后只能是我自作多情,还对 MIUI 留有一点情怀吧。 - 后来一想,也是啊,被国内生态毒害的用户,怎么可能会去想到这些问题呢,最后只能是我自作多情,还对 MIUI 留有一点情怀吧。
- ——来自一个无可奈何的 MIUI 老用户 - ——来自一个无可奈何的 MIUI 老用户
# 后记
- 近期重新适配了 MIUI 12、12.5、13 版本,每个版本的图标设置方法都不一样,而且改的乱七八糟的,我都要无语了,只能用了很多折中方案,毕竟我也没有那么大精力每个版本去修复,实在是累了
- 特地的把自己能有的小米手机刷成各种 MIUI 版本去为酷友做专项适配,我也是很累了,也希望你们能够多多支持,也能让 MIUI 做得更好
- MIUI 再不重写,怕是永远会变成安卓之光。雷军,金凡!!
# 许可证 # 许可证
- [GPL-3.0](https://www.gnu.org/licenses/gpl-3.0.html) - [GPL-3.0](https://www.gnu.org/licenses/gpl-3.0.html)

View File

@@ -29,7 +29,7 @@ android {
buildTypes { buildTypes {
release { release {
minifyEnabled true minifyEnabled false
signingConfig signingConfigs.debug signingConfig signingConfigs.debug
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
} }

View File

@@ -47,20 +47,34 @@ class HookMain : IXposedHookLoadPackage {
companion object { companion object {
/** 一直存在的类 */
private const val SystemUIApplicationClass = "$SYSTEMUI_PACKAGE_NAME.SystemUIApplication" private const val SystemUIApplicationClass = "$SYSTEMUI_PACKAGE_NAME.SystemUIApplication"
/** MIUI 新版本存在的类 */
private const val NotificationHeaderViewWrapperInjectorClass = private const val NotificationHeaderViewWrapperInjectorClass =
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.row.wrapper.NotificationHeaderViewWrapperInjector" "$SYSTEMUI_PACKAGE_NAME.statusbar.notification.row.wrapper.NotificationHeaderViewWrapperInjector"
/** 一直存在的类 */
private const val NotificationHeaderViewWrapperClass =
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.NotificationHeaderViewWrapper"
/** 一直存在的类 */
private const val NotificationViewWrapperClass =
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.NotificationViewWrapper"
/** 原生存在的类 */
private const val StatusBarIconViewClass = "$SYSTEMUI_PACKAGE_NAME.statusbar.StatusBarIconView" private const val StatusBarIconViewClass = "$SYSTEMUI_PACKAGE_NAME.statusbar.StatusBarIconView"
/** 原生存在的类 */
private const val ContrastColorUtilClass = "com.android.internal.util.ContrastColorUtil" private const val ContrastColorUtilClass = "com.android.internal.util.ContrastColorUtil"
/** 根据多个版本存在不同的包名相同的类 */
private val NotificationUtilClass = Pair( private val NotificationUtilClass = Pair(
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.NotificationUtil", "$SYSTEMUI_PACKAGE_NAME.statusbar.notification.NotificationUtil",
"$SYSTEMUI_PACKAGE_NAME.miui.statusbar.notification.NotificationUtil" "$SYSTEMUI_PACKAGE_NAME.miui.statusbar.notification.NotificationUtil"
) )
/** 根据多个版本存在不同的包名相同的类 */
private val ExpandedNotificationClass = Pair( private val ExpandedNotificationClass = Pair(
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.ExpandedNotification", "$SYSTEMUI_PACKAGE_NAME.statusbar.notification.ExpandedNotification",
"$SYSTEMUI_PACKAGE_NAME.miui.statusbar.ExpandedNotification" "$SYSTEMUI_PACKAGE_NAME.miui.statusbar.ExpandedNotification"
@@ -81,13 +95,6 @@ class HookMain : IXposedHookLoadPackage {
} }
} }
/** 仅作用于替换的 Hook 方法体 */
private val replaceToFalse = object : XC_MethodReplacement() {
override fun replaceHookedMethod(param: MethodHookParam?): Any {
return false
}
}
/** /**
* 忽略异常运行 * 忽略异常运行
* @param error 错误信息 * @param error 错误信息
@@ -237,7 +244,8 @@ class HookMain : IXposedHookLoadPackage {
} }
/** /**
* ⚠️ 这个是修复彩色图标的关键核心代码判断 * - 这个是修复彩色图标的关键核心代码判断
*
* 判断是否为灰度图标 - 反射执行系统方法 * 判断是否为灰度图标 - 反射执行系统方法
* @param context 实例 * @param context 实例
* @param icon 要判断的图标 * @param icon 要判断的图标
@@ -251,6 +259,30 @@ class HookMain : IXposedHookLoadPackage {
.apply { isAccessible = true }.invoke(instance, icon) as Boolean .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() =
isMethodExist(NotificationUtilClass, name = "ignoreStatusBarIconColor")
/** /**
* 获取 [ExpandedNotificationClass] 的应用名称 * 获取 [ExpandedNotificationClass] 的应用名称
* @param instance 通知实例 * @param instance 通知实例
@@ -267,27 +299,38 @@ class HookMain : IXposedHookLoadPackage {
/** /**
* 获取全局上下文 * 获取全局上下文
* @return [Context] * @return [Context] or null
*/ */
private val XC_LoadPackage.LoadPackageParam.globalContext private val XC_LoadPackage.LoadPackageParam.globalContext
get() = findClass(SystemUIApplicationClass) get() = try {
.getDeclaredMethod("getContext").apply { isAccessible = true } findClass(SystemUIApplicationClass)
.invoke(null) as Context .getDeclaredMethod("getContext").apply { isAccessible = true }
.invoke(null) as? Context?
} catch (_: Throwable) {
null
}
/** /**
* Hook 状态栏小图标 * Hook 状态栏小图标
*
* 区分系统版本 - 由于每个系统版本的方法不一样这里单独拿出来进行 Hook * 区分系统版本 - 由于每个系统版本的方法不一样这里单独拿出来进行 Hook
* @param context 实例
* @param expandedNf 通知实例
* @param param Hook Param * @param param Hook Param
*/ */
private fun XC_LoadPackage.LoadPackageParam.hookSmallIconOnSet(param: XC_MethodHook.MethodHookParam) = private fun XC_LoadPackage.LoadPackageParam.hookSmallIconOnSet(
context: Context,
expandedNf: StatusBarNotification?,
param: XC_MethodHook.MethodHookParam
) {
runWithoutError(error = "GetSmallIconOnSet") { runWithoutError(error = "GetSmallIconOnSet") {
/** 获取通知小图标 */ /** 获取通知小图标 */
val iconDrawable = (param.result as Icon).loadDrawable(globalContext) val iconDrawable = (param.result as Icon).loadDrawable(context)
/** 判断是否不是灰度图标 */ /** 判断是否不是灰度图标 */
val isNotGrayscaleIcon = !isGrayscaleIcon(globalContext, iconDrawable) val isNotGrayscaleIcon = !isGrayscaleIcon(context, iconDrawable)
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */ /** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
(param.args?.get(0) as? StatusBarNotification?)?.also { notifyInstance -> expandedNf?.also { notifyInstance ->
/** 目标彩色通知 APP 图标 */ /** 目标彩色通知 APP 图标 */
var customIcon: Icon? = null var customIcon: Icon? = null
if (HookMedium.getBoolean(HookMedium.ENABLE_COLOR_ICON_HOOK, default = true)) if (HookMedium.getBoolean(HookMedium.ENABLE_COLOR_ICON_HOOK, default = true))
@@ -319,37 +362,38 @@ class HookMain : IXposedHookLoadPackage {
"[appName] ${findAppName(notifyInstance)}" "[appName] ${findAppName(notifyInstance)}"
) { ) {
param.result = Icon.createWithBitmap( param.result = Icon.createWithBitmap(
iconDrawable.toBitmap().round(15.dp(globalContext)) iconDrawable.toBitmap().round(15.dp(context))
) )
} }
} }
} ?: logW(content = "GetSmallIconOnSet -> StatusBarNotification got null") } ?: logW(content = "GetSmallIconOnSet -> StatusBarNotification got null")
} }
}
/** /**
* Hook 通知栏小图标 * Hook 通知栏小图标
*
* 区分系统版本 - 由于每个系统版本的方法不一样这里单独拿出来进行 Hook * 区分系统版本 - 由于每个系统版本的方法不一样这里单独拿出来进行 Hook
* @param param Hook Param * @param context 实例
* @param isNew 是否为新版方式 * @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") { runWithoutError(error = "AutoSetAppIconOnSet") {
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */ /** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
(param.args?.get(if (isNew) 2 else 1) as? StatusBarNotification?)?.let { notifyInstance -> expandedNf?.let { notifyInstance ->
/** 是否 Hook 彩色通知图标 */ /** 是否 Hook 彩色通知图标 */
val isHookColorIcon = HookMedium.getBoolean(HookMedium.ENABLE_COLOR_ICON_HOOK, default = true) 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 newStyle = if (context.isSystemInDarkMode) 0xFF2D2D2D.toInt() else Color.WHITE
/** 旧版风格反色 */ /** 旧版风格反色 */
val oldStyle = if (context.isNotSystemInDarkMode) 0xFF515151.toInt() else Color.WHITE val oldStyle = if (context.isNotSystemInDarkMode) 0xFF707070.toInt() else Color.WHITE
/** 获取图标框 */
val iconImageView = param.args[if (isNew) 1 else 0] as ImageView
/** 获取通知小图标 */ /** 获取通知小图标 */
val iconDrawable = notifyInstance.notification.smallIcon.loadDrawable(context) val iconDrawable = notifyInstance.notification.smallIcon.loadDrawable(context)
@@ -431,70 +475,75 @@ class HookMain : IXposedHookLoadPackage {
} }
} ?: logW(content = "AutoSetAppIconOnSet -> StatusBarNotification got null") } ?: logW(content = "AutoSetAppIconOnSet -> StatusBarNotification got null")
} }
}
/** /**
* Hook 通知栏小图标颜色 * Hook 通知栏小图标颜色
*
* 区分系统版本 - 由于每个系统版本的方法不一样这里单独拿出来进行 Hook * 区分系统版本 - 由于每个系统版本的方法不一样这里单独拿出来进行 Hook
* @param context 实例
* @param expandedNf 状态栏实例 * @param expandedNf 状态栏实例
* @return [Boolean] 是否忽略通知图标颜色 * @return [Boolean] 是否忽略通知图标颜色
*/ */
private fun XC_LoadPackage.LoadPackageParam.hookIgnoreStatusBarIconColor(expandedNf: StatusBarNotification?) = private fun XC_LoadPackage.LoadPackageParam.hookIgnoreStatusBarIconColor(
if (HookMedium.getBoolean(HookMedium.ENABLE_COLOR_ICON_HOOK, default = true)) context: Context,
try { expandedNf: StatusBarNotification?
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */ ) = if (HookMedium.getBoolean(HookMedium.ENABLE_COLOR_ICON_HOOK, default = true))
expandedNf?.let { notifyInstance -> try {
/** 获取通知小图标 */ /** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
val iconDrawable = expandedNf?.let { notifyInstance ->
notifyInstance.notification.smallIcon.loadDrawable(globalContext) /** 获取通知小图标 */
val iconDrawable =
notifyInstance.notification.smallIcon.loadDrawable(context)
/** 判断是否不是灰度图标 */ /** 判断是否不是灰度图标 */
val isNotGrayscaleIcon = !isGrayscaleIcon(globalContext, iconDrawable) val isNotGrayscaleIcon = !isGrayscaleIcon(context, iconDrawable)
/** 获取目标修复彩色图标的 APP */ /** 获取目标修复彩色图标的 APP */
var isTargetApp = false var isTargetApp = false
run { run {
IconPackParams.iconDatas.forEach { IconPackParams.iconDatas.forEach {
if ((notifyInstance.opPkgName == it.packageName || if ((notifyInstance.opPkgName == it.packageName ||
findAppName(notifyInstance) == it.appName) && findAppName(notifyInstance) == it.appName) &&
HookMedium.isAppNotifyHookOf(it) HookMedium.isAppNotifyHookOf(it)
) { ) {
if (isNotGrayscaleIcon || HookMedium.isAppNotifyHookAllOf(it)) isTargetApp = true if (isNotGrayscaleIcon || HookMedium.isAppNotifyHookAllOf(it)) isTargetApp = true
return@run 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) { /** 如果开启了修复 APP 的彩色图标 */
logE("Failed to hook ignoreStatusBarIconColor", e) if (isTargetApp && HookMedium.getBoolean(HookMedium.ENABLE_NOTIFY_ICON_HOOK, default = true)) let {
false 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
} }
else let { } catch (e: Exception) {
logD(content = "IgnoreStatusBarIconColor -> hook NonColor AppIcon") logE("Failed to hook ignoreStatusBarIconColor", e)
false false
} }
else let {
logD(content = "IgnoreStatusBarIconColor -> hook NonColor AppIcon")
false
}
override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) { override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) {
if (lpparam == null) return if (lpparam == null) return
@@ -532,11 +581,18 @@ class HookMain : IXposedHookLoadPackage {
lpparam.classLoader, lpparam.classLoader,
"shouldSubstituteSmallIcon", "shouldSubstituteSmallIcon",
lpparam.findClass(ExpandedNotificationClass), lpparam.findClass(ExpandedNotificationClass),
replaceToFalse object : XC_MethodReplacement() {
override fun replaceHookedMethod(param: MethodHookParam) =
/**
* 因为之前的 MIUI 版本的状态栏图标颜色会全部设置为白色的 - 找不到修复的地方就直接判断版本了
* 对于之前没有通知图标色彩判断功能的版本判断是 MIUI 样式就停止 Hook
*/
if (lpparam.hasIgnoreStatusBarIconColor()) false else lpparam.isShowMiuiStyle()
}
) )
} }
/** 修复通知图标为彩色 */ /** 修复通知图标为彩色 */
if (lpparam.isMethodExist(NotificationUtilClass, name = "ignoreStatusBarIconColor")) if (lpparam.hasIgnoreStatusBarIconColor())
runWithoutError(error = "IgnoreStatusBarIconColor") { runWithoutError(error = "IgnoreStatusBarIconColor") {
XposedHelpers.findAndHookMethod( XposedHelpers.findAndHookMethod(
lpparam.existClass(NotificationUtilClass), lpparam.existClass(NotificationUtilClass),
@@ -545,42 +601,53 @@ class HookMain : IXposedHookLoadPackage {
lpparam.findClass(ExpandedNotificationClass), lpparam.findClass(ExpandedNotificationClass),
object : XC_MethodReplacement() { object : XC_MethodReplacement() {
override fun replaceHookedMethod(param: MethodHookParam) = override fun replaceHookedMethod(param: MethodHookParam) =
lpparam.hookIgnoreStatusBarIconColor(param.args?.get(0) as? StatusBarNotification?) lpparam.hookIgnoreStatusBarIconColor(
context = lpparam.globalContext ?: error("GlobalContext got null"),
param.args?.get(0) as? StatusBarNotification?
)
} }
) )
} }
else /** 之前的版本解决方案 */
runWithoutError(error = "UpdateIconColor") { else runWithoutError(error = "UpdateIconColor") {
XposedHelpers.findAndHookMethod( XposedHelpers.findAndHookMethod(
StatusBarIconViewClass, StatusBarIconViewClass,
lpparam.classLoader, "updateIconColor", lpparam.classLoader, "updateIconColor",
object : XC_MethodHook() { object : XC_MethodHook() {
override fun afterHookedMethod(param: MethodHookParam) = override fun afterHookedMethod(param: MethodHookParam) =
runWithoutError(error = "UpdateIconColorOnSet") { runWithoutError(error = "UpdateIconColorOnSet") hook@{
/** 是否忽略图标颜色 */ /** 对于之前没有通知图标色彩判断功能的版本判断是 MIUI 样式就停止 Hook */
val isIgnoredColor = lpparam.hookIgnoreStatusBarIconColor( if (lpparam.isShowMiuiStyle()) return@hook
param.thisObject.javaClass.getDeclaredField("mNotification").apply { /** 获取自身 */
isAccessible = true val iconImageView = param.thisObject as ImageView
}[param.thisObject] as? StatusBarNotification?
)
/** 当前着色颜色 */ /** 是否忽略图标颜色 */
val currentColor = val isIgnoredColor = lpparam.hookIgnoreStatusBarIconColor(
param.thisObject.javaClass.getDeclaredField("mCurrentSetColor").apply { iconImageView.context,
isAccessible = true param.thisObject.javaClass.getDeclaredField("mNotification").apply {
}[param.thisObject] as? Int ?: Color.WHITE isAccessible = true
/** 判断并设置颜色 */ }[param.thisObject] as? StatusBarNotification?
if (isIgnoredColor) )
(param.thisObject as? ImageView?)?.colorFilter = null
else (param.thisObject as? ImageView?)?.setColorFilter(currentColor) /** 当前着色颜色 */
logD(content = "IgnoreStatusBarIconColor[UseOldWay] -> isIgnored[$isIgnoredColor]") 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") { runWithoutError(error = "GetSmallIcon") {
var isTooOld: Boolean
try { try {
isTooOld = false
/** 新版方法 */ /** 新版方法 */
lpparam.findClass(NotificationUtilClass) lpparam.findClass(NotificationUtilClass)
.getDeclaredMethod( .getDeclaredMethod(
@@ -590,11 +657,13 @@ class HookMain : IXposedHookLoadPackage {
).apply { isAccessible = true } ).apply { isAccessible = true }
} catch (_: Throwable) { } catch (_: Throwable) {
try { try {
isTooOld = false
/** 旧版方法 */ /** 旧版方法 */
lpparam.findClass(NotificationUtilClass) lpparam.findClass(NotificationUtilClass)
.getDeclaredMethod("getSmallIcon", lpparam.findClass(ExpandedNotificationClass)) .getDeclaredMethod("getSmallIcon", lpparam.findClass(ExpandedNotificationClass))
.apply { isAccessible = true } .apply { isAccessible = true }
} catch (_: Throwable) { } catch (_: Throwable) {
isTooOld = true
/** 超旧版方法 */ /** 超旧版方法 */
lpparam.findClass(NotificationUtilClass) lpparam.findClass(NotificationUtilClass)
.getDeclaredMethod( .getDeclaredMethod(
@@ -606,7 +675,12 @@ class HookMain : IXposedHookLoadPackage {
}.also { }.also {
XposedBridge.hookMethod(it, object : XC_MethodHook() { XposedBridge.hookMethod(it, object : XC_MethodHook() {
override fun afterHookedMethod(param: MethodHookParam) { override fun afterHookedMethod(param: MethodHookParam) {
lpparam.hookSmallIconOnSet(param) /** 对于之前没有通知图标色彩判断功能的版本判断是 MIUI 样式就停止 Hook */
if (!lpparam.hasIgnoreStatusBarIconColor() && lpparam.isShowMiuiStyle()) return
lpparam.hookSmallIconOnSet(
context = lpparam.globalContext ?: param.args[0] as Context,
param.args?.get(if (isTooOld) 1 else 0) as? StatusBarNotification?, param
)
} }
}) })
} }
@@ -636,13 +710,62 @@ class HookMain : IXposedHookLoadPackage {
}.also { }.also {
XposedBridge.hookMethod(it, object : XC_MethodReplacement() { XposedBridge.hookMethod(it, object : XC_MethodReplacement() {
override fun replaceHookedMethod(param: MethodHookParam): Any? { override fun replaceHookedMethod(param: MethodHookParam): Any? {
lpparam.hookNotifyIconOnSet(param, isNew = isNewWay) 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 return null
} }
}) })
} }
} }
else logW(content = "Your MIUI Version $miuiVersion is too old and not support for RowsIcon") /** 之前的版本解决方案 */
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 变量 */
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 */ /** 干掉下拉通知图标自动设置回 APP 图标的方法 - Android 12 */
if (isUpperOfAndroidS && if (isUpperOfAndroidS &&
lpparam.isMethodExist( lpparam.isMethodExist(

View File

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

View File

@@ -99,6 +99,15 @@ class MainActivity : BaseActivity() {
noCancelable() noCancelable()
} }
} }
/** MIUI 12 的版本特殊 - 所以给出提示 */
if (miuiVersion == "12" && isMiuiNotifyStyle)
showDialog {
title = "经典通知栏样式已启用"
msg = "在 MIUI 12 中启用了经典通知栏样式后状态栏图标将不再做原生处理,模块停止工作," +
"这取决于系统设置,你应当在 设置>通知管理>通知显示设置 中将样式设置为“原生样式”。"
confirmButton(text = "我知道了")
noCancelable()
}
/** 初始化 View */ /** 初始化 View */
val moduleEnableSwitch = findViewById<SwitchCompat>(R.id.module_enable_switch) val moduleEnableSwitch = findViewById<SwitchCompat>(R.id.module_enable_switch)
val moduleEnableLogSwitch = findViewById<SwitchCompat>(R.id.module_enable_log_switch) val moduleEnableLogSwitch = findViewById<SwitchCompat>(R.id.module_enable_log_switch)

View File

@@ -29,6 +29,7 @@ import android.content.res.Configuration
import android.graphics.* import android.graphics.*
import android.graphics.Bitmap.createBitmap import android.graphics.Bitmap.createBitmap
import android.os.Build import android.os.Build
import android.provider.Settings
import android.service.notification.StatusBarNotification import android.service.notification.StatusBarNotification
import android.util.Base64 import android.util.Base64
import com.fankes.miui.notify.application.MNNApplication.Companion.appContext import com.fankes.miui.notify.application.MNNApplication.Companion.appContext
@@ -54,6 +55,12 @@ inline val isNotSystemInDarkMode get() = !isSystemInDarkMode
*/ */
val Context.isSystemInDarkMode get() = (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES 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() = Settings.System.getInt(contentResolver, "status_bar_notification_style") == 0
/** /**
* 系统深色模式是否没开启 * 系统深色模式是否没开启
* @return [Boolean] 是否开启 * @return [Boolean] 是否开启