mirror of
https://github.com/fankes/MIUINativeNotifyIcon.git
synced 2025-09-07 03:05:51 +08:00
Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
d7a9f1e413 | |||
edf199d9a6 | |||
8d6a05e02c | |||
c7d9b2661b | |||
d0a32e08d9 |
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/app/src/main/ic_launcher-playstore.png" width = "100" height = "100"/>
|
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/app/src/main/ic_launcher-playstore.png" width = "100" height = "100"/>
|
||||||
<br/>
|
<br/>
|
||||||
@@ -12,7 +12,7 @@ Fix the native notification bar icon function abandoned by the MIUI development
|
|||||||
# 开始使用
|
# 开始使用
|
||||||
|
|
||||||
点击下载最新版本
|
点击下载最新版本
|
||||||
<a href='https://github.com/fankes/MIUINativeNotifyIcon/releases'></a>
|
<a href='https://github.com/fankes/MIUINativeNotifyIcon/releases'></a>
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
⚠️ 适配说明<br/>
|
⚠️ 适配说明<br/>
|
||||||
|
|
||||||
|
@@ -20,7 +20,7 @@
|
|||||||
android:value="true" />
|
android:value="true" />
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="xposeddescription"
|
android:name="xposeddescription"
|
||||||
android:value="MIUI 原生通知图标,修复 12.5、13 后期被破坏的彩色图标。\n开发者:酷安 @星夜不荟" />
|
android:value="为金凡教我做事的 MIUI 修复 12.5、13 后期被破坏的彩色图标。\n开发者:酷安 @星夜不荟" />
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="xposedminversion"
|
android:name="xposedminversion"
|
||||||
android:value="93" />
|
android:value="93" />
|
||||||
|
@@ -22,6 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.fankes.miui.notify.hook
|
package com.fankes.miui.notify.hook
|
||||||
|
|
||||||
|
import android.app.NotificationManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
@@ -55,6 +56,7 @@ import com.highcapable.yukihookapi.hook.param.PackageParam
|
|||||||
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.DrawableClass
|
||||||
import com.highcapable.yukihookapi.hook.type.android.ImageViewClass
|
import com.highcapable.yukihookapi.hook.type.android.ImageViewClass
|
||||||
|
import com.highcapable.yukihookapi.hook.type.java.BooleanType
|
||||||
import com.highcapable.yukihookapi.hook.type.java.IntType
|
import com.highcapable.yukihookapi.hook.type.java.IntType
|
||||||
import com.highcapable.yukihookapi.hook.xposed.proxy.YukiHookXposedInitProxy
|
import com.highcapable.yukihookapi.hook.xposed.proxy.YukiHookXposedInitProxy
|
||||||
|
|
||||||
@@ -264,6 +266,28 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
else null
|
else null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动适配状态栏、通知栏自定义小图标
|
||||||
|
* @param isGrayscaleIcon 是否为灰度图标
|
||||||
|
* @param packageName APP 包名
|
||||||
|
* @return [Pair] - ([Bitmap] 位图,[Int] 颜色)
|
||||||
|
*/
|
||||||
|
private fun PackageParam.compatCustomIcon(isGrayscaleIcon: Boolean, packageName: String): Pair<Bitmap?, Int> {
|
||||||
|
var customPair: Pair<Bitmap?, Int>? = null
|
||||||
|
if (prefs.getBoolean(ENABLE_NOTIFY_ICON_FIX, default = true))
|
||||||
|
run {
|
||||||
|
if (iconDatas.isNotEmpty())
|
||||||
|
iconDatas.forEach {
|
||||||
|
if (packageName == it.packageName && isAppNotifyHookOf(it)) {
|
||||||
|
if (!isGrayscaleIcon || isAppNotifyHookAllOf(it))
|
||||||
|
customPair = Pair(it.iconBitmap, it.iconColor)
|
||||||
|
return@run
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return customPair ?: Pair(null, 0)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook 状态栏小图标
|
* Hook 状态栏小图标
|
||||||
*
|
*
|
||||||
@@ -293,23 +317,12 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
val isNotGrayscaleIcon = notifyInstance.isXmsf || !isGrayscaleIcon(context, iconDrawable)
|
val isNotGrayscaleIcon = notifyInstance.isXmsf || !isGrayscaleIcon(context, iconDrawable)
|
||||||
|
|
||||||
/** 目标彩色通知 APP 图标 */
|
/** 目标彩色通知 APP 图标 */
|
||||||
var customIcon: Bitmap? = null
|
val customIcon = compatCustomIcon(!isNotGrayscaleIcon, notifyInstance.opPkgName).first
|
||||||
if (prefs.getBoolean(ENABLE_NOTIFY_ICON_FIX, default = true))
|
|
||||||
run {
|
|
||||||
if (iconDatas.isNotEmpty())
|
|
||||||
iconDatas.forEach {
|
|
||||||
if (notifyInstance.opPkgName == it.packageName && isAppNotifyHookOf(it)) {
|
|
||||||
if (isNotGrayscaleIcon || isAppNotifyHookAllOf(it))
|
|
||||||
customIcon = it.iconBitmap
|
|
||||||
return@run
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/** 打印日志 */
|
/** 打印日志 */
|
||||||
printLogcat(tag = "StatusIcon", context, notifyInstance, isCustom = customIcon != null, !isNotGrayscaleIcon)
|
printLogcat(tag = "StatusIcon", context, notifyInstance, isCustom = customIcon != null, !isNotGrayscaleIcon)
|
||||||
when {
|
when {
|
||||||
/** 处理自定义通知图标优化 */
|
/** 处理自定义通知图标优化 */
|
||||||
customIcon != null -> it(customIcon!!)
|
customIcon != null -> it(customIcon)
|
||||||
/** 若不是灰度图标自动处理为圆角 */
|
/** 若不是灰度图标自动处理为圆角 */
|
||||||
isNotGrayscaleIcon -> it(notifyInstance.compatNotifyIcon(context, iconDrawable).toBitmap())
|
isNotGrayscaleIcon -> it(notifyInstance.compatNotifyIcon(context, iconDrawable).toBitmap())
|
||||||
}
|
}
|
||||||
@@ -323,108 +336,102 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
* @param context 实例
|
* @param context 实例
|
||||||
* @param expandedNf 通知实例
|
* @param expandedNf 通知实例
|
||||||
* @param iconImageView 通知图标实例
|
* @param iconImageView 通知图标实例
|
||||||
|
* @param isExpanded 通知是否展开 - 可做最小化通知处理
|
||||||
*/
|
*/
|
||||||
private fun PackageParam.hookNotifyIconOnSet(context: Context, expandedNf: StatusBarNotification?, iconImageView: ImageView) =
|
private fun PackageParam.hookNotifyIconOnSet(
|
||||||
safeRun(msg = "AutoSetAppIconOnSet") {
|
context: Context,
|
||||||
/** 判断是 MIUI 样式就停止 Hook */
|
expandedNf: StatusBarNotification?,
|
||||||
if (context.isMiuiNotifyStyle) return@safeRun
|
iconImageView: ImageView,
|
||||||
/** 如果没开启修复 APP 的彩色图标 */
|
isExpanded: Boolean
|
||||||
if (!prefs.getBoolean(ENABLE_COLOR_ICON_HOOK, default = true)) return@safeRun
|
) = safeRun(msg = "AutoSetAppIconOnSet") {
|
||||||
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
|
/** 判断是 MIUI 样式就停止 Hook */
|
||||||
expandedNf?.let { notifyInstance ->
|
if (context.isMiuiNotifyStyle) return@safeRun
|
||||||
/** 是否开启修复 APP 的彩色图标 */
|
/** 如果没开启修复 APP 的彩色图标 */
|
||||||
val isNotifyIconFix = prefs.getBoolean(ENABLE_NOTIFY_ICON_FIX, default = true)
|
if (!prefs.getBoolean(ENABLE_COLOR_ICON_HOOK, default = true)) return@safeRun
|
||||||
|
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
|
||||||
|
expandedNf?.let { notifyInstance ->
|
||||||
|
|
||||||
/** 新版风格反色 */
|
/** 新版风格反色 */
|
||||||
val newStyle = if (context.isSystemInDarkMode) 0xFF2D2D2D.toInt() else Color.WHITE
|
val newStyle = if (context.isSystemInDarkMode) 0xFF2D2D2D.toInt() else Color.WHITE
|
||||||
|
|
||||||
/** 旧版风格反色 */
|
/** 旧版风格反色 */
|
||||||
val oldStyle = if (context.isNotSystemInDarkMode) 0xFF707070.toInt() else Color.WHITE
|
val oldStyle = if (context.isNotSystemInDarkMode) 0xFF707070.toInt() else Color.WHITE
|
||||||
|
|
||||||
/** 通知图标原始颜色 */
|
/** 通知图标原始颜色 */
|
||||||
val iconColor = notifyInstance.notification.color
|
val iconColor = notifyInstance.notification.color
|
||||||
|
|
||||||
/** 是否有通知栏图标颜色 */
|
/** 是否有通知栏图标颜色 */
|
||||||
val hasIconColor = iconColor != 0
|
val hasIconColor = iconColor != 0
|
||||||
|
|
||||||
/** 通知图标适配颜色 */
|
/** 通知图标适配颜色 */
|
||||||
val supportColor = iconColor.let {
|
val supportColor = iconColor.let {
|
||||||
when {
|
when {
|
||||||
isUpperOfAndroidS -> newStyle
|
isUpperOfAndroidS -> newStyle
|
||||||
it == 0 -> oldStyle
|
it == 0 || !isExpanded -> oldStyle
|
||||||
else -> it
|
else -> it
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** 获取通知小图标 */
|
/** 获取通知小图标 */
|
||||||
val iconDrawable = notifyInstance.notification.smallIcon.loadDrawable(context)
|
val iconDrawable = notifyInstance.notification.smallIcon.loadDrawable(context)
|
||||||
|
|
||||||
/** 判断图标风格 */
|
/** 判断图标风格 */
|
||||||
val isGrayscaleIcon = !notifyInstance.isXmsf && isGrayscaleIcon(context, iconDrawable)
|
val isGrayscaleIcon = !notifyInstance.isXmsf && isGrayscaleIcon(context, iconDrawable)
|
||||||
|
|
||||||
/** 自定义默认小图标 */
|
/** 自定义默认小图标 */
|
||||||
var customIcon: Bitmap? = null
|
var customIcon: Bitmap?
|
||||||
|
|
||||||
/** 自定义默认小图标颜色 */
|
/** 自定义默认小图标颜色 */
|
||||||
var customIconColor = 0
|
var customIconColor: Int
|
||||||
|
compatCustomIcon(isGrayscaleIcon, notifyInstance.opPkgName).also {
|
||||||
if (isNotifyIconFix) run {
|
customIcon = it.first
|
||||||
if (iconDatas.isNotEmpty())
|
customIconColor = if (isUpperOfAndroidS || isExpanded) it.second else 0
|
||||||
iconDatas.forEach {
|
}
|
||||||
if (notifyInstance.opPkgName == it.packageName && isAppNotifyHookOf(it)) {
|
/** 打印日志 */
|
||||||
if (!isGrayscaleIcon || isAppNotifyHookAllOf(it)) {
|
printLogcat(tag = "NotifyIcon", context, notifyInstance, isCustom = customIcon != null, isGrayscaleIcon)
|
||||||
customIcon = it.iconBitmap
|
/** 处理自定义通知图标优化 */
|
||||||
customIconColor = it.iconColor
|
if (customIcon != null)
|
||||||
return@run
|
iconImageView.apply {
|
||||||
}
|
/** 设置自定义小图标 */
|
||||||
}
|
setImageBitmap(customIcon)
|
||||||
}
|
/** 上色 */
|
||||||
|
setColorFilter(if (isUpperOfAndroidS || customIconColor == 0) supportColor else customIconColor)
|
||||||
|
/** Android 12 设置图标外圈颜色 */
|
||||||
|
if (isUpperOfAndroidS && customIconColor != 0)
|
||||||
|
background = DrawableBuilder().rounded().solidColor(customIconColor).build()
|
||||||
}
|
}
|
||||||
/** 打印日志 */
|
else {
|
||||||
printLogcat(tag = "NotifyIcon", context, notifyInstance, isCustom = customIcon != null, isGrayscaleIcon)
|
/** 重新设置图标 - 防止系统更改它 */
|
||||||
/** 处理自定义通知图标优化 */
|
iconImageView.setImageDrawable(iconDrawable)
|
||||||
if (customIcon != null)
|
/** 判断如果是灰度图标就给他设置一个白色颜色遮罩 */
|
||||||
iconImageView.apply {
|
if (isGrayscaleIcon) iconImageView.apply {
|
||||||
/** 设置自定义小图标 */
|
/** 设置图标着色 */
|
||||||
setImageBitmap(customIcon)
|
setColorFilter(supportColor)
|
||||||
/** 上色 */
|
/** Android 12 设置图标外圈颜色 */
|
||||||
setColorFilter(if (isUpperOfAndroidS || customIconColor == 0) supportColor else customIconColor)
|
if (isUpperOfAndroidS && hasIconColor)
|
||||||
/** Android 12 设置图标外圈颜色 */
|
background = DrawableBuilder().rounded().solidColor(iconColor).build()
|
||||||
if (isUpperOfAndroidS && customIconColor != 0)
|
} else iconImageView.apply {
|
||||||
background = DrawableBuilder().rounded().solidColor(customIconColor).build()
|
/** 重新设置图标 */
|
||||||
}
|
setImageDrawable(notifyInstance.compatNotifyIcon(context, iconDrawable))
|
||||||
else {
|
/** 设置裁切到边界 */
|
||||||
/** 重新设置图标 - 防止系统更改它 */
|
clipToOutline = true
|
||||||
iconImageView.setImageDrawable(iconDrawable)
|
/** 设置一个圆角轮廓裁切 */
|
||||||
/** 判断如果是灰度图标就给他设置一个白色颜色遮罩 */
|
outlineProvider = object : ViewOutlineProvider() {
|
||||||
if (isGrayscaleIcon) iconImageView.apply {
|
override fun getOutline(view: View, out: Outline) {
|
||||||
/** 设置图标着色 */
|
out.setRoundRect(
|
||||||
setColorFilter(supportColor)
|
0, 0,
|
||||||
/** Android 12 设置图标外圈颜色 */
|
view.width, view.height, 5.dp(context)
|
||||||
if (isUpperOfAndroidS && hasIconColor)
|
)
|
||||||
background = DrawableBuilder().rounded().solidColor(iconColor).build()
|
|
||||||
} else iconImageView.apply {
|
|
||||||
/** 重新设置图标 */
|
|
||||||
setImageDrawable(notifyInstance.compatNotifyIcon(context, iconDrawable))
|
|
||||||
/** 设置裁切到边界 */
|
|
||||||
clipToOutline = true
|
|
||||||
/** 设置一个圆角轮廓裁切 */
|
|
||||||
outlineProvider = object : ViewOutlineProvider() {
|
|
||||||
override fun getOutline(view: View, out: Outline) {
|
|
||||||
out.setRoundRect(
|
|
||||||
0, 0,
|
|
||||||
view.width, view.height, 5.dp(context)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/** 清除原生的背景边距设置 */
|
|
||||||
if (isUpperOfAndroidS) setPadding(0, 0, 0, 0)
|
|
||||||
/** 清除原生的主题色背景圆圈颜色 */
|
|
||||||
if (isUpperOfAndroidS) background = null
|
|
||||||
}
|
}
|
||||||
|
/** 清除原生的背景边距设置 */
|
||||||
|
if (isUpperOfAndroidS) setPadding(0, 0, 0, 0)
|
||||||
|
/** 清除原生的主题色背景圆圈颜色 */
|
||||||
|
if (isUpperOfAndroidS) background = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook 通知栏小图标颜色
|
* Hook 通知栏小图标颜色
|
||||||
@@ -446,18 +453,7 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
val isNotGrayscaleIcon = notifyInstance.isXmsf || !isGrayscaleIcon(context, iconDrawable)
|
val isNotGrayscaleIcon = notifyInstance.isXmsf || !isGrayscaleIcon(context, iconDrawable)
|
||||||
|
|
||||||
/** 获取目标修复彩色图标的 APP */
|
/** 获取目标修复彩色图标的 APP */
|
||||||
var isTargetFixApp = false
|
val isTargetFixApp = compatCustomIcon(!isNotGrayscaleIcon, notifyInstance.opPkgName).first != null
|
||||||
/** 如果开启了自定义通知图标优化 */
|
|
||||||
if (prefs.getBoolean(ENABLE_NOTIFY_ICON_FIX, default = true))
|
|
||||||
run {
|
|
||||||
if (iconDatas.isNotEmpty())
|
|
||||||
iconDatas.forEach {
|
|
||||||
if (notifyInstance.opPkgName == it.packageName && isAppNotifyHookOf(it)) {
|
|
||||||
if (isNotGrayscaleIcon || isAppNotifyHookAllOf(it)) isTargetFixApp = true
|
|
||||||
return@run
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* 只要不是灰度就返回彩色图标
|
* 只要不是灰度就返回彩色图标
|
||||||
* 否则不对颜色进行反色处理防止一些系统图标出现异常
|
* 否则不对颜色进行反色处理防止一些系统图标出现异常
|
||||||
@@ -552,6 +548,9 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
NotificationHeaderViewWrapperClass.clazz
|
NotificationHeaderViewWrapperClass.clazz
|
||||||
.field { name = "mIcon" }.of<ImageView>(instance) ?: return@afterHook
|
.field { name = "mIcon" }.of<ImageView>(instance) ?: return@afterHook
|
||||||
|
|
||||||
|
/** 通知是否展开 */
|
||||||
|
var isExpanded = false
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从父类中得到 mRow 变量 - [ExpandableNotificationRowClass]
|
* 从父类中得到 mRow 变量 - [ExpandableNotificationRowClass]
|
||||||
* 获取其中的得到通知方法
|
* 获取其中的得到通知方法
|
||||||
@@ -560,7 +559,12 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
.method { name = "getEntry" }
|
.method { name = "getEntry" }
|
||||||
.get(NotificationViewWrapperClass.clazz.field {
|
.get(NotificationViewWrapperClass.clazz.field {
|
||||||
name = "mRow"
|
name = "mRow"
|
||||||
}.get(instance).self).call()?.let {
|
}.get(instance).self?.also {
|
||||||
|
isExpanded = ExpandableNotificationRowClass.clazz.method {
|
||||||
|
name = "isExpanded"
|
||||||
|
returnType = BooleanType
|
||||||
|
}.get(it).invoke<Boolean>() == true
|
||||||
|
}).call()?.let {
|
||||||
it.javaClass.method {
|
it.javaClass.method {
|
||||||
name = "getSbn"
|
name = "getSbn"
|
||||||
}.get(it).invoke<StatusBarNotification>()
|
}.get(it).invoke<StatusBarNotification>()
|
||||||
@@ -568,8 +572,15 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
.method { name = "getStatusBarNotification" }
|
.method { name = "getStatusBarNotification" }
|
||||||
.get(NotificationViewWrapperClass.clazz.field { name = "mRow" }.get(instance).self)
|
.get(NotificationViewWrapperClass.clazz.field { name = "mRow" }.get(instance).self)
|
||||||
.invoke<StatusBarNotification>()
|
.invoke<StatusBarNotification>()
|
||||||
|
|
||||||
|
/** 获取优先级 */
|
||||||
|
val importance =
|
||||||
|
(iconImageView.context.getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager?)
|
||||||
|
?.getNotificationChannel(expandedNf?.notification?.channelId)?.importance ?: 0
|
||||||
|
/** 非最小化优先级的通知全部设置为展开状态 */
|
||||||
|
if (importance != 1) isExpanded = true
|
||||||
/** 执行 Hook */
|
/** 执行 Hook */
|
||||||
hookNotifyIconOnSet(iconImageView.context, expandedNf, iconImageView)
|
hookNotifyIconOnSet(iconImageView.context, expandedNf, iconImageView, isExpanded)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -56,7 +56,7 @@ class IconPackParams(private val context: Context? = null, private val param: Pa
|
|||||||
val iconDatas
|
val iconDatas
|
||||||
get() = ArrayList<IconDataBean>().apply {
|
get() = ArrayList<IconDataBean>().apply {
|
||||||
storageDataJson?.also {
|
storageDataJson?.also {
|
||||||
if (it.isNotBlank())
|
if (it.isNotBlank()) runCatching {
|
||||||
JSONArray(it).also { array ->
|
JSONArray(it).also { array ->
|
||||||
for (i in 0 until array.length()) runCatching {
|
for (i in 0 until array.length()) runCatching {
|
||||||
(array.get(i) as JSONObject).apply {
|
(array.get(i) as JSONObject).apply {
|
||||||
@@ -74,6 +74,7 @@ class IconPackParams(private val context: Context? = null, private val param: Pa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -5,8 +5,8 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
appVersionName = "1.85"
|
appVersionName = "1.86"
|
||||||
appVersionCode = 18
|
appVersionCode = 19
|
||||||
}
|
}
|
||||||
|
|
||||||
task clean(type: Delete) {
|
task clean(type: Delete) {
|
||||||
|
Reference in New Issue
Block a user