diff --git a/app/src/main/java/com/fankes/coloros/notify/hook/entity/SystemUIHooker.kt b/app/src/main/java/com/fankes/coloros/notify/hook/entity/SystemUIHooker.kt index 2a6878a..491a665 100644 --- a/app/src/main/java/com/fankes/coloros/notify/hook/entity/SystemUIHooker.kt +++ b/app/src/main/java/com/fankes/coloros/notify/hook/entity/SystemUIHooker.kt @@ -67,6 +67,7 @@ import com.fankes.coloros.notify.utils.factory.isUpperOfAndroidS import com.fankes.coloros.notify.utils.factory.runInSafe import com.fankes.coloros.notify.utils.factory.safeOf import com.fankes.coloros.notify.utils.factory.safeOfFalse +import com.fankes.coloros.notify.utils.factory.safeOfNull import com.fankes.coloros.notify.utils.factory.systemAccentColor import com.fankes.coloros.notify.utils.tool.ActivationPromptTool import com.fankes.coloros.notify.utils.tool.BitmapCompatTool @@ -81,6 +82,7 @@ import com.highcapable.yukihookapi.hook.factory.injectModuleAppResources import com.highcapable.yukihookapi.hook.log.YLog import de.robv.android.xposed.XposedHelpers import top.defaults.drawabletoolbox.DrawableBuilder +import java.util.WeakHashMap /** * 系统界面核心 Hook 类 @@ -278,6 +280,9 @@ object SystemUIHooker : YukiBaseHooker() { /** 是否已经使用过缓存刷新功能 */ private var isUsingCachingMethod = false + + /** 记录已处理过的图标 [ImageView] - 值 true 表示本模块接管,false 表示交还系统;用于拦截判断与避免重复处理 */ + private val moduleStyledIcons = WeakHashMap() /** * 判断通知是否来自系统推送 @@ -285,6 +290,14 @@ object SystemUIHooker : YukiBaseHooker() { */ private val StatusBarNotification.isOplusPush get() = opPkg == PackageName.SYSTEM_FRAMEWORK && opPkg != packageName + /** + * 判断通知是否由系统生成 (ColorOS 16.1折叠通知) + * @return [Boolean] + */ + private fun isCollapseNotification(nfPackageName: String, contextPackageName: String) : Boolean { + return contextPackageName == PackageName.SYSTEMUI && nfPackageName != contextPackageName + } + /** * 判断通知背景是否为旧版本 * @return [Boolean] @@ -296,6 +309,14 @@ object SystemUIHooker : YukiBaseHooker() { parameterCount = 2 } != null + /** + * 取通知头部包装器的图标 [ImageView] + * @param headerWrapperExImp [OplusNotificationHeaderViewWrapperExImpClass] 实例 + * @return [ImageView] or null + */ + private fun headerIconOf(headerWrapperExImp: Any?) = + safeOfNull { XposedHelpers.getObjectField(XposedHelpers.callMethod(headerWrapperExImp, "getBase"), "mIcon") as? ImageView } + /** * 判断通知是否为新版本 * @return [Boolean] @@ -528,15 +549,20 @@ object SystemUIHooker : YukiBaseHooker() { iconView: ImageView, header: Boolean = false ) = runInSafe { - compatCustomIcon(context, isGrayscaleIcon, if (nf.isOplusPush) nf.packageName else packageName).also { customTriple -> + val realPackageName = if (nf.isOplusPush || isCollapseNotification(nf.packageName, packageName)) nf.packageName else packageName + compatCustomIcon(context, isGrayscaleIcon, realPackageName).also { customTriple -> when { ConfigData.isEnableNotifyIconForceAppIcon -> iconView.apply { + /** 标记为已处理但非本模块接管 */ + moduleStyledIcons[this] = false /** 重新设置图标 */ - setImageDrawable(appIcons[packageName] ?: context.appIconOf(packageName)) + setImageDrawable(appIcons[realPackageName] ?: context.appIconOf(realPackageName)) /** 设置默认样式 */ setDefaultNotifyIconViewStyle() } (customTriple.first != null && customTriple.third.not()) || isGrayscaleIcon -> iconView.apply { + /** 标记为本模块接管(兜底判断/防止重复处理用) */ + moduleStyledIcons[this] = true /** 设置不要裁切到边界 */ clipToOutline = false /** 重新设置图标 */ @@ -593,6 +619,8 @@ object SystemUIHooker : YukiBaseHooker() { } } else -> iconView.apply { + /** 标记为已处理但非本模块接管 */ + moduleStyledIcons[this] = false /** 重新设置图标 */ setImageDrawable(nf.compatPushingIcon(drawable)) /** 设置默认样式 */ @@ -706,22 +734,22 @@ object SystemUIHooker : YukiBaseHooker() { } /** 获取媒体会话管理器 */ - fun getMediaSessionManager(context: Context): MediaSessionManager { + /*fun getMediaSessionManager(context: Context): MediaSessionManager { if (mediaSessionManager == null) mediaSessionManager = context.getSystemService(Context.MEDIA_SESSION_SERVICE) as MediaSessionManager return mediaSessionManager!! - } + }*/ /** 判断是否为媒体通知 */ - fun isMediaNotificationAOSP(notification: Notification?): Boolean { + /*fun isMediaNotificationAOSP(notification: Notification?): Boolean { if (notification == null) return false return notification.javaClass.resolve().firstMethod { name = "isMediaNotification" }.of(notification).invoke() == true - } + }*/ /** 通过媒体会话和AOSP方法判断是否为媒体通知 */ - fun isMediaNotification(context: Context, notification: Notification, packageName: String): Boolean { + /*fun isMediaNotification(context: Context, notification: Notification, packageName: String): Boolean { if (isMediaNotificationAOSP(notification)) return true val mediaSessionManager: MediaSessionManager = getMediaSessionManager(context) @@ -731,7 +759,7 @@ object SystemUIHooker : YukiBaseHooker() { return true return false - } + }*/ /** * 刷新缓存数据 @@ -819,7 +847,7 @@ object SystemUIHooker : YukiBaseHooker() { NotificationEntryClass.resolve().optional().firstMethodOrNull { name = "getSbn" }?.of(args().first().any())?.invokeQuietly()?.also { nf -> - if (!isMediaNotification(context, nf.notification, nf.packageName)) nf.notification.smallIcon.loadDrawable(context)?.also { iconDrawable -> + nf.notification.smallIcon.loadDrawable(context)?.also { iconDrawable -> compatStatusIcon( context = context, nf = nf, @@ -953,7 +981,7 @@ object SystemUIHooker : YukiBaseHooker() { }?.invoke() }.also { nf -> nf?.notification?.also { - if (!isMediaNotification(context, it, context.packageName)) it.smallIcon.loadDrawable(context)?.also { iconDrawable -> + it.smallIcon.loadDrawable(context)?.also { iconDrawable -> compatNotifyIcon( context = context, nf = nf, @@ -977,8 +1005,7 @@ object SystemUIHooker : YukiBaseHooker() { name = "proxyOnContentUpdated" parameterCount = 1 }?.hook()?.after { - val imageView = XposedHelpers.getObjectField(XposedHelpers.callMethod(instance, "getBase"), "mIcon") as ImageView - imageView.apply { + headerIconOf(instance)?.apply { ExpandableNotificationRowClass.resolve().optional() .firstMethodOrNull { name = "getEntry" } ?.of(args[0])?.invokeQuietly()?.let { @@ -987,7 +1014,7 @@ object SystemUIHooker : YukiBaseHooker() { }?.invoke() }.also { nf -> nf?.notification?.also { - if (!isMediaNotification(context, it, context.packageName)) it.smallIcon.loadDrawable(context)?.also { iconDrawable -> + it.smallIcon.loadDrawable(context)?.also { iconDrawable -> compatNotifyIcon( context = context, nf = nf, @@ -1002,19 +1029,25 @@ object SystemUIHooker : YukiBaseHooker() { } } } + firstMethodOrNull { + name = "updateIconColor" + emptyParameters() + }?.hook()?.before { + if (moduleStyledIcons[headerIconOf(instance)] == true) resultFalse() + } } OplusNotificationGroupTemplateWrapperClass?.resolve()?.optional()?.apply { firstMethodOrNull { name = "initIcon" }?.hook()?.before { - val instanceContext = firstFieldOrNull { + /*val instanceContext = firstFieldOrNull { name = "context" }?.of(instance)?.get() as Context? if (instanceContext == null) - return@before + return@before*/ resultNull() - NotificationHeaderViewWrapperClass.resolve().optional().firstFieldOrNull { name = "mIcon" }?.of(instance)?.get()?.apply { + /*NotificationHeaderViewWrapperClass.resolve().optional().firstFieldOrNull { name = "mIcon" }?.of(instance)?.get()?.apply { ExpandableNotificationRowClass.resolve().optional() .firstMethodOrNull { name = "getEntry" } ?.of(NotificationViewWrapperClass.resolve().optional().firstFieldOrNull { @@ -1043,7 +1076,7 @@ object SystemUIHooker : YukiBaseHooker() { } } } - } + }*/ } } } else { @@ -1090,7 +1123,7 @@ object SystemUIHooker : YukiBaseHooker() { /** 替换通知图标和样式 */ NotificationHeaderViewWrapperClass.resolve().optional().apply { - method { + /*method { name { it == "updateExpandability" || it == "setExpanded" } }.hookAll().before { firstFieldOrNull { name = "mIcon" }?.of(instance)?.get()?.apply { @@ -1104,7 +1137,7 @@ object SystemUIHooker : YukiBaseHooker() { }?.invoke() }.also { nf -> nf?.notification?.also { - if (!isMediaNotification(context, it, context.packageName)) it.smallIcon.loadDrawable(context)?.also { iconDrawable -> + it.smallIcon.loadDrawable(context)?.also { iconDrawable -> /** 执行替换 */ compatNotifyIcon( context = context, @@ -1119,7 +1152,7 @@ object SystemUIHooker : YukiBaseHooker() { } } } - } + }*/ method { name { it == "resolveHeaderViews" || it == "onContentUpdated" } @@ -1135,7 +1168,7 @@ object SystemUIHooker : YukiBaseHooker() { }?.invoke() }.also { nf -> nf?.notification?.also { - if (!isMediaNotification(context, it, context.packageName)) it.smallIcon.loadDrawable(context)?.also { iconDrawable -> + it.smallIcon.loadDrawable(context)?.also { iconDrawable -> /** 执行替换 */ fun doParse() { compatNotifyIcon(