mirror of
https://github.com/fankes/ColorOSNotifyIcon.git
synced 2025-09-04 01:35:22 +08:00
refactor: migrate and update to YukiHookAPI 1.3.0
This commit is contained in:
@@ -81,6 +81,8 @@ dependencies {
|
||||
compileOnly(de.robv.android.xposed.api)
|
||||
implementation(com.highcapable.yukihookapi.api)
|
||||
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.github.topjohnwu.libsu.core)
|
||||
implementation(com.github.duanhong169.drawabletoolbox)
|
||||
|
@@ -22,11 +22,9 @@
|
||||
*/
|
||||
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.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 类
|
||||
@@ -38,9 +36,9 @@ object FrameworkHooker : YukiBaseHooker() {
|
||||
|
||||
override fun onHook() {
|
||||
/** 拦截 ColorOS 覆盖应用通知图标 */
|
||||
OplusNotificationFixHelperClass?.method {
|
||||
OplusNotificationFixHelperClass?.resolve()?.optional()?.firstMethodOrNull {
|
||||
name = "fixSmallIcon"
|
||||
param(NotificationClass, StringClass, StringClass, BooleanType)
|
||||
}?.ignored()?.hook()?.intercept()
|
||||
parameters(Notification::class, String::class, String::class, Boolean::class)
|
||||
}?.hook()?.intercept()
|
||||
}
|
||||
}
|
@@ -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.IconAdaptationTool
|
||||
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.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.method
|
||||
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
|
||||
|
||||
/**
|
||||
@@ -135,8 +121,7 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
private val OplusContrastColorUtilClass by lazyClassOrNull("com.oplusos.util.OplusContrastColorUtil")
|
||||
|
||||
/** ColorOS 存在的类 - 旧版本不存在 */
|
||||
private val OplusNotificationBackgroundViewClass by lazyClassOrNull(
|
||||
"com.oplusos.systemui.statusbar.notification.row.OplusNotificationBackgroundView")
|
||||
private val OplusNotificationBackgroundViewClass by lazyClassOrNull("com.oplusos.systemui.statusbar.notification.row.OplusNotificationBackgroundView")
|
||||
|
||||
/** ColorOS 存在的类 - 旧版本不存在 */
|
||||
private val OplusMediaControlPanelClass by lazyClassOrNull("com.oplusos.systemui.media.OplusMediaControlPanel")
|
||||
@@ -284,10 +269,11 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
* @return [Boolean]
|
||||
*/
|
||||
private val isOldNotificationBackground
|
||||
get() = NotificationBackgroundViewClass?.hasMethod {
|
||||
name = "drawCustom"
|
||||
paramCount = 2
|
||||
} ?: false
|
||||
get() = NotificationBackgroundViewClass?.resolve()?.optional(silent = true)
|
||||
?.firstMethodOrNull {
|
||||
name = "drawCustom"
|
||||
parameterCount = 2
|
||||
} != null
|
||||
|
||||
/**
|
||||
* 打印日志
|
||||
@@ -327,28 +313,25 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
|
||||
/** 刷新状态栏小图标 */
|
||||
private fun refreshStatusBarIcons() = runInSafe {
|
||||
val nfField = StatusBarIconViewClass.field { name = "mNotification" }
|
||||
val sRadiusField = StatusBarIconViewClass.field {
|
||||
val nfField = StatusBarIconViewClass.resolve().optional().firstFieldOrNull { name = "mNotification" }
|
||||
val sRadiusField = StatusBarIconViewClass.resolve().optional(silent = true).firstFieldOrNull {
|
||||
name = "sIconRadiusFraction"
|
||||
}.remedys {
|
||||
StatusBarIconControllerClass.field { name = "sIconRadiusFraction" }
|
||||
}
|
||||
val sNfSizeField = StatusBarIconViewClass.field {
|
||||
} ?: StatusBarIconControllerClass.resolve().optional(silent = true).firstFieldOrNull { name = "sIconRadiusFraction" }
|
||||
val sNfSizeField = StatusBarIconViewClass.resolve().optional(silent = true).firstFieldOrNull {
|
||||
name = "sNotificationRoundIconSize"
|
||||
}.remedys {
|
||||
StatusBarIconControllerClass.field { name = "sNotificationRoundIconSize" }
|
||||
}
|
||||
val roundUtil = RoundRectDrawableUtil_CompanionClass.method {
|
||||
} ?: StatusBarIconControllerClass.resolve().optional(silent = true).firstFieldOrNull { name = "sNotificationRoundIconSize" }
|
||||
val roundUtil = RoundRectDrawableUtil_CompanionClass.resolve().optional(silent = true).firstMethodOrNull {
|
||||
name = "getRoundRectDrawable"
|
||||
param(DrawableClass, FloatType, IntType, IntType, ContextClass)
|
||||
}.onNoSuchMethod { YLog.error("Your system not support \"getRoundRectDrawable\"!", it) }
|
||||
.get(RoundRectDrawableUtilClass.field { name = "Companion" }.get().any())
|
||||
parameters(Drawable::class, Float::class, Int::class, Int::class, Context::class)
|
||||
}.apply {
|
||||
if (this == null) YLog.error("Your system not support \"getRoundRectDrawable\"!")
|
||||
}?.of(RoundRectDrawableUtilClass.resolve().optional().firstFieldOrNull { name = "Companion" }?.get())
|
||||
/** 启动一个线程防止卡顿 */
|
||||
Thread {
|
||||
(notificationIconContainer?.children?.toList() ?: notificationIconInstances.takeIf { it.isNotEmpty() })?.forEach {
|
||||
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)
|
||||
@@ -362,12 +345,16 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
drawable = iconDrawable
|
||||
).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 {
|
||||
notificationPresenter?.current()?.method {
|
||||
notificationPresenter?.resolve()?.optional()?.firstMethodOrNull {
|
||||
name = "updateNotificationsOnDensityOrFontScaleChanged"
|
||||
emptyParam()
|
||||
}?.call()
|
||||
emptyParameters()
|
||||
}?.invoke()
|
||||
modifyNotifyPanelAlpha(notificationPlayerView, isTint = true)
|
||||
}
|
||||
|
||||
@@ -393,15 +380,19 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
*/
|
||||
private fun isGrayscaleIcon(context: Context, drawable: Drawable) =
|
||||
if (ConfigData.isEnableColorIconCompat.not()) safeOfFalse {
|
||||
ContrastColorUtilClass.let {
|
||||
it.method {
|
||||
name = "isGrayscaleIcon"
|
||||
param(DrawableClass)
|
||||
}.get(it.method {
|
||||
name = "getInstance"
|
||||
param(ContextClass)
|
||||
}.get().invoke(context)).boolean(drawable)
|
||||
}
|
||||
ContrastColorUtilClass.resolve()
|
||||
.optional(silent = true)
|
||||
.let {
|
||||
it.firstMethodOrNull {
|
||||
name = "isGrayscaleIcon"
|
||||
parameters(Drawable::class)
|
||||
}?.of(
|
||||
it.firstMethodOrNull {
|
||||
name = "getInstance"
|
||||
parameters(Context::class)
|
||||
}?.invoke(context)
|
||||
)?.invokeQuietly<Boolean>(drawable) == true
|
||||
}
|
||||
} else BitmapCompatTool.isGrayscaleDrawable(drawable)
|
||||
|
||||
/**
|
||||
@@ -430,7 +421,11 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
context.injectModuleAppResources()
|
||||
var customPair: Triple<Drawable?, Int, Boolean>? = null
|
||||
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)
|
||||
when {
|
||||
/** 替换系统图标为 Android 默认 */
|
||||
@@ -681,61 +676,66 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
/** 缓存图标数据 */
|
||||
cachingIconDatas()
|
||||
/** 移除开发者警告通知 */
|
||||
SystemPromptControllerClass.method {
|
||||
SystemPromptControllerClass.resolve().optional().firstMethodOrNull {
|
||||
name = "updateDeveloperMode"
|
||||
}.hook().before {
|
||||
}?.hook()?.before {
|
||||
/** 是否移除 */
|
||||
if (ConfigData.isEnableRemoveDevNotify) resultNull()
|
||||
}
|
||||
/** 移除充电完成通知 */
|
||||
OplusPowerNotificationWarningsClass.method {
|
||||
OplusPowerNotificationWarningsClass.resolve().optional().firstMethodOrNull {
|
||||
name = "showChargeErrorDialog"
|
||||
param(IntType)
|
||||
}.hook().before {
|
||||
parameters(Int::class)
|
||||
}?.hook()?.before {
|
||||
/** 是否移除 */
|
||||
if (args().first().int() == 7 && ConfigData.isEnableRemoveChangeCompleteNotify) resultNull()
|
||||
}
|
||||
/** 移除免打扰通知 */
|
||||
DndAlertHelperClass.method {
|
||||
name { it.lowercase() == "sendnotificationwithendtime" }
|
||||
param(LongType)
|
||||
}.remedys {
|
||||
method {
|
||||
name = "operateNotification"
|
||||
param(LongType, IntType, BooleanType)
|
||||
DndAlertHelperClass.resolve().optional(silent = true).apply {
|
||||
firstMethodOrNull {
|
||||
name { it.lowercase() == "sendnotificationwithendtime" }
|
||||
parameters(Long::class)
|
||||
}?.hook()?.before {
|
||||
/** 是否移除 */
|
||||
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使用应用图标判断 */
|
||||
OplusNotificationSmallIconUtilClass?.method {
|
||||
/** 拦截 ColorOS 使用应用图标判断 */
|
||||
OplusNotificationSmallIconUtilClass?.resolve()?.optional()?.firstMethodOrNull {
|
||||
name = "useAppIconForSmallIcon"
|
||||
param(NotificationClass)
|
||||
parameters(Notification::class)
|
||||
}?.hook()?.before {
|
||||
resultFalse()
|
||||
}
|
||||
/** 修复并替换 ColorOS 以及原生灰度图标色彩判断 */
|
||||
NotificationUtilsClass.apply {
|
||||
method {
|
||||
NotificationUtilsClass.resolve().optional(silent = true).apply {
|
||||
firstMethodOrNull {
|
||||
name = "isGrayscale"
|
||||
param(ImageViewClass, ContrastColorUtilClass)
|
||||
}.hook().replaceAny { args().first().cast<ImageView>()?.let { isGrayscaleIcon(it.context, it.drawable) } ?: callOriginal() }
|
||||
method {
|
||||
parameters(ImageView::class, ContrastColorUtilClass)
|
||||
}?.hook()?.replaceAny { args().first().cast<ImageView>()?.let { isGrayscaleIcon(it.context, it.drawable) } ?: callOriginal() }
|
||||
firstMethodOrNull {
|
||||
name = "isGrayscaleOplus"
|
||||
param(ImageViewClass, OplusContrastColorUtilClass ?: VagueType)
|
||||
}.ignored().hook().replaceAny { args().first().cast<ImageView>()?.let { isGrayscaleIcon(it.context, it.drawable) } ?: callOriginal() }
|
||||
parameters(ImageView::class, OplusContrastColorUtilClass ?: VagueType)
|
||||
}?.hook()?.replaceAny { args().first().cast<ImageView>()?.let { isGrayscaleIcon(it.context, it.drawable) } ?: callOriginal() }
|
||||
}
|
||||
/** 替换状态栏图标 */
|
||||
IconManagerClass.method {
|
||||
IconManagerClass.resolve().optional().firstMethodOrNull {
|
||||
name = "getIconDescriptor"
|
||||
param(NotificationEntryClass, BooleanType)
|
||||
}.hook().after {
|
||||
IconBuilderClass.field { name = "context" }
|
||||
.get(IconManagerClass.field { name = "iconBuilder" }.get(instance).cast()).cast<Context>()?.also { context ->
|
||||
NotificationEntryClass.method {
|
||||
parameters(NotificationEntryClass, Boolean::class)
|
||||
}?.hook()?.after {
|
||||
IconBuilderClass.resolve().optional().firstFieldOrNull { name = "context" }
|
||||
?.of(IconManagerClass.resolve().optional().firstFieldOrNull { name = "iconBuilder" }?.of(instance)?.get())
|
||||
?.getQuietly<Context>()?.also { context ->
|
||||
NotificationEntryClass.resolve().optional().firstMethodOrNull {
|
||||
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 ->
|
||||
compatStatusIcon(
|
||||
context = context,
|
||||
@@ -747,171 +747,148 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
packageName = nf.packageName,
|
||||
drawable = iconDrawable
|
||||
).also { pair ->
|
||||
if (pair.second) StatusBarIconClass.field {
|
||||
if (pair.second) StatusBarIconClass.resolve().optional().firstFieldOrNull {
|
||||
name = "icon"
|
||||
type = IconClass
|
||||
}.get(result).set(Icon.createWithBitmap(pair.first.toBitmap()))
|
||||
type = Icon::class
|
||||
}?.of(result)?.set(Icon.createWithBitmap(pair.first.toBitmap()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/** 得到状态栏图标实例 */
|
||||
StatusBarIconViewClass.method {
|
||||
StatusBarIconViewClass.resolve().optional().firstMethodOrNull {
|
||||
name = "setNotification"
|
||||
param(StatusBarNotificationClass)
|
||||
}.hook().after {
|
||||
parameters(StatusBarNotification::class)
|
||||
}?.hook()?.after {
|
||||
/** 注册壁纸颜色监听 */
|
||||
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
|
||||
method {
|
||||
(firstMethodOrNull {
|
||||
name = "updateIconsForLayout"
|
||||
paramCount = 10
|
||||
}.remedys {
|
||||
parameterCount = 10
|
||||
} ?: firstMethodOrNull {
|
||||
/** ColorOS 14 */
|
||||
method {
|
||||
name = "updateIconsForLayout"
|
||||
parameterCount = 5
|
||||
} ?: firstMethodOrNull {
|
||||
name = "updateIconsForLayout"
|
||||
parameterCount = 1
|
||||
}?.apply { way = 1 }
|
||||
?: firstMethodOrNull {
|
||||
name = "updateIconsForLayout"
|
||||
paramCount = 5
|
||||
}
|
||||
method {
|
||||
name = "updateIconsForLayout"
|
||||
paramCount = 1
|
||||
}.onFind { way = 1 }
|
||||
method {
|
||||
name = "updateStatusBarIcons"
|
||||
}.onFind { way = 2 }
|
||||
}.hook().after {
|
||||
}?.apply { way = 2 })?.hook()?.after {
|
||||
when (way) {
|
||||
2 -> notificationIconContainer = OplusNotificationIconAreaControllerClass.method { name = "getNotificationIcons" }.get(instance).invoke()
|
||||
2 -> notificationIconContainer = OplusNotificationIconAreaControllerClass.resolve().optional()
|
||||
.firstMethodOrNull { name = "getNotificationIcons" }
|
||||
?.of(instance)?.invoke<ViewGroup>()
|
||||
1 -> {
|
||||
notificationIconInstances.clear()
|
||||
field { name = "mLastToShow" }.get(instance).list<View>()
|
||||
.takeIf { it.isNotEmpty() }?.forEach { notificationIconInstances.add(it) }
|
||||
firstFieldOrNull { name = "mLastToShow" }?.of(instance)?.get<List<View>>()
|
||||
?.takeIf { it.isNotEmpty() }?.forEach { notificationIconInstances.add(it) }
|
||||
}
|
||||
else -> notificationIconContainer = args(index = 1).cast()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 注入状态栏通知图标容器实例 */
|
||||
if (LegacyNotificationIconAreaControllerImpl != null) {
|
||||
/** ColorOS 15.0.1 */
|
||||
LegacyNotificationIconAreaControllerImpl?.apply {
|
||||
method {
|
||||
(LegacyNotificationIconAreaControllerImpl ?: NotificationIconAreaControllerClass)
|
||||
.resolve().optional().apply {
|
||||
firstMethodOrNull {
|
||||
name = "updateIconsForLayout"
|
||||
paramCount = 8
|
||||
}.hook().after {
|
||||
parameterCount = 8
|
||||
}?.hook()?.after {
|
||||
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())
|
||||
OplusNotificationBackgroundViewClass?.apply {
|
||||
method {
|
||||
name = "drawRegionBlur"
|
||||
paramCount = 2
|
||||
}.remedys {
|
||||
method {
|
||||
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)
|
||||
OplusNotificationBackgroundViewClass?.resolve()?.optional()?.apply {
|
||||
firstMethodOrNull {
|
||||
name { it == "drawRegionBlur" || it == "draw" }
|
||||
parameterCount = 2
|
||||
superclass()
|
||||
}?.hook()?.before { modifyNotifyPanelAlpha(instance(), args().last().cast<Drawable>()) }
|
||||
}
|
||||
/** 替换通知面板背景 - 旧版本 */
|
||||
if (isOldNotificationBackground)
|
||||
NotificationBackgroundViewClass?.apply {
|
||||
method {
|
||||
NotificationBackgroundViewClass?.resolve()?.optional(silent = true)?.apply {
|
||||
firstMethodOrNull {
|
||||
name = "draw"
|
||||
paramCount = 2
|
||||
}.hook().before { modifyNotifyPanelAlpha(instance(), args().last().cast<Drawable>()) }
|
||||
method {
|
||||
parameterCount = 2
|
||||
}?.hook()?.before { modifyNotifyPanelAlpha(instance(), args().last().cast<Drawable>()) }
|
||||
firstMethodOrNull {
|
||||
name = "drawCustom"
|
||||
paramCount = 2
|
||||
}.ignored().hook().before { modifyNotifyPanelAlpha(instance(), args().last().cast<Drawable>()) }
|
||||
parameterCount = 2
|
||||
}?.hook()?.before { modifyNotifyPanelAlpha(instance(), args().last().cast<Drawable>()) }
|
||||
}
|
||||
/** 替换通知面板背景 - 避免折叠展开通知二次修改通知面板背景 */
|
||||
ExpandableNotificationRowClass.apply {
|
||||
method {
|
||||
ExpandableNotificationRowClass.resolve().optional().apply {
|
||||
firstMethodOrNull {
|
||||
name = "updateBackgroundForGroupState"
|
||||
emptyParam()
|
||||
}.hook().before {
|
||||
if (ConfigData.isEnableNotifyPanelAlpha) field { name = "mShowGroupBackgroundWhenExpanded" }.get(instance).setTrue()
|
||||
emptyParameters()
|
||||
}?.hook()?.before {
|
||||
if (ConfigData.isEnableNotifyPanelAlpha)
|
||||
firstFieldOrNull { name = "mShowGroupBackgroundWhenExpanded" }?.of(instance)?.set(true)
|
||||
}
|
||||
}
|
||||
/** 替换媒体通知面板背景 - 设置媒体通知自动展开 */
|
||||
OplusMediaControlPanelClass?.apply {
|
||||
method {
|
||||
OplusMediaControlPanelClass?.resolve()?.optional()?.apply {
|
||||
firstMethodOrNull {
|
||||
name = "bind"
|
||||
paramCount = 2
|
||||
}.hook().after {
|
||||
parameterCount = 2
|
||||
}?.hook()?.after {
|
||||
/** 得到当前实例 */
|
||||
val holder = OplusMediaControlPanelClass?.field {
|
||||
val holder = OplusMediaControlPanelClass?.resolve()?.optional()?.firstFieldOrNull {
|
||||
name = "mViewHolder"
|
||||
superClass(isOnlySuperClass = true)
|
||||
}?.get(instance)?.any()
|
||||
superclass()
|
||||
}?.of(instance)?.get()
|
||||
/** 记录媒体通知 [View] */
|
||||
notificationPlayerView = PlayerViewHolderClass?.method {
|
||||
notificationPlayerView = PlayerViewHolderClass?.resolve()?.optional()?.firstMethodOrNull {
|
||||
name = "getPlayer"
|
||||
emptyParam()
|
||||
}?.get(holder)?.invoke()
|
||||
emptyParameters()
|
||||
}?.of(holder)?.invokeQuietly<View>()
|
||||
/** 设置背景着色 */
|
||||
modifyNotifyPanelAlpha(notificationPlayerView, isTint = true)
|
||||
/** 当前是否正在播放 */
|
||||
val isPlaying = MediaDataClass?.method {
|
||||
val isPlaying = MediaDataClass?.resolve()?.optional()?.firstMethodOrNull {
|
||||
name = "isPlaying"
|
||||
emptyParam()
|
||||
}?.get(args().first().any())?.boolean() ?: false
|
||||
emptyParameters()
|
||||
}?.of(args().first().any())?.invokeQuietly<Boolean>() ?: false
|
||||
|
||||
/** 当前通知是否展开 */
|
||||
val isExpanded = OplusMediaViewControllerClass?.method {
|
||||
val isExpanded = OplusMediaViewControllerClass?.resolve()?.optional()?.firstMethodOrNull {
|
||||
name = "getExpanded"
|
||||
emptyParam()
|
||||
}?.get(field { name = "mOplusMediaViewController" }.get(instance).any())?.boolean() ?: false
|
||||
emptyParameters()
|
||||
}?.of(firstFieldOrNull { name = "mOplusMediaViewController" }?.of(instance)?.get())?.invokeQuietly<Boolean>() ?: false
|
||||
/** 符合条件后执行 */
|
||||
if (ConfigData.isEnableNotifyMediaPanelAutoExp.not() || isExpanded || isPlaying.not()) return@after
|
||||
/** 模拟手动展开通知 */
|
||||
BasePlayViewHolderClass?.method {
|
||||
BasePlayViewHolderClass?.resolve()?.optional()?.firstMethodOrNull {
|
||||
name = "getExpandButton"
|
||||
emptyParam()
|
||||
}?.get(holder)?.invoke<View>()?.performClick()
|
||||
emptyParameters()
|
||||
}?.of(holder)?.invokeQuietly<View>()?.performClick()
|
||||
}
|
||||
}
|
||||
/** 替换通知图标和样式 */
|
||||
NotificationHeaderViewWrapperClass.apply {
|
||||
NotificationHeaderViewWrapperClass.resolve().optional().apply {
|
||||
method {
|
||||
name { it == "resolveHeaderViews" || it == "onContentUpdated" }
|
||||
}.hookAll().after {
|
||||
field { name = "mIcon" }.get(instance).cast<ImageView>()?.apply {
|
||||
ExpandableNotificationRowClass
|
||||
.method { name = "getEntry" }
|
||||
.get(NotificationViewWrapperClass.field {
|
||||
firstFieldOrNull { name = "mIcon" }?.of(instance)?.get<ImageView>()?.apply {
|
||||
ExpandableNotificationRowClass.resolve().optional()
|
||||
.firstMethodOrNull { name = "getEntry" }
|
||||
?.of(NotificationViewWrapperClass.resolve().optional().firstFieldOrNull {
|
||||
name = "mRow"
|
||||
}.get(instance).any()).call()?.let {
|
||||
it.javaClass.method {
|
||||
}?.of(instance)?.get())?.invokeQuietly()?.let {
|
||||
it.resolve().optional().firstMethodOrNull {
|
||||
name = "getSbn"
|
||||
}.get(it).invoke<StatusBarNotification>()
|
||||
}?.invoke<StatusBarNotification>()
|
||||
}.also { nf ->
|
||||
nf?.notification?.also {
|
||||
it.smallIcon.loadDrawable(context)?.also { iconDrawable ->
|
||||
|
@@ -20,21 +20,20 @@
|
||||
*
|
||||
* This file is created by fankes on 2022/1/30.
|
||||
*/
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package com.fankes.coloros.notify.ui.activity.base
|
||||
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.fankes.coloros.notify.R
|
||||
import com.fankes.coloros.notify.utils.factory.isNotSystemInDarkMode
|
||||
import com.highcapable.yukihookapi.hook.factory.current
|
||||
import com.highcapable.yukihookapi.hook.factory.method
|
||||
import com.highcapable.yukihookapi.hook.type.android.LayoutInflaterClass
|
||||
import com.highcapable.kavaref.KavaRef.Companion.resolve
|
||||
import com.highcapable.kavaref.extension.genericSuperclassTypeArguments
|
||||
import com.highcapable.kavaref.extension.toClassOrNull
|
||||
|
||||
abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
||||
|
||||
@@ -50,10 +49,11 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
isMainThreadRunning = true
|
||||
binding = current().generic()?.argument()?.method {
|
||||
val bindingClass = javaClass.genericSuperclassTypeArguments().firstOrNull()?.toClassOrNull()
|
||||
binding = bindingClass?.resolve()?.optional()?.firstMethodOrNull {
|
||||
name = "inflate"
|
||||
param(LayoutInflaterClass)
|
||||
}?.get()?.invoke<VB>(layoutInflater) ?: error("binding failed")
|
||||
parameters(LayoutInflater::class)
|
||||
}?.invoke<VB>(layoutInflater) ?: error("binding failed")
|
||||
if (Build.VERSION.SDK_INT >= 35) binding.root.fitsSystemWindows = true
|
||||
setContentView(binding.root)
|
||||
/** 隐藏系统的标题栏 */
|
||||
@@ -63,6 +63,7 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
||||
isAppearanceLightStatusBars = isNotSystemInDarkMode
|
||||
isAppearanceLightNavigationBars = isNotSystemInDarkMode
|
||||
}
|
||||
@Suppress("DEPRECATION")
|
||||
ResourcesCompat.getColor(resources, R.color.colorThemeBackground, null).also {
|
||||
window?.statusBarColor = it
|
||||
window?.navigationBarColor = it
|
||||
|
@@ -20,6 +20,8 @@
|
||||
*
|
||||
* This file is created by fankes on 2022/6/3.
|
||||
*/
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package com.fankes.coloros.notify.utils.factory
|
||||
|
||||
import android.content.Context
|
||||
|
@@ -20,7 +20,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
|
||||
|
||||
|
@@ -20,7 +20,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
|
||||
|
||||
@@ -56,6 +56,7 @@ import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.content.pm.PackageInfoCompat
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.core.net.toUri
|
||||
import com.fankes.coloros.notify.wrapper.BuildConfigWrapper
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.highcapable.yukihookapi.hook.factory.field
|
||||
@@ -133,7 +134,7 @@ inline val isNotColorOS get() = !isColorOS
|
||||
val isRealmeUI
|
||||
get() = safeOfFalse {
|
||||
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()
|
||||
.appendPath("app_feature")
|
||||
.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 {
|
||||
if (packageName.isNotBlank()) setPackage(packageName)
|
||||
action = Intent.ACTION_VIEW
|
||||
data = Uri.parse(url)
|
||||
data = url.toUri()
|
||||
/** 防止顶栈一样重叠在自己的 APP 中 */
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
})
|
||||
|
@@ -1306,6 +1306,35 @@
|
||||
android:textColor="@color/colorTextGray"
|
||||
android:textSize="11sp" />
|
||||
</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>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</LinearLayout>
|
BIN
app/src/main/res/mipmap-xxhdpi/ic_kavaref.png
Normal file
BIN
app/src/main/res/mipmap-xxhdpi/ic_kavaref.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
@@ -22,7 +22,7 @@ repositories:
|
||||
plugins:
|
||||
com.android.application:
|
||||
alias: android-application
|
||||
version: 8.9.0
|
||||
version: 8.9.3
|
||||
org.jetbrains.kotlin.android:
|
||||
alias: kotlin-android
|
||||
version: 2.1.10
|
||||
@@ -43,9 +43,14 @@ libraries:
|
||||
rovo89-xposed-api
|
||||
com.highcapable.yukihookapi:
|
||||
api:
|
||||
version: 1.2.1
|
||||
version: 1.3.0
|
||||
ksp-xposed:
|
||||
version-ref: <this>::api
|
||||
com.highcapable.kavaref:
|
||||
kavaref-core:
|
||||
version: 1.0.0
|
||||
kavaref-extension:
|
||||
version: 1.0.0
|
||||
com.github.topjohnwu.libsu:
|
||||
core:
|
||||
version: 5.2.2
|
||||
@@ -55,13 +60,13 @@ libraries:
|
||||
version: 1.0.7
|
||||
com.squareup.okhttp3:
|
||||
okhttp:
|
||||
version: 5.0.0-alpha.14
|
||||
version: 5.0.0-alpha.16
|
||||
androidx.core:
|
||||
core-ktx:
|
||||
version: 1.15.0
|
||||
version: 1.16.0
|
||||
androidx.appcompat:
|
||||
appcompat:
|
||||
version: 1.7.0
|
||||
version: 1.7.1
|
||||
com.google.android.material:
|
||||
material:
|
||||
version: 1.12.0
|
||||
|
Reference in New Issue
Block a user