refactor: migrate and update to YukiHookAPI 1.3.0

This commit is contained in:
2025-06-25 23:25:23 +08:00
parent c5ed4f720f
commit 8a775b3fdd
10 changed files with 271 additions and 222 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

@@ -30,7 +30,6 @@ import android.app.WallpaperManager
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.graphics.Bitmap
import android.graphics.Color import android.graphics.Color
import android.graphics.Outline import android.graphics.Outline
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
@@ -45,7 +44,9 @@ import android.widget.ImageView
import android.widget.RemoteViews import android.widget.RemoteViews
import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.drawable.toBitmap
import androidx.core.graphics.drawable.toDrawable import androidx.core.graphics.drawable.toDrawable
import androidx.core.graphics.scale
import androidx.core.view.children import androidx.core.view.children
import androidx.core.view.isNotEmpty
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.view.setPadding import androidx.core.view.setPadding
import com.fankes.miui.notify.R import com.fankes.miui.notify.R
@@ -76,28 +77,19 @@ import com.fankes.miui.notify.utils.tool.ActivationPromptTool
import com.fankes.miui.notify.utils.tool.BitmapCompatTool import com.fankes.miui.notify.utils.tool.BitmapCompatTool
import com.fankes.miui.notify.utils.tool.IconAdaptationTool import com.fankes.miui.notify.utils.tool.IconAdaptationTool
import com.fankes.miui.notify.utils.tool.SystemUITool import com.fankes.miui.notify.utils.tool.SystemUITool
import com.highcapable.yukihookapi.hook.bean.VariousClass import com.highcapable.kavaref.KavaRef.Companion.resolve
import com.highcapable.kavaref.condition.MethodCondition
import com.highcapable.kavaref.extension.VariousClass
import com.highcapable.kavaref.extension.classOf
import com.highcapable.kavaref.extension.isSubclassOf
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.extends
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.param.HookParam import com.highcapable.yukihookapi.hook.param.HookParam
import com.highcapable.yukihookapi.hook.type.android.ContextClass import com.highcapable.yukihookapi.hook.type.android.ContextClass
import com.highcapable.yukihookapi.hook.type.android.DrawableClass
import com.highcapable.yukihookapi.hook.type.android.ImageViewClass
import com.highcapable.yukihookapi.hook.type.android.NotificationClass import com.highcapable.yukihookapi.hook.type.android.NotificationClass
import com.highcapable.yukihookapi.hook.type.android.RemoteViewsClass import com.highcapable.yukihookapi.hook.type.android.RemoteViewsClass
import com.highcapable.yukihookapi.hook.type.android.StatusBarNotificationClass
import com.highcapable.yukihookapi.hook.type.java.ArrayListClass
import com.highcapable.yukihookapi.hook.type.java.BooleanClass import com.highcapable.yukihookapi.hook.type.java.BooleanClass
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 top.defaults.drawabletoolbox.DrawableBuilder import top.defaults.drawabletoolbox.DrawableBuilder
/** /**
@@ -238,13 +230,18 @@ object SystemUIHooker : YukiBaseHooker() {
* @return [Context] or null * @return [Context] or null
*/ */
private val globalContext private val globalContext
get() = SystemUIApplicationClass?.method { name = "getContext" }?.ignored()?.get()?.invoke<Context?>() ?: appContext get() = SystemUIApplicationClass?.resolve()?.optional(silent = true)
?.firstMethodOrNull { name = "getContext" }
?.invoke<Context?>() ?: appContext
/** /**
* 是否为 MIUI 样式通知栏 - 旧版 - 新版一律返回 false * 是否为 MIUI 样式通知栏 - 旧版 - 新版一律返回 false
* @return [Boolean] * @return [Boolean]
*/ */
private val isShowMiuiStyle get() = NotificationUtilClass.method { name = "showMiuiStyle" }.ignored().get().boolean() private val isShowMiuiStyle
get() = NotificationUtilClass.resolve().optional(silent = true)
.firstMethodOrNull { name = "showMiuiStyle" }
?.invoke<Boolean>() == true
/** /**
* 是否没有单独的 MIUI 通知栏样式 * 是否没有单独的 MIUI 通知栏样式
@@ -360,15 +357,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)
/** /**
@@ -408,10 +409,10 @@ object SystemUIHooker : YukiBaseHooker() {
/** 刷新状态栏小图标 */ /** 刷新状态栏小图标 */
private fun refreshStatusBarIcons() = runInSafe { private fun refreshStatusBarIcons() = runInSafe {
StatusBarIconViewClass.field { name = "mNotification" }.also { result -> StatusBarIconViewClass.resolve().optional(silent = true).firstFieldOrNull { name = "mNotification" }?.also { result ->
notificationIconContainer?.children?.forEach { notificationIconContainer?.children?.forEach {
/** 得到通知实例 */ /** 得到通知实例 */
val nf = result.get(it).cast<StatusBarNotification>() ?: return val nf = result.of(it).get<StatusBarNotification>() ?: return
/** 刷新状态栏图标 */ /** 刷新状态栏图标 */
compatStatusIcon(it.context, nf, nf.notification.smallIcon.loadDrawable(it.context)).also { pair -> compatStatusIcon(it.context, nf, nf.notification.smallIcon.loadDrawable(it.context)).also { pair ->
pair.first.let { e -> (it as? ImageView?)?.setImageDrawable(e) } pair.first.let { e -> (it as? ImageView?)?.setImageDrawable(e) }
@@ -423,14 +424,13 @@ object SystemUIHooker : YukiBaseHooker() {
/** 刷新通知小图标 */ /** 刷新通知小图标 */
private fun refreshNotificationIcons() = runInSafe { private fun refreshNotificationIcons() = runInSafe {
val updateNotificationMethodName = "updateNotificationsOnDensityOrFontScaleChanged" val updateNotificationMethodName = "updateNotificationsOnDensityOrFontScaleChanged"
if (StatusBarNotificationPresenterClass.hasMethod { name = updateNotificationMethodName }) val result = notificationPresenter?.resolve()?.optional(silent = true)?.firstMethodOrNull {
notificationPresenter?.current(ignored = true)?.method { name = updateNotificationMethodName
name = updateNotificationMethodName emptyParameters()
emptyParam() }?.invoke()
}?.call() if (result == null) settingsManager?.resolve()?.optional(silent = true)?.apply {
else settingsManager?.current { firstFieldOrNull { name = "notifStyle" }?.set(-100)
field { name = "notifStyle" }.set(-100) firstMethodOrNull { name = "onNotifStyleChanged" }?.invoke()
method { name = "onNotifStyleChanged" }.call()
} }
} }
@@ -645,7 +645,7 @@ object SystemUIHooker : YukiBaseHooker() {
*/ */
private fun ImageView.isGrayscaleIcon(): Boolean { private fun ImageView.isGrayscaleIcon(): Boolean {
/** 获取 [StatusBarNotification] 实例 */ /** 获取 [StatusBarNotification] 实例 */
val notifyInstance = current().field { name = "mNotification" }.cast<StatusBarNotification>() ?: return false val notifyInstance = resolve().optional().firstFieldOrNull { name = "mNotification" }?.get<StatusBarNotification>() ?: return false
/** 获取通知小图标 */ /** 获取通知小图标 */
val iconDrawable = notifyInstance.notification?.smallIcon?.loadDrawable(context) ?: return false val iconDrawable = notifyInstance.notification?.smallIcon?.loadDrawable(context) ?: return false
@@ -669,7 +669,7 @@ object SystemUIHooker : YukiBaseHooker() {
* @param animColor 动画过渡颜色 * @param animColor 动画过渡颜色
*/ */
private fun updateStatusBarIconsColor(container: ViewGroup, isDarkIconMode: Boolean = this.isDarkIconMode, animColor: Int? = null) { private fun updateStatusBarIconsColor(container: ViewGroup, isDarkIconMode: Boolean = this.isDarkIconMode, animColor: Int? = null) {
if (container.childCount > 0) container.children.forEach { iconView -> if (container.isNotEmpty()) container.children.forEach { iconView ->
if (iconView !is ImageView) return@forEach if (iconView !is ImageView) return@forEach
updateStatusBarIconColor(iconView, isDarkIconMode, animColor) updateStatusBarIconColor(iconView, isDarkIconMode, animColor)
} }
@@ -699,12 +699,15 @@ object SystemUIHooker : YukiBaseHooker() {
* @param container 当前 [NotificationIconContainerClass] 的实例 * @param container 当前 [NotificationIconContainerClass] 的实例
*/ */
private fun updateStatusBarIconsAlpha(container: ViewGroup) { private fun updateStatusBarIconsAlpha(container: ViewGroup) {
val iconStatesMap = container.current().field { name = "mIconStates" }.cast<HashMap<View, Any>>() val iconStatesMap = container.resolve().optional().firstFieldOrNull { name = "mIconStates" }?.get<HashMap<View, Any>>()
if (container.childCount > 0) container.children.forEach { iconView -> if (container.isNotEmpty()) container.children.forEach { iconView ->
if (iconView !is ImageView) return@forEach if (iconView !is ImageView) return@forEach
val iconAlpha = if (iconView.isGrayscaleIcon()) statusBarIconAlpha else 1f val iconAlpha = if (iconView.isGrayscaleIcon()) statusBarIconAlpha else 1f
iconView.alpha = iconAlpha iconView.alpha = iconAlpha
iconStatesMap?.get(iconView)?.current()?.field { name { it == "alpha" || it == "mAlpha" }; superClass() }?.set(iconAlpha) iconStatesMap?.get(iconView)?.resolve()?.optional()?.firstFieldOrNull {
name { it == "alpha" || it == "mAlpha" }
superclass()
}?.set(iconAlpha)
} }
} }
@@ -713,7 +716,7 @@ object SystemUIHooker : YukiBaseHooker() {
* @param instance 被 Hook 的 Method 的实例 * @param instance 被 Hook 的 Method 的实例
*/ */
private fun hookStatusBarMaxStaticIcons(instance: Any) { private fun hookStatusBarMaxStaticIcons(instance: Any) {
val maxStaticIconsField = NotificationIconContainerClass.field { val maxStaticIconsResolver = NotificationIconContainerClass.resolve().optional().firstFieldOrNull {
name { name {
/** 旧版名称 */ /** 旧版名称 */
val oldVersion = it == "mMaxStaticIcons" val oldVersion = it == "mMaxStaticIcons"
@@ -725,22 +728,22 @@ object SystemUIHooker : YukiBaseHooker() {
val newVersion = it == "mMaxIcons" val newVersion = it == "mMaxIcons"
oldVersion || oldVersion2 || newVersion oldVersion || oldVersion2 || newVersion
} }
}.get(instance) }?.of(instance) ?: return
if (statusBarMaxStaticIcons == -1 || if (statusBarMaxStaticIcons == -1 ||
/** 系统设置内修改,模块同步更新 */ /** 系统设置内修改,模块同步更新 */
moduleLastSetStatusBarMaxStaticIcons != maxStaticIconsField.int()) { moduleLastSetStatusBarMaxStaticIcons != maxStaticIconsResolver.get<Int>()) {
statusBarMaxStaticIcons = maxStaticIconsField.int() statusBarMaxStaticIcons = maxStaticIconsResolver.get<Int>() ?: return
} }
if (!ConfigData.isEnableLiftedStatusIconCount) { if (!ConfigData.isEnableLiftedStatusIconCount) {
maxStaticIconsField.set(statusBarMaxStaticIcons) maxStaticIconsResolver.set(statusBarMaxStaticIcons)
return return
} }
/** 解除状态栏通知图标个数限制 */ /** 解除状态栏通知图标个数限制 */
if (isShowNotificationIcons) { if (isShowNotificationIcons) {
moduleLastSetStatusBarMaxStaticIcons = ConfigData.liftedStatusIconCount.let { if (it in 0..100) it else 5 } moduleLastSetStatusBarMaxStaticIcons = ConfigData.liftedStatusIconCount.let { if (it in 0..100) it else 5 }
maxStaticIconsField.set(moduleLastSetStatusBarMaxStaticIcons) maxStaticIconsResolver.set(moduleLastSetStatusBarMaxStaticIcons)
} else { } else {
maxStaticIconsField.set(0) maxStaticIconsResolver.set(0)
moduleLastSetStatusBarMaxStaticIcons = 0 moduleLastSetStatusBarMaxStaticIcons = 0
} }
} }
@@ -754,8 +757,8 @@ object SystemUIHooker : YukiBaseHooker() {
if (isNotHasAbsoluteMiuiStyle && isShowMiuiStyle) return if (isNotHasAbsoluteMiuiStyle && isShowMiuiStyle) return
/** 获取小图标 */ /** 获取小图标 */
val iconImageView = NotificationHeaderViewWrapperClass val iconImageView = NotificationHeaderViewWrapperClass.resolve().optional()
.field { name = "mIcon" }.get(wrapper).cast<ImageView>() ?: return .firstFieldOrNull { name = "mIcon" }?.of(wrapper)?.get<ImageView>() ?: return
/** 获取 [ExpandableNotificationRowClass] */ /** 获取 [ExpandableNotificationRowClass] */
val rowPair = wrapper.getRowPair() val rowPair = wrapper.getRowPair()
@@ -788,16 +791,15 @@ object SystemUIHooker : YukiBaseHooker() {
* 从父类中得到 mRow 变量 - [ExpandableNotificationRowClass] * 从父类中得到 mRow 变量 - [ExpandableNotificationRowClass]
* 获取其中的得到通知方法 * 获取其中的得到通知方法
*/ */
val row = NotificationViewWrapperClass.field { val row = NotificationViewWrapperClass.resolve().optional().firstFieldOrNull {
name = "mRow" name = "mRow"
}.get(this).any()?.also { }?.of(this)?.get()?.also {
isExpanded = ExpandableNotificationRowClass.method { isExpanded = ExpandableNotificationRowClass.resolve().optional().firstMethodOrNull {
name = "isExpanded" name = "isExpanded"
param(BooleanType) parameters(Boolean::class)
returnType = BooleanType returnType = Boolean::class
}.get(it).boolean(false) }?.of(it)?.invoke<Boolean>(false) == true
} }; return isExpanded to row
return Pair(isExpanded, row)
} }
/** /**
@@ -805,15 +807,18 @@ object SystemUIHooker : YukiBaseHooker() {
* @return [StatusBarNotification] or null * @return [StatusBarNotification] or null
*/ */
private fun Any?.getSbn() = private fun Any?.getSbn() =
ExpandableNotificationRowClass ExpandableNotificationRowClass.resolve()
.field { name = "mEntry" } .optional(silent = true)
.get(this) .firstFieldOrNull {
.current(ignored = true) name = "mEntry"
?.field { name = "mSbn" } }?.of(this)?.get()?.resolve()
?.cast<StatusBarNotification>() ?.optional(silent = true)
?: ExpandableNotificationRowClass ?.firstFieldOrNull { name = "mSbn" }
.method { name = "getStatusBarNotification" } ?.get<StatusBarNotification>()
.get(this).invoke<StatusBarNotification>() ?: ExpandableNotificationRowClass.resolve()
.optional(silent = true)
.firstMethodOrNull { name = "getStatusBarNotification" }
?.of(this)?.invoke<StatusBarNotification>()
/** /**
* 根据当前 [ImageView] 的父布局克隆一个新的 [ImageView] * 根据当前 [ImageView] 的父布局克隆一个新的 [ImageView]
@@ -916,71 +921,77 @@ object SystemUIHooker : YukiBaseHooker() {
/** 注入 MIUI 自己增加的一个工具类 */ /** 注入 MIUI 自己增加的一个工具类 */
NotificationUtilClass.apply { NotificationUtilClass.apply {
/** 强制回写系统的状态栏图标样式为原生 */ /** 强制回写系统的状态栏图标样式为原生 */
method { resolve().optional().method {
name { it == "shouldSubstituteSmallIcon" || it == "shouldSubstituteSmallIconForStatusBarNotification" } name { it == "shouldSubstituteSmallIcon" || it == "shouldSubstituteSmallIconForStatusBarNotification" }
param { it[0] extends StatusBarNotificationClass } parameters { it.first() isSubclassOf StatusBarNotification::class }
}.hookAll().replaceToFalse() }.hookAll().replaceToFalse()
var isUseLegacy = false var isUseLegacy = false
/** /**
* 强制修改 getCustomAppIcon 获取的图标为 smallIcon * 强制修改 getCustomAppIcon 获取的图标为 smallIcon
* 部分系统没有 "getCustomAppIcon" 这个方法 - 所以直接忽略 * 部分系统没有 "getCustomAppIcon" 这个方法 - 所以直接忽略
*/ */
if (hasMethod { name = "getCustomAppIcon" }) resolve().optional(silent = true).firstMethodOrNull {
method { name = "getCustomAppIcon"
name = "getCustomAppIcon" parameters(Notification::class, Context::class)
param(NotificationClass, ContextClass) }?.hook()?.after {
}.hook().after { val nf = args().first().cast<Notification>()
val nf = args().first().cast<Notification>() val context = args(index = 1).cast<Context>()
val context = args(index = 1).cast<Context>() val iconBitmap = nf?.smallIcon?.loadDrawable(context)?.toBitmap()
val iconBitmap = nf?.smallIcon?.loadDrawable(context)?.toBitmap() result = if (context != null && iconBitmap != null && !iconBitmap.isRecycled)
result = if (context != null && iconBitmap != null && !iconBitmap.isRecycled) iconBitmap.toDrawable(context.resources)
iconBitmap.toDrawable(context.resources) else null
else null }
}
/** /**
* 强制回写系统的状态栏图标样式为原生 * 强制回写系统的状态栏图标样式为原生
* 部分系统没有 "getSmallIcon" 这个方法 - 所以直接忽略 * 部分系统没有 "getSmallIcon" 这个方法 - 所以直接忽略
*/ */
if (hasMethod { name = "getSmallIcon" }) val getSmallIconCondition1 = MethodCondition<Any>().apply {
method { name = "getSmallIcon"
name = "getSmallIcon" parameters { it[0] isSubclassOf StatusBarNotification::class && it[1] == classOf<Int>() }
param { it[0] extends StatusBarNotificationClass && it[1] == IntType } }
}.remedys { val getSmallIconCondition2 = MethodCondition<Any>().apply {
method { name = "getSmallIcon"
name = "getSmallIcon" parameters(ExpandedNotificationClass)
param(ExpandedNotificationClass) }
} val getSmallIconCondition3 = MethodCondition<Any>().apply {
method { name = "getSmallIcon"
name = "getSmallIcon" parameters { it[0] == classOf<Context>() && it[1] isSubclassOf StatusBarNotification::class }
param { it[0] == ContextClass && it[1] extends StatusBarNotificationClass } }
}.onFind { isUseLegacy = true } val getSmallIconResolver = resolve().optional(silent = true)
}.hook().after { val getSmallIcon = getSmallIconResolver.firstMethodOrNull(getSmallIconCondition1)
(globalContext ?: args().first().cast())?.also { context -> ?: getSmallIconResolver.firstMethodOrNull(getSmallIconCondition2)
val expandedNf = args(if (isUseLegacy) 1 else 0).cast<StatusBarNotification?>() ?: getSmallIconResolver.firstMethodOrNull(getSmallIconCondition3)
/** Hook 状态栏小图标 */ ?.also { isUseLegacy = true }
compatStatusIcon( getSmallIcon?.hook()?.after {
context = context, (globalContext ?: args().first().cast())?.also { context ->
nf = expandedNf, val expandedNf = args(if (isUseLegacy) 1 else 0).cast<StatusBarNotification?>()
iconDrawable = result<Icon>()?.loadDrawable(context) /** Hook 状态栏小图标 */
).also { pair -> if (pair.second) result = Icon.createWithBitmap(pair.first?.toBitmap()) } compatStatusIcon(
} context = context,
nf = expandedNf,
iconDrawable = result<Icon>()?.loadDrawable(context)
).also { pair -> if (pair.second) result = Icon.createWithBitmap(pair.first?.toBitmap()) }
} }
}
} }
/** 焦点通知深色模式切换点 */ /** 焦点通知深色模式切换点 */
FocusedNotifPromptViewClass?.apply { FocusedNotifPromptViewClass?.resolve()?.optional()?.apply {
method { firstMethodOrNull {
name = "onDarkChanged" name = "onDarkChanged"
param(ArrayListClass, FloatType, IntType, IntType, IntType, BooleanType) parameters(ArrayList::class, Float::class, Int::class, Int::class, Int::class, Boolean::class)
}.hook().after { }?.hook()?.after {
val isDark = args(index = 1).float() val isDark = args(index = 1).float()
val mIcon = field { name = "mIcon" }.get(instance) val mIcon = firstFieldOrNull { name = "mIcon" }?.of(instance)?.get()
if (ConfigData.isEnableModuleLog) if (ConfigData.isEnableModuleLog)
YLog.debug("FocusedNotifPromptView DEBUG $isDark ${mIcon.any()}") YLog.debug("FocusedNotifPromptView DEBUG $isDark $mIcon")
mIcon.current()?.superClass()?.method { name = "setColorFilter" }?.call(if (isDark <= 0.5f) Color.WHITE else Color.BLACK) mIcon?.resolve()?.optional()?.firstMethodOrNull {
name = "setColorFilter"
superclass()
}?.invoke(if (isDark <= 0.5f) Color.WHITE else Color.BLACK)
} }
} }
/** 去他妈的焦点通知彩色图标 */ /** 去他妈的焦点通知彩色图标 */
FocusUtilsClass?.apply { FocusUtilsClass?.resolve()?.optional()?.apply {
fun HookParam.hookTickerDarkIcon(isDark: Boolean) { fun HookParam.hookTickerDarkIcon(isDark: Boolean) {
(globalContext ?: args().first().cast())?.also { context -> (globalContext ?: args().first().cast())?.also { context ->
val expandedNf = args().first().cast<StatusBarNotification?>() val expandedNf = args().first().cast<StatusBarNotification?>()
@@ -992,37 +1003,33 @@ object SystemUIHooker : YukiBaseHooker() {
iconDrawable = small?.loadDrawable(context) iconDrawable = small?.loadDrawable(context)
).also { pair -> ).also { pair ->
val originalBitmap = pair.first?.toBitmap() val originalBitmap = pair.first?.toBitmap()
val bitmap = originalBitmap?.let { Bitmap.createScaledBitmap(it, 50, 50, true) } val bitmap = originalBitmap?.scale(50, 50)
result = Icon.createWithBitmap(bitmap).apply { if (pair.second) setTint(if (isDark) Color.BLACK else Color.WHITE) } result = Icon.createWithBitmap(bitmap).apply { if (pair.second) setTint(if (isDark) Color.BLACK else Color.WHITE) }
} }
} }
} }
method { firstMethodOrNull {
name = "getStatusBarTickerDarkIcon" name = "getStatusBarTickerDarkIcon"
param(StatusBarNotificationClass) parameters {
}.remedys { (it.first() == classOf<StatusBarNotification>() ||
method { it.first() == ExpandedNotificationClass) && it.size == 1
name = "getStatusBarTickerDarkIcon"
param(ExpandedNotificationClass)
} }
}.hook().after { hookTickerDarkIcon(isDark = true) } }?.hook()?.after { hookTickerDarkIcon(isDark = true) }
method { firstMethodOrNull {
name = "getStatusBarTickerIcon" name = "getStatusBarTickerIcon"
param(StatusBarNotificationClass) parameters {
}.remedys { (it.first() == classOf<StatusBarNotification>() ||
method { it.first() == ExpandedNotificationClass) && it.size == 1
name = "getStatusBarTickerIcon"
param(ExpandedNotificationClass)
} }
}.hook().after { hookTickerDarkIcon(isDark = false) } }?.hook()?.after { hookTickerDarkIcon(isDark = false) }
} }
/** 注入状态栏通知图标实例 */ /** 注入状态栏通知图标实例 */
StatusBarIconViewClass.method { StatusBarIconViewClass.resolve().optional().firstMethodOrNull {
name = "updateIconColor" name = "updateIconColor"
emptyParam() emptyParameters()
}.ignored().hook().after { }?.hook()?.after {
val iconView = instance<ImageView>() val iconView = instance<ImageView>()
val expandedNf = iconView.current().field { name = "mNotification" }.cast<StatusBarNotification>() val expandedNf = iconView.resolve().optional().firstFieldOrNull { name = "mNotification" }?.get<StatusBarNotification>()
/** Hook 状态栏小图标 */ /** Hook 状态栏小图标 */
compatStatusIcon( compatStatusIcon(
context = iconView.context, context = iconView.context,
@@ -1039,13 +1046,13 @@ object SystemUIHooker : YukiBaseHooker() {
* 在 Android 15 中,这个类被移除变成了 `interface`,所以判断并跳过 Hook 行为 * 在 Android 15 中,这个类被移除变成了 `interface`,所以判断并跳过 Hook 行为
*/ */
val isPlaceholder = NotificationIconAreaControllerClass?.isInterface == true val isPlaceholder = NotificationIconAreaControllerClass?.isInterface == true
if (!isPlaceholder) NotificationIconAreaControllerClass?.apply { if (!isPlaceholder) NotificationIconAreaControllerClass?.resolve()?.optional()?.apply {
/** Hook 深色图标模式改变 */ /** Hook 深色图标模式改变 */
method { firstMethodOrNull {
name = "onDarkChanged" name = "onDarkChanged"
paramCount { it > 0 } parameterCount { it > 0 }
}.hook().after { }?.hook()?.after {
field { name = "mNotificationIcons" }.get(instance).cast<ViewGroup>()?.also { firstFieldOrNull { name = "mNotificationIcons" }?.of(instance)?.get<ViewGroup>()?.also {
/** 重新设置通知图标容器实例 */ /** 重新设置通知图标容器实例 */
notificationIconContainer = it notificationIconContainer = it
when (args(index = 1).float()) { when (args(index = 1).float()) {
@@ -1065,7 +1072,7 @@ object SystemUIHooker : YukiBaseHooker() {
method { method {
name { it == "updateNotificationIcons" || it.startsWith("onChanged") } name { it == "updateNotificationIcons" || it.startsWith("onChanged") }
}.hookAll().after { }.hookAll().after {
field { name = "mNotificationIcons" }.get(instance).cast<ViewGroup>()?.also { firstFieldOrNull { name = "mNotificationIcons" }?.of(instance)?.get<ViewGroup>()?.also {
/** 重新设置通知图标容器实例 */ /** 重新设置通知图标容器实例 */
notificationIconContainer = it notificationIconContainer = it
updateStatusBarIconsColor(it) updateStatusBarIconsColor(it)
@@ -1073,11 +1080,11 @@ object SystemUIHooker : YukiBaseHooker() {
delayedRun { updateStatusBarIconsColor(it) } delayedRun { updateStatusBarIconsColor(it) }
} }
} }
} else MiuiClockClass?.apply { } else MiuiClockClass?.resolve()?.optional()?.apply {
method { firstMethodOrNull {
name = "onDarkChanged" name = "onDarkChanged"
paramCount { it > 4 } parameterCount { it > 4 }
}.hook().after { }?.hook()?.after {
notificationIconContainer?.let { notificationIconContainer?.let {
when (args(index = 1).float()) { when (args(index = 1).float()) {
1.0f -> { 1.0f -> {
@@ -1094,24 +1101,22 @@ object SystemUIHooker : YukiBaseHooker() {
} }
} }
/** 注入状态栏通知图标实例 */ /** 注入状态栏通知图标实例 */
StatusBarIconViewClass.apply { StatusBarIconViewClass.resolve().optional().apply {
method { firstMethodOrNull {
name = "setNotification" name = "setNotification"
param(StatusBarNotificationClass) parameters {
}.remedys { (it.first() == classOf<StatusBarNotification>() ||
method { it.first() == ExpandedNotificationClass) && it.size == 1
name = "setNotification"
param(ExpandedNotificationClass)
} }
}.hook().after { }?.hook()?.after {
/** 注册壁纸颜色监听 */ /** 注册壁纸颜色监听 */
if (args().first().any() != null) instance<ImageView>().also { registerWallpaperColorChanged(it) } if (args().first().any() != null) instance<ImageView>().also { registerWallpaperColorChanged(it) }
} }
/** Hook 深色图标模式改变 */ /** Hook 深色图标模式改变 */
if (isPlaceholder) method { if (isPlaceholder) firstMethodOrNull {
name = "onDarkChanged" name = "onDarkChanged"
paramCount { it > 4 } parameterCount { it > 4 }
}.hook().after { }?.hook()?.after {
val self = instance<ImageView>() val self = instance<ImageView>()
when (args(index = 1).float()) { when (args(index = 1).float()) {
1.0f -> { 1.0f -> {
@@ -1127,24 +1132,24 @@ object SystemUIHooker : YukiBaseHooker() {
} }
} }
/** 注入设置管理器实例 */ /** 注入设置管理器实例 */
SettingsManagerClass?.constructor()?.hookAll()?.after { settingsManager = instance } SettingsManagerClass?.resolve()?.optional()?.constructor {}?.hookAll()?.after { settingsManager = instance }
/** 注入通知控制器实例 */ /** 注入通知控制器实例 */
StatusBarNotificationPresenterClass.constructor().hookAll().after { notificationPresenter = instance } StatusBarNotificationPresenterClass.resolve().optional().constructor {}.hookAll().after { notificationPresenter = instance }
/** 注入状态栏通知图标容器实例 */ /** 注入状态栏通知图标容器实例 */
NotificationIconContainerClass.apply { NotificationIconContainerClass.apply {
method { resolve().optional().firstMethodOrNull {
name = "applyIconStates" name = "applyIconStates"
}.hook().after { updateStatusBarIconsAlpha(instance()) } }?.hook()?.after { updateStatusBarIconsAlpha(instance()) }
method { resolve().optional().firstMethodOrNull {
name = "resetViewStates" name = "resetViewStates"
}.hook().after { }?.hook()?.after {
updateStatusBarIconsAlpha(instance()) updateStatusBarIconsAlpha(instance())
/** HyperOS 系统设置修改通知图标个数触发此方法 */ /** HyperOS 系统设置修改通知图标个数触发此方法 */
hookStatusBarMaxStaticIcons(instance) hookStatusBarMaxStaticIcons(instance)
} }
method { resolve().optional().firstMethodOrNull {
name { it == "calculateIconTranslations" || it == "calculateIconXTranslations" } name { it == "calculateIconTranslations" || it == "calculateIconXTranslations" }
}.hook().after { }?.hook()?.after {
/** 缓存实例 */ /** 缓存实例 */
notificationIconContainer = instance<ViewGroup>() notificationIconContainer = instance<ViewGroup>()
/** 修复部分开发版状态栏图标只能显示一个的问题 */ /** 修复部分开发版状态栏图标只能显示一个的问题 */
@@ -1154,38 +1159,38 @@ object SystemUIHooker : YukiBaseHooker() {
} }
} }
/** 旧版方法 (A13 MIUI) - 新版不存在 */ /** 旧版方法 (A13 MIUI) - 新版不存在 */
method { resolve().optional(silent = true).firstMethodOrNull {
name = "updateState" name = "updateState"
}.ignored().hook().before { hookStatusBarMaxStaticIcons(instance) } }?.hook()?.before { hookStatusBarMaxStaticIcons(instance) }
/** 新版方法 (A14 MIUI14 / A14 HyperOS) - 旧版不存在 */ /** 新版方法 (A14 MIUI14 / A14 HyperOS) - 旧版不存在 */
method { resolve().optional(silent = true).firstMethodOrNull {
name = "onMeasure" name = "onMeasure"
}.ignored().hook().before { hookStatusBarMaxStaticIcons(instance) } }?.hook()?.before { hookStatusBarMaxStaticIcons(instance) }
/** 旧版方法 - 新版不存在 */ /** 旧版方法 - 新版不存在 */
method { resolve().optional(silent = true).firstMethodOrNull {
name = "setMaxStaticIcons" name = "setMaxStaticIcons"
param(IntType) parameters(Int::class)
}.ignored().hook().before { isShowNotificationIcons = args().first().int() > 0 } }?.hook()?.before { isShowNotificationIcons = args().first().int() > 0 }
/** 旧版方法 - 新版 (A15 HyperOS) 不存在 */ /** 旧版方法 - 新版 (A15 HyperOS) 不存在 */
method { resolve().optional(silent = true).firstMethodOrNull {
name = "miuiShowNotificationIcons" name = "miuiShowNotificationIcons"
param(BooleanType) parameters(Boolean::class)
}.ignored().hook().before { isShowNotificationIcons = args().first().boolean() } }?.hook()?.before { isShowNotificationIcons = args().first().boolean() }
} }
/** 注入原生通知包装纸实例 */ /** 注入原生通知包装纸实例 */
NotificationHeaderViewWrapperClass.apply { NotificationHeaderViewWrapperClass.resolve().optional().apply {
method { firstMethodOrNull {
name { it == "resolveHeaderViews" || it == "handleHeaderViews" || it == "resolveViews" } name { it == "resolveHeaderViews" || it == "handleHeaderViews" || it == "resolveViews" }
}.hook().after { hookNotificationViewWrapper(instance) } }?.hook()?.after { hookNotificationViewWrapper(instance) }
method { firstMethodOrNull {
name = "onContentUpdated" name = "onContentUpdated"
}.hook().after { hookNotificationViewWrapper(instance) } }?.hook()?.after { hookNotificationViewWrapper(instance) }
} }
/** 修改 MIUI 风格通知栏的通知图标 */ /** 修改 MIUI 风格通知栏的通知图标 */
MiuiNotificationViewWrapperClass?.apply { MiuiNotificationViewWrapperClass?.resolve()?.optional()?.apply {
constructor().hook().after { constructor {}.hookAll().after {
val nf = instance.getRowPair().second.getSbn() ?: return@after val nf = instance.getRowPair().second.getSbn() ?: return@after
field { name = "mAppIcon" }.get(instance).cast<ImageView>()?.clone { firstFieldOrNull { name = "mAppIcon" }?.of(instance)?.get<ImageView>()?.clone {
if (ConfigData.isEnableReplaceMiuiStyleNotifyIcon || ConfigData.isEnableNotifyIconForceAppIcon) if (ConfigData.isEnableReplaceMiuiStyleNotifyIcon || ConfigData.isEnableNotifyIconForceAppIcon)
compatNotifyIcon(context, nf, iconView = this, isUseMaterial3Style = true, isMiuiPanel = true) compatNotifyIcon(context, nf, iconView = this, isUseMaterial3Style = true, isMiuiPanel = true)
else setImageDrawable(nf.miuiAppIcon?.loadDrawable(context) ?: context.appIconOf(nf.packageName)) else setImageDrawable(nf.miuiAppIcon?.loadDrawable(context) ?: context.appIconOf(nf.packageName))
@@ -1193,16 +1198,16 @@ object SystemUIHooker : YukiBaseHooker() {
} }
} }
/** 修改 MIUI 风格通知栏的通知图标 - 折叠通知 */ /** 修改 MIUI 风格通知栏的通知图标 - 折叠通知 */
MiuiNotificationChildrenContainerClass?.apply { MiuiNotificationChildrenContainerClass?.resolve()?.optional()?.apply {
/** 替换通知小图标 */ /** 替换通知小图标 */
method { firstMethodOrNull {
name = "updateAppIcon" name = "updateAppIcon"
param(BooleanType) parameters(Boolean::class)
}.hook().after { }?.hook()?.after {
field { name = "mAppIcon" }.get(instance).cast<ImageView>()?.apply { firstFieldOrNull { name = "mAppIcon" }?.of(instance)?.get<ImageView>()?.apply {
val nf = NotificationChildrenContainerClass.field { val nf = NotificationChildrenContainerClass.resolve().optional().firstFieldOrNull {
name = "mContainingNotification" name = "mContainingNotification"
}.get(instance).any()?.getSbn() ?: return@after }?.of(instance)?.get()?.getSbn() ?: return@after
if (ConfigData.isEnableReplaceMiuiStyleNotifyIcon || ConfigData.isEnableNotifyIconForceAppIcon) if (ConfigData.isEnableReplaceMiuiStyleNotifyIcon || ConfigData.isEnableNotifyIconForceAppIcon)
compatNotifyIcon(context, nf, iconView = this, isUseMaterial3Style = true, isMiuiPanel = true) compatNotifyIcon(context, nf, iconView = this, isUseMaterial3Style = true, isMiuiPanel = true)
else setImageDrawable(nf.miuiAppIcon?.loadDrawable(context) ?: context.appIconOf(nf.packageName)) else setImageDrawable(nf.miuiAppIcon?.loadDrawable(context) ?: context.appIconOf(nf.packageName))
@@ -1210,29 +1215,28 @@ object SystemUIHooker : YukiBaseHooker() {
} }
} }
/** 干掉下拉通知图标自动设置回 APP 图标的方法 */ /** 干掉下拉通知图标自动设置回 APP 图标的方法 */
NotificationHeaderViewWrapperInjectorClass?.apply { NotificationHeaderViewWrapperInjectorClass?.resolve()?.optional(silent = true)?.apply {
method { firstMethodOrNull {
name = "setAppIcon" name = "setAppIcon"
param(ContextClass, ImageViewClass, ExpandedNotificationClass) parameters(Context::class, ImageView::class, ExpandedNotificationClass)
}.remedys { }?.hook()?.intercept()
method { firstMethodOrNull {
name = "setAppIcon" name = "setAppIcon"
param(ImageViewClass, ExpandedNotificationClass) parameters(ImageView::class, ExpandedNotificationClass)
} }?.hook()?.intercept()
}.ignored().hook().intercept() firstMethodOrNull {
method {
name = "resetIconBgAndPaddings" name = "resetIconBgAndPaddings"
param(ImageViewClass, ExpandedNotificationClass) parameters(ImageView::class, ExpandedNotificationClass)
}.ignored().hook().intercept() }?.hook()?.intercept()
} }
NotificationContentInflaterInjectorClass?.method { NotificationContentInflaterInjectorClass?.resolve()?.optional()?.firstMethodOrNull {
name = "handleAppIcon" name = "handleAppIcon"
/** /**
* MIUI 14 ([RemoteViewsClass], [NotificationClass]) * MIUI 14 ([RemoteViewsClass], [NotificationClass])
* HyperOS ([RemoteViewsClass], [NotificationClass], [ContextClass]) * HyperOS ([RemoteViewsClass], [NotificationClass], [ContextClass])
* HyperOS 2.0 ([RemoteViewsClass], [NotificationClass], [ContextClass], [BooleanClass]) * HyperOS 2.0 ([RemoteViewsClass], [NotificationClass], [ContextClass], [BooleanClass])
*/ */
paramCount(numRange = 2..4) parameterCount { it in 2..4 }
}?.hook()?.intercept() }?.hook()?.intercept()
/** /**
* 尝试修复从 MIUI 14 开始出现的一个崩溃问题 * 尝试修复从 MIUI 14 开始出现的一个崩溃问题
@@ -1245,14 +1249,14 @@ object SystemUIHooker : YukiBaseHooker() {
* } * }
* ``` * ```
*/ */
NotificationStatClass?.method { NotificationStatClass?.resolve()?.optional(silent = true)?.firstMethodOrNull {
name = "isUnimportantEntry" name = "isUnimportantEntry"
paramCount = 1 parameterCount = 1
}?.ignored()?.hook()?.replaceAny { }?.hook()?.replaceAny {
args().first().current(ignored = true).method { args().first().resolve().optional().firstMethodOrNull {
name = "getSbn" name = "getSbn"
superClass() superclass()
}.invoke<StatusBarNotification>()?.let { sbn -> }?.invoke<StatusBarNotification>()?.let { sbn ->
sbn.packageName == PackageName.SYSTEMUI && sbn.tag == "UNIMPORTANT" sbn.packageName == PackageName.SYSTEMUI && sbn.tag == "UNIMPORTANT"
} ?: false } ?: false
} }

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.miui.notify.ui.activity.base package com.fankes.miui.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.miui.notify.R import com.fankes.miui.notify.R
import com.fankes.miui.notify.utils.factory.isNotSystemInDarkMode import com.fankes.miui.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

@@ -64,6 +64,7 @@ class BaseAdapterCreater(val context: Context) {
* 绑定 [BaseAdapter] 到 [ListView] * 绑定 [BaseAdapter] 到 [ListView]
* @param bindViews 回调 - ([VB] 每项,[Int] 下标) * @param bindViews 回调 - ([VB] 每项,[Int] 下标)
*/ */
@Suppress("DEPRECATION")
inline fun <reified VB : ViewBinding> onBindViews(crossinline bindViews: (binding: VB, position: Int) -> Unit) { inline fun <reified VB : ViewBinding> onBindViews(crossinline bindViews: (binding: VB, position: Int) -> Unit) {
baseAdapter = object : BaseAdapter() { baseAdapter = object : BaseAdapter() {
override fun getCount() = listDataCallback?.let { it() }?.size ?: 0 override fun getCount() = listDataCallback?.let { it() }?.size ?: 0

View File

@@ -68,6 +68,7 @@ inline fun Context.showDialog(initiate: DialogBuilder<*>.() -> Unit) = DialogBui
* @param context 实例 * @param context 实例
* @param bindingClass [ViewBinding] 的 [Class] 实例 or null * @param bindingClass [ViewBinding] 的 [Class] 实例 or null
*/ */
@Suppress("DEPRECATION")
class DialogBuilder<VB : ViewBinding>(val context: Context, private val bindingClass: Class<*>? = null) { class DialogBuilder<VB : ViewBinding>(val context: Context, private val bindingClass: Class<*>? = null) {
/** 实例对象 */ /** 实例对象 */

View File

@@ -63,6 +63,8 @@ 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.graphics.createBitmap
import androidx.core.net.toUri
import com.fankes.miui.notify.wrapper.BuildConfigWrapper import com.fankes.miui.notify.wrapper.BuildConfigWrapper
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import com.highcapable.yukihookapi.hook.factory.hasClass import com.highcapable.yukihookapi.hook.factory.hasClass
@@ -148,6 +150,7 @@ val isNotMiSystem get() = !isMiSystem
* 当前设备是否是 MIUI 定制 Android 系统 * 当前设备是否是 MIUI 定制 Android 系统
* @return [Boolean] 是否符合条件 * @return [Boolean] 是否符合条件
*/ */
@Suppress("DEPRECATION")
val isMIUI by lazy { "android.miui.R".hasClass() } val isMIUI by lazy { "android.miui.R".hasClass() }
/** /**
@@ -541,7 +544,7 @@ val String.bitmap: Bitmap get() = unbase64.bitmap
* @return [Bitmap] 圆角后的位图 - 失败会返回处理之前的位图 * @return [Bitmap] 圆角后的位图 - 失败会返回处理之前的位图
*/ */
fun Bitmap.round(radius: Float): Bitmap = safeOf(default = this) { fun Bitmap.round(radius: Float): Bitmap = safeOf(default = this) {
Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888).also { out -> createBitmap(width, height).also { out ->
Canvas(out).also { canvas -> Canvas(out).also { canvas ->
Paint().also { paint -> Paint().also { paint ->
paint.isAntiAlias = true paint.isAntiAlias = true
@@ -561,6 +564,7 @@ fun Bitmap.round(radius: Float): Bitmap = safeOf(default = this) {
* @param default 默认值 * @param default 默认值
* @return [String] * @return [String]
*/ */
@Suppress("DEPRECATION")
fun findPropString(key: String, default: String = "") = safeOf(default) { fun findPropString(key: String, default: String = "") = safeOf(default) {
"android.os.SystemProperties".toClassOrNull()?.method { "android.os.SystemProperties".toClassOrNull()?.method {
name = "get" name = "get"
@@ -634,7 +638,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

@@ -32,6 +32,7 @@ import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.graphics.drawable.VectorDrawable import android.graphics.drawable.VectorDrawable
import android.util.ArrayMap import android.util.ArrayMap
import androidx.core.graphics.createBitmap
import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.drawable.toBitmap
import com.fankes.miui.notify.utils.factory.safeOfFalse import com.fankes.miui.notify.utils.factory.safeOfFalse
import kotlin.math.abs import kotlin.math.abs
@@ -77,7 +78,7 @@ object BitmapCompatTool {
var width = bitmap.width var width = bitmap.width
if (height > 64 || width > 64) { if (height > 64 || width > 64) {
if (tempCompactBitmap == null) { if (tempCompactBitmap == null) {
tempCompactBitmap = Bitmap.createBitmap(64, 64, Bitmap.Config.ARGB_8888) tempCompactBitmap = createBitmap(64, 64)
.also { tempCompactBitmapCanvas = Canvas(it) } .also { tempCompactBitmapCanvas = Canvas(it) }
tempCompactBitmapPaint = Paint(Paint.FILTER_BITMAP_FLAG).apply { isFilterBitmap = true } tempCompactBitmapPaint = Paint(Paint.FILTER_BITMAP_FLAG).apply { isFilterBitmap = true }
} }
@@ -91,11 +92,12 @@ object BitmapCompatTool {
val size = height * width val size = height * width
ensureBufferSize(size) ensureBufferSize(size)
tempCompactBitmap?.getPixels(tempBuffer, 0, width, 0, 0, width, height) tempCompactBitmap?.getPixels(tempBuffer, 0, width, 0, 0, width, height)
for (i in 0 until size) for (i in 0 until size) {
if (isGrayscaleColor(tempBuffer[i]).not()) { if (isGrayscaleColor(tempBuffer[i]).not()) {
cachedBitmapGrayscales[bitmap.generationId] = false cachedBitmapGrayscales[bitmap.generationId] = false
return@let false return@let false
} }
}
cachedBitmapGrayscales[bitmap.generationId] = true cachedBitmapGrayscales[bitmap.generationId] = true
true true
} }

View File

@@ -1457,6 +1457,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