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)
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)

View File

@@ -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()
}
}

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.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 ->

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
})

View File

@@ -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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -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