fix: The onContentUpdated hook does not work on ColorOS 16 (#85)

* fix: block coloros 15 fixSmallIcon method

* fix: hook error

* feat: complete ColorOS 15 support

* docs: update README

* misc: Add API 35 and API 36 to androidVersions CodeName

* fix: The onContentUpdated hook does not work on ColorOS 16

* refactor: update code style

---------

Co-authored-by: fankesyooni <qzmmcn@163.com>
This commit is contained in:
Timeline
2025-11-27 19:10:23 +08:00
committed by GitHub
parent 7af4c87839
commit 7ffe18b35c
2 changed files with 173 additions and 65 deletions

View File

@@ -44,6 +44,7 @@ import android.widget.ImageView
import androidx.core.graphics.drawable.toBitmap
import androidx.core.graphics.drawable.toDrawable
import androidx.core.view.children
import androidx.core.view.setPadding
import com.fankes.coloros.notify.R
import com.fankes.coloros.notify.bean.IconDataBean
import com.fankes.coloros.notify.const.PackageName
@@ -136,6 +137,12 @@ object SystemUIHooker : YukiBaseHooker() {
/** ColorOS 存在的类 - 旧版本不存在 */
private val OplusNotificationSmallIconUtilClass by lazyClassOrNull("com.oplus.systemui.statusbar.notification.util.OplusNotificationSmallIconUtil")
/** ColorOS 存在的类 - 旧版本不存在 */
private val OplusNotificationHeaderViewWrapperExImpClass by lazyClassOrNull("com.oplus.systemui.statusbar.notification.row.wrapper.OplusNotificationHeaderViewWrapperExImp")
/** ColorOS 存在的类 - 旧版本不存在 */
private val OplusNotificationGroupTemplateWrapperClass by lazyClassOrNull("com.oplus.systemui.notification.row.oplusgroup.OplusNotificationGroupTemplateWrapper")
/** 根据多个版本存在不同的包名相同的类 */
private val OplusNotificationIconAreaControllerClass by lazyClass(
VariousClass(
@@ -276,6 +283,17 @@ object SystemUIHooker : YukiBaseHooker() {
parameterCount = 2
} != null
/**
* 判断通知是否为新版本
* @return [Boolean]
*/
private val isNewNotification
get() = OplusNotificationHeaderViewWrapperExImpClass?.resolve()?.optional(silent = true)
?.firstMethodOrNull {
name = "proxyOnContentUpdated"
parameterCount = 1
} != null
/**
* 打印日志
* @param tag 标识
@@ -314,6 +332,7 @@ object SystemUIHooker : YukiBaseHooker() {
/** 刷新状态栏小图标 */
private fun refreshStatusBarIcons() = runInSafe {
if (isNewNotification) return@runInSafe
val nfField = StatusBarIconViewClass.resolve().optional().firstFieldOrNull { name = "mNotification" }
val sRadiusField = StatusBarIconViewClass.resolve().optional(silent = true).firstFieldOrNull {
name = "sIconRadiusFraction"
@@ -533,11 +552,11 @@ object SystemUIHooker : YukiBaseHooker() {
.solidColor(newApplyColor)
.build()
setColorFilter(newStyle)
setPadding(2.dp(context), 2.dp(context), 2.dp(context), 2.dp(context))
setPadding(2.dp(context))
} else {
background = null
setColorFilter(oldApplyColor)
setPadding(0, 0, 0, 0)
setPadding(0)
}
}
else -> iconView.apply {
@@ -599,7 +618,7 @@ object SystemUIHooker : YukiBaseHooker() {
}
}
/** 清除图标间距 */
setPadding(0, 0, 0, 0)
setPadding(0)
/** 清除背景 */
background = null
/** 清除着色 */
@@ -767,46 +786,6 @@ object SystemUIHooker : YukiBaseHooker() {
}
/** 注入通知控制器实例 */
StatusBarNotificationPresenterClass.resolve().optional().constructor {}.hookAll().after { notificationPresenter = instance }
/** 注入状态栏通知图标容器实例 */
OplusNotificationIconAreaControllerClass.resolve().optional().apply {
var way = 0
(firstMethodOrNull {
name = "updateIconsForLayout"
parameterCount = 10
} ?: firstMethodOrNull {
/** ColorOS 14 */
name = "updateIconsForLayout"
parameterCount = 5
} ?: firstMethodOrNull {
name = "updateIconsForLayout"
parameterCount = 1
}?.apply { way = 1 }
?: firstMethodOrNull {
name = "updateIconsForLayout"
}?.apply { way = 2 })?.hook()?.after {
when (way) {
2 -> notificationIconContainer = OplusNotificationIconAreaControllerClass.resolve().optional()
.firstMethodOrNull { name = "getNotificationIcons" }
?.of(instance)?.invoke<ViewGroup>()
1 -> {
notificationIconInstances.clear()
firstFieldOrNull { name = "mLastToShow" }?.of(instance)?.get<List<View>>()
?.takeIf { it.isNotEmpty() }?.forEach { notificationIconInstances.add(it) }
}
else -> notificationIconContainer = args(index = 1).cast()
}
}
}
/** 注入状态栏通知图标容器实例 */
(LegacyNotificationIconAreaControllerImpl ?: NotificationIconAreaControllerClass)
.resolve().optional().apply {
firstMethodOrNull {
name = "updateIconsForLayout"
parameterCount = 8
}?.hook()?.after {
notificationIconContainer = args(index = 1).cast()
}
}
/** 替换通知面板背景 - 新版本 */
if (!isOldNotificationBackground)
OplusNotificationBackgroundViewClass?.resolve()?.optional()?.apply {
@@ -876,6 +855,132 @@ object SystemUIHooker : YukiBaseHooker() {
}?.of(holder)?.invokeQuietly<View>()?.performClick()
}
}
if (isNewNotification) {
/** 替换通知图标和样式 */
OplusNotificationHeaderViewWrapperExImpClass?.resolve()?.optional()?.apply {
firstMethodOrNull {
name = "proxyOnContentUpdated"
parameterCount = 1
}?.hook()?.after {
val mBase = instance.asResolver().optional().firstMethodOrNull {
name = "getBase"
emptyParameters()
}?.invokeQuietly()
val imageView = mBase?.asResolver()?.optional()?.firstFieldOrNull {
name = "mIcon"
type = ImageView::class
}?.getQuietly<ImageView>()
imageView?.apply {
ExpandableNotificationRowClass.resolve().optional()
.firstMethodOrNull { name = "getEntry" }
?.of(args[0])?.invokeQuietly()?.let {
it.asResolver().optional().firstMethodOrNull {
name = "getSbn"
}?.invoke<StatusBarNotification>()
}.also { nf ->
nf?.notification?.also {
it.smallIcon.loadDrawable(context)?.also { iconDrawable ->
compatNotifyIcon(
context = context,
nf = nf,
isGrayscaleIcon = isGrayscaleIcon(context, iconDrawable),
packageName = context.packageName,
drawable = iconDrawable,
iconColor = it.color,
iconView = this
)
}
}
}
}
}
}
OplusNotificationGroupTemplateWrapperClass?.resolve()?.optional()?.apply {
firstMethodOrNull {
name = "initIcon"
}?.hook()?.before {
val instanceContext = firstFieldOrNull {
name = "context"
}?.of(instance)?.get() as Context?
if (instanceContext == null)
return@before
resultNull()
NotificationHeaderViewWrapperClass.resolve().optional().firstFieldOrNull { name = "mIcon" }?.of(instance)?.get<ImageView>()?.apply {
ExpandableNotificationRowClass.resolve().optional()
.firstMethodOrNull { name = "getEntry" }
?.of(NotificationViewWrapperClass.resolve().optional().firstFieldOrNull {
name = "mRow"
}?.of(instance)?.get())?.invokeQuietly()?.let {
it.asResolver().optional().firstMethodOrNull {
name = "getSbn"
}?.invoke<StatusBarNotification>()
}.also { nf ->
val context = StatusBarNotification::class.resolve().firstMethod {
name = "getPackageContext"
}.of(nf).invoke<Context>(instanceContext)
if (context == null) return@also
nf?.notification?.also {
it.smallIcon.loadDrawable(context)?.also { iconDrawable ->
compatNotifyIcon(
context = context,
nf = nf,
isGrayscaleIcon = isGrayscaleIcon(context, iconDrawable),
packageName = context.packageName,
drawable = iconDrawable,
iconColor = it.color,
iconView = this
)
}
}
}
}
}
}
} else {
/** 注入状态栏通知图标容器实例 */
OplusNotificationIconAreaControllerClass.resolve().optional().apply {
var way = 0
(firstMethodOrNull {
name = "updateIconsForLayout"
parameterCount = 10
} ?: firstMethodOrNull {
/** ColorOS 14 */
name = "updateIconsForLayout"
parameterCount = 5
} ?: firstMethodOrNull {
name = "updateIconsForLayout"
parameterCount = 1
}?.apply { way = 1 }
?: firstMethodOrNull {
name = "updateIconsForLayout"
}?.apply { way = 2 })?.hook()?.after {
when (way) {
2 -> notificationIconContainer = OplusNotificationIconAreaControllerClass.resolve().optional()
.firstMethodOrNull { name = "getNotificationIcons" }
?.of(instance)?.invoke<ViewGroup>()
1 -> {
notificationIconInstances.clear()
firstFieldOrNull { name = "mLastToShow" }?.of(instance)?.get<List<View>>()
?.takeIf { it.isNotEmpty() }?.forEach { notificationIconInstances.add(it) }
}
else -> notificationIconContainer = args(index = 1).cast()
}
}
}
/** 注入状态栏通知图标容器实例 */
(LegacyNotificationIconAreaControllerImpl ?: NotificationIconAreaControllerClass)
.resolve().optional().apply {
firstMethodOrNull {
name = "updateIconsForLayout"
parameterCount = 8
}?.hook()?.after {
notificationIconContainer = args(index = 1).cast()
}
}
/** 替换通知图标和样式 */
NotificationHeaderViewWrapperClass.resolve().optional().apply {
method {
@@ -915,4 +1020,5 @@ object SystemUIHooker : YukiBaseHooker() {
}
}
}
}
}

View File

@@ -150,6 +150,8 @@ val isRealmeUI
*/
val androidVersionCodeName
get() = when (Build.VERSION.SDK_INT) {
36 -> "B"
35 -> "V"
34 -> "U"
33 -> "T"
32 -> "S_V2"