refactor: migrate and update to YukiHookAPI 1.3.0

This commit is contained in:
2025-06-25 23:22:49 +08:00
parent 9b9eda8a39
commit 29b14a811e
10 changed files with 223 additions and 208 deletions

View File

@@ -81,6 +81,8 @@ dependencies {
compileOnly(de.robv.android.xposed.api) compileOnly(de.robv.android.xposed.api)
implementation(com.highcapable.yukihookapi.api) implementation(com.highcapable.yukihookapi.api)
ksp(com.highcapable.yukihookapi.ksp.xposed) ksp(com.highcapable.yukihookapi.ksp.xposed)
implementation(com.highcapable.kavaref.kavaref.core)
implementation(com.highcapable.kavaref.kavaref.extension)
implementation(com.fankes.projectpromote.project.promote) implementation(com.fankes.projectpromote.project.promote)
implementation(com.github.topjohnwu.libsu.core) implementation(com.github.topjohnwu.libsu.core)
implementation(com.github.duanhong169.drawabletoolbox) implementation(com.github.duanhong169.drawabletoolbox)

View File

@@ -22,11 +22,9 @@
*/ */
package com.fankes.coloros.notify.hook.entity package com.fankes.coloros.notify.hook.entity
import android.app.Notification
import com.highcapable.kavaref.KavaRef.Companion.resolve
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
import com.highcapable.yukihookapi.hook.factory.method
import com.highcapable.yukihookapi.hook.type.android.NotificationClass
import com.highcapable.yukihookapi.hook.type.java.BooleanType
import com.highcapable.yukihookapi.hook.type.java.StringClass
/** /**
* 系统框架核心 Hook 类 * 系统框架核心 Hook 类
@@ -38,9 +36,9 @@ object FrameworkHooker : YukiBaseHooker() {
override fun onHook() { override fun onHook() {
/** 拦截 ColorOS 覆盖应用通知图标 */ /** 拦截 ColorOS 覆盖应用通知图标 */
OplusNotificationFixHelperClass?.method { OplusNotificationFixHelperClass?.resolve()?.optional()?.firstMethodOrNull {
name = "fixSmallIcon" name = "fixSmallIcon"
param(NotificationClass, StringClass, StringClass, BooleanType) parameters(Notification::class, String::class, String::class, Boolean::class)
}?.ignored()?.hook()?.intercept() }?.hook()?.intercept()
} }
} }

View File

@@ -68,26 +68,12 @@ import com.fankes.coloros.notify.utils.tool.ActivationPromptTool
import com.fankes.coloros.notify.utils.tool.BitmapCompatTool import com.fankes.coloros.notify.utils.tool.BitmapCompatTool
import com.fankes.coloros.notify.utils.tool.IconAdaptationTool import com.fankes.coloros.notify.utils.tool.IconAdaptationTool
import com.fankes.coloros.notify.utils.tool.SystemUITool import com.fankes.coloros.notify.utils.tool.SystemUITool
import com.highcapable.yukihookapi.hook.bean.VariousClass import com.highcapable.kavaref.KavaRef.Companion.resolve
import com.highcapable.kavaref.condition.type.VagueType
import com.highcapable.kavaref.extension.VariousClass
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
import com.highcapable.yukihookapi.hook.factory.constructor
import com.highcapable.yukihookapi.hook.factory.current
import com.highcapable.yukihookapi.hook.factory.field
import com.highcapable.yukihookapi.hook.factory.hasMethod
import com.highcapable.yukihookapi.hook.factory.injectModuleAppResources import com.highcapable.yukihookapi.hook.factory.injectModuleAppResources
import com.highcapable.yukihookapi.hook.factory.method
import com.highcapable.yukihookapi.hook.log.YLog import com.highcapable.yukihookapi.hook.log.YLog
import com.highcapable.yukihookapi.hook.type.android.ContextClass
import com.highcapable.yukihookapi.hook.type.android.DrawableClass
import com.highcapable.yukihookapi.hook.type.android.IconClass
import com.highcapable.yukihookapi.hook.type.android.ImageViewClass
import com.highcapable.yukihookapi.hook.type.android.NotificationClass
import com.highcapable.yukihookapi.hook.type.android.StatusBarNotificationClass
import com.highcapable.yukihookapi.hook.type.defined.VagueType
import com.highcapable.yukihookapi.hook.type.java.BooleanType
import com.highcapable.yukihookapi.hook.type.java.FloatType
import com.highcapable.yukihookapi.hook.type.java.IntType
import com.highcapable.yukihookapi.hook.type.java.LongType
import top.defaults.drawabletoolbox.DrawableBuilder import top.defaults.drawabletoolbox.DrawableBuilder
/** /**
@@ -135,8 +121,7 @@ object SystemUIHooker : YukiBaseHooker() {
private val OplusContrastColorUtilClass by lazyClassOrNull("com.oplusos.util.OplusContrastColorUtil") private val OplusContrastColorUtilClass by lazyClassOrNull("com.oplusos.util.OplusContrastColorUtil")
/** ColorOS 存在的类 - 旧版本不存在 */ /** ColorOS 存在的类 - 旧版本不存在 */
private val OplusNotificationBackgroundViewClass by lazyClassOrNull( private val OplusNotificationBackgroundViewClass by lazyClassOrNull("com.oplusos.systemui.statusbar.notification.row.OplusNotificationBackgroundView")
"com.oplusos.systemui.statusbar.notification.row.OplusNotificationBackgroundView")
/** ColorOS 存在的类 - 旧版本不存在 */ /** ColorOS 存在的类 - 旧版本不存在 */
private val OplusMediaControlPanelClass by lazyClassOrNull("com.oplusos.systemui.media.OplusMediaControlPanel") private val OplusMediaControlPanelClass by lazyClassOrNull("com.oplusos.systemui.media.OplusMediaControlPanel")
@@ -284,10 +269,11 @@ object SystemUIHooker : YukiBaseHooker() {
* @return [Boolean] * @return [Boolean]
*/ */
private val isOldNotificationBackground private val isOldNotificationBackground
get() = NotificationBackgroundViewClass?.hasMethod { get() = NotificationBackgroundViewClass?.resolve()?.optional(silent = true)
name = "drawCustom" ?.firstMethodOrNull {
paramCount = 2 name = "drawCustom"
} ?: false parameterCount = 2
} != null
/** /**
* 打印日志 * 打印日志
@@ -327,28 +313,25 @@ object SystemUIHooker : YukiBaseHooker() {
/** 刷新状态栏小图标 */ /** 刷新状态栏小图标 */
private fun refreshStatusBarIcons() = runInSafe { private fun refreshStatusBarIcons() = runInSafe {
val nfField = StatusBarIconViewClass.field { name = "mNotification" } val nfField = StatusBarIconViewClass.resolve().optional().firstFieldOrNull { name = "mNotification" }
val sRadiusField = StatusBarIconViewClass.field { val sRadiusField = StatusBarIconViewClass.resolve().optional(silent = true).firstFieldOrNull {
name = "sIconRadiusFraction" name = "sIconRadiusFraction"
}.remedys { } ?: StatusBarIconControllerClass.resolve().optional(silent = true).firstFieldOrNull { name = "sIconRadiusFraction" }
StatusBarIconControllerClass.field { name = "sIconRadiusFraction" } val sNfSizeField = StatusBarIconViewClass.resolve().optional(silent = true).firstFieldOrNull {
}
val sNfSizeField = StatusBarIconViewClass.field {
name = "sNotificationRoundIconSize" name = "sNotificationRoundIconSize"
}.remedys { } ?: StatusBarIconControllerClass.resolve().optional(silent = true).firstFieldOrNull { name = "sNotificationRoundIconSize" }
StatusBarIconControllerClass.field { name = "sNotificationRoundIconSize" } val roundUtil = RoundRectDrawableUtil_CompanionClass.resolve().optional(silent = true).firstMethodOrNull {
}
val roundUtil = RoundRectDrawableUtil_CompanionClass.method {
name = "getRoundRectDrawable" name = "getRoundRectDrawable"
param(DrawableClass, FloatType, IntType, IntType, ContextClass) parameters(Drawable::class, Float::class, Int::class, Int::class, Context::class)
}.onNoSuchMethod { YLog.error("Your system not support \"getRoundRectDrawable\"!", it) } }.apply {
.get(RoundRectDrawableUtilClass.field { name = "Companion" }.get().any()) if (this == null) YLog.error("Your system not support \"getRoundRectDrawable\"!")
}?.of(RoundRectDrawableUtilClass.resolve().optional().firstFieldOrNull { name = "Companion" }?.get())
/** 启动一个线程防止卡顿 */ /** 启动一个线程防止卡顿 */
Thread { Thread {
(notificationIconContainer?.children?.toList() ?: notificationIconInstances.takeIf { it.isNotEmpty() })?.forEach { (notificationIconContainer?.children?.toList() ?: notificationIconInstances.takeIf { it.isNotEmpty() })?.forEach {
runInSafe { runInSafe {
/** 得到通知实例 */ /** 得到通知实例 */
val nf = nfField.get(it).cast<StatusBarNotification>() ?: return@Thread val nf = nfField?.of(it)?.get<StatusBarNotification>() ?: return@Thread
/** 得到原始通知图标 */ /** 得到原始通知图标 */
val iconDrawable = nf.notification.smallIcon.loadDrawable(it.context) val iconDrawable = nf.notification.smallIcon.loadDrawable(it.context)
@@ -362,12 +345,16 @@ object SystemUIHooker : YukiBaseHooker() {
drawable = iconDrawable drawable = iconDrawable
).also { pair -> ).also { pair ->
/** 得到图标圆角 */ /** 得到图标圆角 */
val sRadius = sRadiusField.get(it).float() val sRadius = sRadiusField?.of(it)?.get<Float>()
/** 得到缩放大小 */ /** 得到缩放大小 */
val sNfSize = sNfSizeField.get(it).int() val sNfSize = sNfSizeField?.of(it)?.get<Int>()
/** 在主线程设置图标 */ /** 在主线程设置图标 */
it.post { (it as? ImageView?)?.setImageDrawable(roundUtil.invoke(pair.first, sRadius, sNfSize, sNfSize, it.context)) } it.post {
val drawable = roundUtil?.invokeQuietly<Drawable>(pair.first, sRadius, sNfSize, sNfSize, it.context)
(it as? ImageView?)?.setImageDrawable(drawable)
}
} }
} }
} }
@@ -376,10 +363,10 @@ object SystemUIHooker : YukiBaseHooker() {
/** 刷新通知小图标 */ /** 刷新通知小图标 */
private fun refreshNotificationIcons() = runInSafe { private fun refreshNotificationIcons() = runInSafe {
notificationPresenter?.current()?.method { notificationPresenter?.resolve()?.optional()?.firstMethodOrNull {
name = "updateNotificationsOnDensityOrFontScaleChanged" name = "updateNotificationsOnDensityOrFontScaleChanged"
emptyParam() emptyParameters()
}?.call() }?.invoke()
modifyNotifyPanelAlpha(notificationPlayerView, isTint = true) modifyNotifyPanelAlpha(notificationPlayerView, isTint = true)
} }
@@ -393,15 +380,19 @@ object SystemUIHooker : YukiBaseHooker() {
*/ */
private fun isGrayscaleIcon(context: Context, drawable: Drawable) = private fun isGrayscaleIcon(context: Context, drawable: Drawable) =
if (ConfigData.isEnableColorIconCompat.not()) safeOfFalse { if (ConfigData.isEnableColorIconCompat.not()) safeOfFalse {
ContrastColorUtilClass.let { ContrastColorUtilClass.resolve()
it.method { .optional(silent = true)
name = "isGrayscaleIcon" .let {
param(DrawableClass) it.firstMethodOrNull {
}.get(it.method { name = "isGrayscaleIcon"
name = "getInstance" parameters(Drawable::class)
param(ContextClass) }?.of(
}.get().invoke(context)).boolean(drawable) it.firstMethodOrNull {
} name = "getInstance"
parameters(Context::class)
}?.invoke(context)
)?.invokeQuietly<Boolean>(drawable) == true
}
} else BitmapCompatTool.isGrayscaleDrawable(drawable) } else BitmapCompatTool.isGrayscaleDrawable(drawable)
/** /**
@@ -430,7 +421,11 @@ object SystemUIHooker : YukiBaseHooker() {
context.injectModuleAppResources() context.injectModuleAppResources()
var customPair: Triple<Drawable?, Int, Boolean>? = null var customPair: Triple<Drawable?, Int, Boolean>? = null
val statSysAdbIcon = runCatching { val statSysAdbIcon = runCatching {
context.resources.drawableOf("com.android.internal.R\$drawable".toClass().field { name = "stat_sys_adb" }.get().int()) val resId = "com.android.internal.R\$drawable".toClass()
.resolve()
.firstField { name = "stat_sys_adb" }
.get<Int>() ?: error("Resource not found")
context.resources.drawableOf(resId)
}.getOrNull() ?: context.resources.drawableOf(R.drawable.ic_unsupported) }.getOrNull() ?: context.resources.drawableOf(R.drawable.ic_unsupported)
when { when {
/** 替换系统图标为 Android 默认 */ /** 替换系统图标为 Android 默认 */
@@ -681,61 +676,66 @@ object SystemUIHooker : YukiBaseHooker() {
/** 缓存图标数据 */ /** 缓存图标数据 */
cachingIconDatas() cachingIconDatas()
/** 移除开发者警告通知 */ /** 移除开发者警告通知 */
SystemPromptControllerClass.method { SystemPromptControllerClass.resolve().optional().firstMethodOrNull {
name = "updateDeveloperMode" name = "updateDeveloperMode"
}.hook().before { }?.hook()?.before {
/** 是否移除 */ /** 是否移除 */
if (ConfigData.isEnableRemoveDevNotify) resultNull() if (ConfigData.isEnableRemoveDevNotify) resultNull()
} }
/** 移除充电完成通知 */ /** 移除充电完成通知 */
OplusPowerNotificationWarningsClass.method { OplusPowerNotificationWarningsClass.resolve().optional().firstMethodOrNull {
name = "showChargeErrorDialog" name = "showChargeErrorDialog"
param(IntType) parameters(Int::class)
}.hook().before { }?.hook()?.before {
/** 是否移除 */ /** 是否移除 */
if (args().first().int() == 7 && ConfigData.isEnableRemoveChangeCompleteNotify) resultNull() if (args().first().int() == 7 && ConfigData.isEnableRemoveChangeCompleteNotify) resultNull()
} }
/** 移除免打扰通知 */ /** 移除免打扰通知 */
DndAlertHelperClass.method { DndAlertHelperClass.resolve().optional(silent = true).apply {
name { it.lowercase() == "sendnotificationwithendtime" } firstMethodOrNull {
param(LongType) name { it.lowercase() == "sendnotificationwithendtime" }
}.remedys { parameters(Long::class)
method { }?.hook()?.before {
name = "operateNotification" /** 是否移除 */
param(LongType, IntType, BooleanType) if (ConfigData.isEnableRemoveDndAlertNotify) resultNull()
}
firstMethodOrNull {
name = "operateNotification"
parameters(Long::class, Int::class, Boolean::class)
}?.hook()?.before {
/** 是否移除 */
if (ConfigData.isEnableRemoveDndAlertNotify) resultNull()
} }
}.hook().before {
/** 是否移除 */
if (ConfigData.isEnableRemoveDndAlertNotify) resultNull()
} }
/** 拦截ColorOS使用应用图标判断 */ /** 拦截 ColorOS 使用应用图标判断 */
OplusNotificationSmallIconUtilClass?.method { OplusNotificationSmallIconUtilClass?.resolve()?.optional()?.firstMethodOrNull {
name = "useAppIconForSmallIcon" name = "useAppIconForSmallIcon"
param(NotificationClass) parameters(Notification::class)
}?.hook()?.before { }?.hook()?.before {
resultFalse() resultFalse()
} }
/** 修复并替换 ColorOS 以及原生灰度图标色彩判断 */ /** 修复并替换 ColorOS 以及原生灰度图标色彩判断 */
NotificationUtilsClass.apply { NotificationUtilsClass.resolve().optional(silent = true).apply {
method { firstMethodOrNull {
name = "isGrayscale" name = "isGrayscale"
param(ImageViewClass, ContrastColorUtilClass) parameters(ImageView::class, ContrastColorUtilClass)
}.hook().replaceAny { args().first().cast<ImageView>()?.let { isGrayscaleIcon(it.context, it.drawable) } ?: callOriginal() } }?.hook()?.replaceAny { args().first().cast<ImageView>()?.let { isGrayscaleIcon(it.context, it.drawable) } ?: callOriginal() }
method { firstMethodOrNull {
name = "isGrayscaleOplus" name = "isGrayscaleOplus"
param(ImageViewClass, OplusContrastColorUtilClass ?: VagueType) parameters(ImageView::class, OplusContrastColorUtilClass ?: VagueType)
}.ignored().hook().replaceAny { args().first().cast<ImageView>()?.let { isGrayscaleIcon(it.context, it.drawable) } ?: callOriginal() } }?.hook()?.replaceAny { args().first().cast<ImageView>()?.let { isGrayscaleIcon(it.context, it.drawable) } ?: callOriginal() }
} }
/** 替换状态栏图标 */ /** 替换状态栏图标 */
IconManagerClass.method { IconManagerClass.resolve().optional().firstMethodOrNull {
name = "getIconDescriptor" name = "getIconDescriptor"
param(NotificationEntryClass, BooleanType) parameters(NotificationEntryClass, Boolean::class)
}.hook().after { }?.hook()?.after {
IconBuilderClass.field { name = "context" } IconBuilderClass.resolve().optional().firstFieldOrNull { name = "context" }
.get(IconManagerClass.field { name = "iconBuilder" }.get(instance).cast()).cast<Context>()?.also { context -> ?.of(IconManagerClass.resolve().optional().firstFieldOrNull { name = "iconBuilder" }?.of(instance)?.get())
NotificationEntryClass.method { ?.getQuietly<Context>()?.also { context ->
NotificationEntryClass.resolve().optional().firstMethodOrNull {
name = "getSbn" name = "getSbn"
}.get(args().first().any()).invoke<StatusBarNotification>()?.also { nf -> }?.of(args().first().any())?.invokeQuietly<StatusBarNotification>()?.also { nf ->
nf.notification.smallIcon.loadDrawable(context)?.also { iconDrawable -> nf.notification.smallIcon.loadDrawable(context)?.also { iconDrawable ->
compatStatusIcon( compatStatusIcon(
context = context, context = context,
@@ -747,171 +747,148 @@ object SystemUIHooker : YukiBaseHooker() {
packageName = nf.packageName, packageName = nf.packageName,
drawable = iconDrawable drawable = iconDrawable
).also { pair -> ).also { pair ->
if (pair.second) StatusBarIconClass.field { if (pair.second) StatusBarIconClass.resolve().optional().firstFieldOrNull {
name = "icon" name = "icon"
type = IconClass type = Icon::class
}.get(result).set(Icon.createWithBitmap(pair.first.toBitmap())) }?.of(result)?.set(Icon.createWithBitmap(pair.first.toBitmap()))
} }
} }
} }
} }
} }
/** 得到状态栏图标实例 */ /** 得到状态栏图标实例 */
StatusBarIconViewClass.method { StatusBarIconViewClass.resolve().optional().firstMethodOrNull {
name = "setNotification" name = "setNotification"
param(StatusBarNotificationClass) parameters(StatusBarNotification::class)
}.hook().after { }?.hook()?.after {
/** 注册壁纸颜色监听 */ /** 注册壁纸颜色监听 */
if (args().first().any() != null) instance<ImageView>().also { registerWallpaperColorChanged(it) } if (args().first().any() != null) instance<ImageView>().also { registerWallpaperColorChanged(it) }
} }
/** 注入通知控制器实例 */ /** 注入通知控制器实例 */
StatusBarNotificationPresenterClass.constructor().hookAll().after { notificationPresenter = instance } StatusBarNotificationPresenterClass.resolve().optional().constructor {}.hookAll().after { notificationPresenter = instance }
/** 注入状态栏通知图标容器实例 */ /** 注入状态栏通知图标容器实例 */
OplusNotificationIconAreaControllerClass.apply { OplusNotificationIconAreaControllerClass.resolve().optional().apply {
var way = 0 var way = 0
method { (firstMethodOrNull {
name = "updateIconsForLayout" name = "updateIconsForLayout"
paramCount = 10 parameterCount = 10
}.remedys { } ?: firstMethodOrNull {
/** ColorOS 14 */ /** ColorOS 14 */
method { name = "updateIconsForLayout"
parameterCount = 5
} ?: firstMethodOrNull {
name = "updateIconsForLayout"
parameterCount = 1
}?.apply { way = 1 }
?: firstMethodOrNull {
name = "updateIconsForLayout" name = "updateIconsForLayout"
paramCount = 5 }?.apply { way = 2 })?.hook()?.after {
}
method {
name = "updateIconsForLayout"
paramCount = 1
}.onFind { way = 1 }
method {
name = "updateStatusBarIcons"
}.onFind { way = 2 }
}.hook().after {
when (way) { when (way) {
2 -> notificationIconContainer = OplusNotificationIconAreaControllerClass.method { name = "getNotificationIcons" }.get(instance).invoke() 2 -> notificationIconContainer = OplusNotificationIconAreaControllerClass.resolve().optional()
.firstMethodOrNull { name = "getNotificationIcons" }
?.of(instance)?.invoke<ViewGroup>()
1 -> { 1 -> {
notificationIconInstances.clear() notificationIconInstances.clear()
field { name = "mLastToShow" }.get(instance).list<View>() firstFieldOrNull { name = "mLastToShow" }?.of(instance)?.get<List<View>>()
.takeIf { it.isNotEmpty() }?.forEach { notificationIconInstances.add(it) } ?.takeIf { it.isNotEmpty() }?.forEach { notificationIconInstances.add(it) }
} }
else -> notificationIconContainer = args(index = 1).cast() else -> notificationIconContainer = args(index = 1).cast()
} }
} }
} }
/** 注入状态栏通知图标容器实例 */ /** 注入状态栏通知图标容器实例 */
if (LegacyNotificationIconAreaControllerImpl != null) { (LegacyNotificationIconAreaControllerImpl ?: NotificationIconAreaControllerClass)
/** ColorOS 15.0.1 */ .resolve().optional().apply {
LegacyNotificationIconAreaControllerImpl?.apply { firstMethodOrNull {
method {
name = "updateIconsForLayout" name = "updateIconsForLayout"
paramCount = 8 parameterCount = 8
}.hook().after { }?.hook()?.after {
notificationIconContainer = args(index = 1).cast() notificationIconContainer = args(index = 1).cast()
} }
} }
} else {
/** ColorOS 15 */
NotificationIconAreaControllerClass.apply {
method {
name = "updateIconsForLayout"
paramCount = 8
}.hook().after {
notificationIconContainer = args(index = 1).cast()
}
}
}
/** 替换通知面板背景 - 新版本 */ /** 替换通知面板背景 - 新版本 */
if (isOldNotificationBackground.not()) if (!isOldNotificationBackground)
OplusNotificationBackgroundViewClass?.apply { OplusNotificationBackgroundViewClass?.resolve()?.optional()?.apply {
method { firstMethodOrNull {
name = "drawRegionBlur" name { it == "drawRegionBlur" || it == "draw" }
paramCount = 2 parameterCount = 2
}.remedys { superclass()
method { }?.hook()?.before { modifyNotifyPanelAlpha(instance(), args().last().cast<Drawable>()) }
name = "draw"
paramCount = 2
}
}.hook().before { modifyNotifyPanelAlpha(instance(), args().last().cast<Drawable>()) }
method {
name = "draw"
paramCount = 2
superClass(isOnlySuperClass = true)
}.hook().before { modifyNotifyPanelAlpha(instance(), args().last().cast<Drawable>()) }
} }
/** 替换通知面板背景 - 旧版本 */ /** 替换通知面板背景 - 旧版本 */
if (isOldNotificationBackground) if (isOldNotificationBackground)
NotificationBackgroundViewClass?.apply { NotificationBackgroundViewClass?.resolve()?.optional(silent = true)?.apply {
method { firstMethodOrNull {
name = "draw" name = "draw"
paramCount = 2 parameterCount = 2
}.hook().before { modifyNotifyPanelAlpha(instance(), args().last().cast<Drawable>()) } }?.hook()?.before { modifyNotifyPanelAlpha(instance(), args().last().cast<Drawable>()) }
method { firstMethodOrNull {
name = "drawCustom" name = "drawCustom"
paramCount = 2 parameterCount = 2
}.ignored().hook().before { modifyNotifyPanelAlpha(instance(), args().last().cast<Drawable>()) } }?.hook()?.before { modifyNotifyPanelAlpha(instance(), args().last().cast<Drawable>()) }
} }
/** 替换通知面板背景 - 避免折叠展开通知二次修改通知面板背景 */ /** 替换通知面板背景 - 避免折叠展开通知二次修改通知面板背景 */
ExpandableNotificationRowClass.apply { ExpandableNotificationRowClass.resolve().optional().apply {
method { firstMethodOrNull {
name = "updateBackgroundForGroupState" name = "updateBackgroundForGroupState"
emptyParam() emptyParameters()
}.hook().before { }?.hook()?.before {
if (ConfigData.isEnableNotifyPanelAlpha) field { name = "mShowGroupBackgroundWhenExpanded" }.get(instance).setTrue() if (ConfigData.isEnableNotifyPanelAlpha)
firstFieldOrNull { name = "mShowGroupBackgroundWhenExpanded" }?.of(instance)?.set(true)
} }
} }
/** 替换媒体通知面板背景 - 设置媒体通知自动展开 */ /** 替换媒体通知面板背景 - 设置媒体通知自动展开 */
OplusMediaControlPanelClass?.apply { OplusMediaControlPanelClass?.resolve()?.optional()?.apply {
method { firstMethodOrNull {
name = "bind" name = "bind"
paramCount = 2 parameterCount = 2
}.hook().after { }?.hook()?.after {
/** 得到当前实例 */ /** 得到当前实例 */
val holder = OplusMediaControlPanelClass?.field { val holder = OplusMediaControlPanelClass?.resolve()?.optional()?.firstFieldOrNull {
name = "mViewHolder" name = "mViewHolder"
superClass(isOnlySuperClass = true) superclass()
}?.get(instance)?.any() }?.of(instance)?.get()
/** 记录媒体通知 [View] */ /** 记录媒体通知 [View] */
notificationPlayerView = PlayerViewHolderClass?.method { notificationPlayerView = PlayerViewHolderClass?.resolve()?.optional()?.firstMethodOrNull {
name = "getPlayer" name = "getPlayer"
emptyParam() emptyParameters()
}?.get(holder)?.invoke() }?.of(holder)?.invokeQuietly<View>()
/** 设置背景着色 */ /** 设置背景着色 */
modifyNotifyPanelAlpha(notificationPlayerView, isTint = true) modifyNotifyPanelAlpha(notificationPlayerView, isTint = true)
/** 当前是否正在播放 */ /** 当前是否正在播放 */
val isPlaying = MediaDataClass?.method { val isPlaying = MediaDataClass?.resolve()?.optional()?.firstMethodOrNull {
name = "isPlaying" name = "isPlaying"
emptyParam() emptyParameters()
}?.get(args().first().any())?.boolean() ?: false }?.of(args().first().any())?.invokeQuietly<Boolean>() ?: false
/** 当前通知是否展开 */ /** 当前通知是否展开 */
val isExpanded = OplusMediaViewControllerClass?.method { val isExpanded = OplusMediaViewControllerClass?.resolve()?.optional()?.firstMethodOrNull {
name = "getExpanded" name = "getExpanded"
emptyParam() emptyParameters()
}?.get(field { name = "mOplusMediaViewController" }.get(instance).any())?.boolean() ?: false }?.of(firstFieldOrNull { name = "mOplusMediaViewController" }?.of(instance)?.get())?.invokeQuietly<Boolean>() ?: false
/** 符合条件后执行 */ /** 符合条件后执行 */
if (ConfigData.isEnableNotifyMediaPanelAutoExp.not() || isExpanded || isPlaying.not()) return@after if (ConfigData.isEnableNotifyMediaPanelAutoExp.not() || isExpanded || isPlaying.not()) return@after
/** 模拟手动展开通知 */ /** 模拟手动展开通知 */
BasePlayViewHolderClass?.method { BasePlayViewHolderClass?.resolve()?.optional()?.firstMethodOrNull {
name = "getExpandButton" name = "getExpandButton"
emptyParam() emptyParameters()
}?.get(holder)?.invoke<View>()?.performClick() }?.of(holder)?.invokeQuietly<View>()?.performClick()
} }
} }
/** 替换通知图标和样式 */ /** 替换通知图标和样式 */
NotificationHeaderViewWrapperClass.apply { NotificationHeaderViewWrapperClass.resolve().optional().apply {
method { method {
name { it == "resolveHeaderViews" || it == "onContentUpdated" } name { it == "resolveHeaderViews" || it == "onContentUpdated" }
}.hookAll().after { }.hookAll().after {
field { name = "mIcon" }.get(instance).cast<ImageView>()?.apply { firstFieldOrNull { name = "mIcon" }?.of(instance)?.get<ImageView>()?.apply {
ExpandableNotificationRowClass ExpandableNotificationRowClass.resolve().optional()
.method { name = "getEntry" } .firstMethodOrNull { name = "getEntry" }
.get(NotificationViewWrapperClass.field { ?.of(NotificationViewWrapperClass.resolve().optional().firstFieldOrNull {
name = "mRow" name = "mRow"
}.get(instance).any()).call()?.let { }?.of(instance)?.get())?.invokeQuietly()?.let {
it.javaClass.method { it.resolve().optional().firstMethodOrNull {
name = "getSbn" name = "getSbn"
}.get(it).invoke<StatusBarNotification>() }?.invoke<StatusBarNotification>()
}.also { nf -> }.also { nf ->
nf?.notification?.also { nf?.notification?.also {
it.smallIcon.loadDrawable(context)?.also { iconDrawable -> it.smallIcon.loadDrawable(context)?.also { iconDrawable ->

View File

@@ -20,21 +20,20 @@
* *
* This file is created by fankes on 2022/1/30. * This file is created by fankes on 2022/1/30.
*/ */
@file:Suppress("DEPRECATION")
package com.fankes.coloros.notify.ui.activity.base package com.fankes.coloros.notify.ui.activity.base
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.viewbinding.ViewBinding import androidx.viewbinding.ViewBinding
import com.fankes.coloros.notify.R import com.fankes.coloros.notify.R
import com.fankes.coloros.notify.utils.factory.isNotSystemInDarkMode import com.fankes.coloros.notify.utils.factory.isNotSystemInDarkMode
import com.highcapable.yukihookapi.hook.factory.current import com.highcapable.kavaref.KavaRef.Companion.resolve
import com.highcapable.yukihookapi.hook.factory.method import com.highcapable.kavaref.extension.genericSuperclassTypeArguments
import com.highcapable.yukihookapi.hook.type.android.LayoutInflaterClass import com.highcapable.kavaref.extension.toClassOrNull
abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() { abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
@@ -50,10 +49,11 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
isMainThreadRunning = true isMainThreadRunning = true
binding = current().generic()?.argument()?.method { val bindingClass = javaClass.genericSuperclassTypeArguments().firstOrNull()?.toClassOrNull()
binding = bindingClass?.resolve()?.optional()?.firstMethodOrNull {
name = "inflate" name = "inflate"
param(LayoutInflaterClass) parameters(LayoutInflater::class)
}?.get()?.invoke<VB>(layoutInflater) ?: error("binding failed") }?.invoke<VB>(layoutInflater) ?: error("binding failed")
if (Build.VERSION.SDK_INT >= 35) binding.root.fitsSystemWindows = true if (Build.VERSION.SDK_INT >= 35) binding.root.fitsSystemWindows = true
setContentView(binding.root) setContentView(binding.root)
/** 隐藏系统的标题栏 */ /** 隐藏系统的标题栏 */
@@ -63,6 +63,7 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
isAppearanceLightStatusBars = isNotSystemInDarkMode isAppearanceLightStatusBars = isNotSystemInDarkMode
isAppearanceLightNavigationBars = isNotSystemInDarkMode isAppearanceLightNavigationBars = isNotSystemInDarkMode
} }
@Suppress("DEPRECATION")
ResourcesCompat.getColor(resources, R.color.colorThemeBackground, null).also { ResourcesCompat.getColor(resources, R.color.colorThemeBackground, null).also {
window?.statusBarColor = it window?.statusBarColor = it
window?.navigationBarColor = it window?.navigationBarColor = it

View File

@@ -20,6 +20,8 @@
* *
* This file is created by fankes on 2022/6/3. * This file is created by fankes on 2022/6/3.
*/ */
@file:Suppress("DEPRECATION")
package com.fankes.coloros.notify.utils.factory package com.fankes.coloros.notify.utils.factory
import android.content.Context import android.content.Context

View File

@@ -20,7 +20,7 @@
* *
* This file is created by fankes on 2022/1/7. * This file is created by fankes on 2022/1/7.
*/ */
@file:Suppress("unused") @file:Suppress("unused", "DEPRECATION")
package com.fankes.coloros.notify.utils.factory package com.fankes.coloros.notify.utils.factory

View File

@@ -20,7 +20,7 @@
* *
* This file is created by fankes on 2022/1/7. * This file is created by fankes on 2022/1/7.
*/ */
@file:Suppress("unused", "ObsoleteSdkInt") @file:Suppress("unused", "ObsoleteSdkInt", "DEPRECATION")
package com.fankes.coloros.notify.utils.factory package com.fankes.coloros.notify.utils.factory
@@ -56,6 +56,7 @@ import androidx.core.app.NotificationManagerCompat
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import androidx.core.content.pm.PackageInfoCompat import androidx.core.content.pm.PackageInfoCompat
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
import androidx.core.net.toUri
import com.fankes.coloros.notify.wrapper.BuildConfigWrapper import com.fankes.coloros.notify.wrapper.BuildConfigWrapper
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import com.highcapable.yukihookapi.hook.factory.field import com.highcapable.yukihookapi.hook.factory.field
@@ -133,7 +134,7 @@ inline val isNotColorOS get() = !isColorOS
val isRealmeUI val isRealmeUI
get() = safeOfFalse { get() = safeOfFalse {
val query = appContext.contentResolver.query( val query = appContext.contentResolver.query(
Uri.parse("content://com.oplus.customize.coreapp.configmanager.configprovider.AppFeatureProvider") "content://com.oplus.customize.coreapp.configmanager.configprovider.AppFeatureProvider".toUri()
.buildUpon() .buildUpon()
.appendPath("app_feature") .appendPath("app_feature")
.build(), null, "featurename=?", arrayOf("com.android.launcher.device_rm"), null .build(), null, "featurename=?", arrayOf("com.android.launcher.device_rm"), null
@@ -485,7 +486,7 @@ fun Context.openBrowser(url: String, packageName: String = "") = runCatching {
startActivity(Intent().apply { startActivity(Intent().apply {
if (packageName.isNotBlank()) setPackage(packageName) if (packageName.isNotBlank()) setPackage(packageName)
action = Intent.ACTION_VIEW action = Intent.ACTION_VIEW
data = Uri.parse(url) data = url.toUri()
/** 防止顶栈一样重叠在自己的 APP 中 */ /** 防止顶栈一样重叠在自己的 APP 中 */
flags = Intent.FLAG_ACTIVITY_NEW_TASK flags = Intent.FLAG_ACTIVITY_NEW_TASK
}) })

View File

@@ -1306,6 +1306,35 @@
android:textColor="@color/colorTextGray" android:textColor="@color/colorTextGray"
android:textSize="11sp" /> android:textSize="11sp" />
</LinearLayout> </LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginBottom="10dp"
android:background="@drawable/bg_permotion_round"
android:gravity="center|start"
android:orientation="horizontal"
android:padding="10dp">
<ImageView
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_marginEnd="10dp"
android:src="@mipmap/ic_kavaref" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autoLink="web"
android:ellipsize="end"
android:lineSpacingExtra="6dp"
android:maxLines="2"
android:text="此模块使用 KavaRef 强力驱动。\n了解更多 https://github.com/HighCapable/KavaRef"
android:textColor="@color/colorTextGray"
android:textSize="11sp" />
</LinearLayout>
</LinearLayout> </LinearLayout>
</androidx.core.widget.NestedScrollView> </androidx.core.widget.NestedScrollView>
</LinearLayout> </LinearLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -22,7 +22,7 @@ repositories:
plugins: plugins:
com.android.application: com.android.application:
alias: android-application alias: android-application
version: 8.9.0 version: 8.9.3
org.jetbrains.kotlin.android: org.jetbrains.kotlin.android:
alias: kotlin-android alias: kotlin-android
version: 2.1.10 version: 2.1.10
@@ -43,9 +43,14 @@ libraries:
rovo89-xposed-api rovo89-xposed-api
com.highcapable.yukihookapi: com.highcapable.yukihookapi:
api: api:
version: 1.2.1 version: 1.3.0
ksp-xposed: ksp-xposed:
version-ref: <this>::api version-ref: <this>::api
com.highcapable.kavaref:
kavaref-core:
version: 1.0.0
kavaref-extension:
version: 1.0.0
com.github.topjohnwu.libsu: com.github.topjohnwu.libsu:
core: core:
version: 5.2.2 version: 5.2.2
@@ -55,13 +60,13 @@ libraries:
version: 1.0.7 version: 1.0.7
com.squareup.okhttp3: com.squareup.okhttp3:
okhttp: okhttp:
version: 5.0.0-alpha.14 version: 5.0.0-alpha.16
androidx.core: androidx.core:
core-ktx: core-ktx:
version: 1.15.0 version: 1.16.0
androidx.appcompat: androidx.appcompat:
appcompat: appcompat:
version: 1.7.0 version: 1.7.1
com.google.android.material: com.google.android.material:
material: material:
version: 1.12.0 version: 1.12.0