mirror of
https://github.com/fankes/MIUINativeNotifyIcon.git
synced 2025-09-07 03:05:51 +08:00
Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
00bf1acdb8 | |||
099886b0b2 | |||
4109a25b5d | |||
db93f8d48e |
@@ -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/>
|
||||||
|
|
||||||
|
@@ -63,13 +63,11 @@ tasks.whenTaskAdded {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
compileOnly 'de.robv.android.xposed:api:82'
|
||||||
|
implementation 'com.highcapable.yukihookapi:api:1.0.4'
|
||||||
|
ksp 'com.highcapable.yukihookapi:ksp-xposed:1.0.4'
|
||||||
implementation "com.github.topjohnwu.libsu:core:3.1.2"
|
implementation "com.github.topjohnwu.libsu:core:3.1.2"
|
||||||
implementation 'androidx.annotation:annotation:1.3.0'
|
implementation 'androidx.annotation:annotation:1.3.0'
|
||||||
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1'
|
|
||||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
|
|
||||||
compileOnly 'de.robv.android.xposed:api:82'
|
|
||||||
implementation 'com.highcapable.yukihookapi:api:1.0.3'
|
|
||||||
ksp 'com.highcapable.yukihookapi:ksp-xposed:1.0.3'
|
|
||||||
implementation 'com.geyifeng.immersionbar:immersionbar:3.2.0'
|
implementation 'com.geyifeng.immersionbar:immersionbar:3.2.0'
|
||||||
implementation 'com.geyifeng.immersionbar:immersionbar-ktx:3.2.0'
|
implementation 'com.geyifeng.immersionbar:immersionbar-ktx:3.2.0'
|
||||||
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
|
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
|
||||||
|
@@ -75,6 +75,9 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
/** 原生存在的类 */
|
/** 原生存在的类 */
|
||||||
private const val ContrastColorUtilClass = "com.android.internal.util.ContrastColorUtil"
|
private const val ContrastColorUtilClass = "com.android.internal.util.ContrastColorUtil"
|
||||||
|
|
||||||
|
/** 原生存在的类 */
|
||||||
|
private const val StatusBarIconViewClass = "$SYSTEMUI_PACKAGE_NAME.statusbar.StatusBarIconView"
|
||||||
|
|
||||||
/** 根据多个版本存在不同的包名相同的类 */
|
/** 根据多个版本存在不同的包名相同的类 */
|
||||||
private val ExpandableNotificationRowClass = VariousClass(
|
private val ExpandableNotificationRowClass = VariousClass(
|
||||||
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.row.ExpandableNotificationRow",
|
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.row.ExpandableNotificationRow",
|
||||||
@@ -130,17 +133,6 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
}
|
}
|
||||||
} else BitmapCompatTool.isGrayscaleDrawable(drawable)
|
} else BitmapCompatTool.isGrayscaleDrawable(drawable)
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否为新版本 MIUI 方案
|
|
||||||
*
|
|
||||||
* 拥有状态栏图标颜色检查功能
|
|
||||||
* @return [Boolean]
|
|
||||||
*/
|
|
||||||
private val PackageParam.hasIgnoreStatusBarIconColor
|
|
||||||
get() = safeOfFalse {
|
|
||||||
NotificationUtilClass.clazz.hasMethod(name = "ignoreStatusBarIconColor", ExpandedNotificationClass.clazz)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否为旧版本 MIUI 方案
|
* 是否为旧版本 MIUI 方案
|
||||||
*
|
*
|
||||||
@@ -432,14 +424,14 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook 通知栏小图标颜色
|
* 判断状态栏小图标颜色以及反射的核心方法
|
||||||
*
|
*
|
||||||
* 区分系统版本 - 由于每个系统版本的方法不一样这里单独拿出来进行 Hook
|
* 区分系统版本 - 由于每个系统版本的方法不一样这里单独拿出来进行 Hook
|
||||||
* @param context 实例
|
* @param context 实例
|
||||||
* @param expandedNf 状态栏实例
|
* @param expandedNf 状态栏实例
|
||||||
* @return [Boolean] 是否忽略通知图标颜色
|
* @return [Boolean] 是否忽略通知图标颜色
|
||||||
*/
|
*/
|
||||||
private fun PackageParam.hookIgnoreStatusBarIconColor(context: Context, expandedNf: StatusBarNotification?) =
|
private fun PackageParam.hasIgnoreStatusBarIconColor(context: Context, expandedNf: StatusBarNotification?) =
|
||||||
if (!context.isMiuiNotifyStyle)
|
if (!context.isMiuiNotifyStyle)
|
||||||
if (prefs.getBoolean(ENABLE_COLOR_ICON_HOOK, default = true)) safeOfFalse {
|
if (prefs.getBoolean(ENABLE_COLOR_ICON_HOOK, default = true)) safeOfFalse {
|
||||||
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
|
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
|
||||||
@@ -456,16 +448,26 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
* 只要不是灰度就返回彩色图标
|
* 只要不是灰度就返回彩色图标
|
||||||
* 否则不对颜色进行反色处理防止一些系统图标出现异常
|
* 否则不对颜色进行反色处理防止一些系统图标出现异常
|
||||||
*/
|
*/
|
||||||
if (isTargetFixApp) false else isNotGrayscaleIcon
|
(if (isTargetFixApp) false else isNotGrayscaleIcon).also {
|
||||||
} ?: true
|
printLogcat(tag = "IconColor", context, expandedNf, isTargetFixApp, !isNotGrayscaleIcon)
|
||||||
} else false
|
}
|
||||||
else true
|
} ?: true.also { printLogcat(tag = "IconColor", context, expandedNf, isCustom = false, isGrayscale = false) }
|
||||||
|
} else false.also { printLogcat(tag = "IconColor", context, expandedNf, isCustom = false, isGrayscale = true) }
|
||||||
|
else true.also { printLogcat(tag = "IconColor", context, expandedNf, isCustom = false, isGrayscale = false) }
|
||||||
|
|
||||||
override fun onHook() = encase {
|
override fun onHook() {
|
||||||
configs {
|
runConfig()
|
||||||
debugTag = "MIUINativeNotifyIcon"
|
runHook()
|
||||||
isDebug = false
|
}
|
||||||
}
|
|
||||||
|
/** 配置 Hook */
|
||||||
|
private fun runConfig() = configs {
|
||||||
|
debugTag = "MIUINativeNotifyIcon"
|
||||||
|
isDebug = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 开始 Hook */
|
||||||
|
private fun runHook() = encase {
|
||||||
loadApp(SYSTEMUI_PACKAGE_NAME) {
|
loadApp(SYSTEMUI_PACKAGE_NAME) {
|
||||||
when {
|
when {
|
||||||
/** 不是 MIUI 系统停止 Hook */
|
/** 不是 MIUI 系统停止 Hook */
|
||||||
@@ -494,19 +496,6 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
*/
|
*/
|
||||||
replaceAny { globalContext?.isMiuiNotifyStyle ?: isShowMiuiStyle }
|
replaceAny { globalContext?.isMiuiNotifyStyle ?: isShowMiuiStyle }
|
||||||
}
|
}
|
||||||
if (hasIgnoreStatusBarIconColor)
|
|
||||||
injectMember {
|
|
||||||
method {
|
|
||||||
name = "ignoreStatusBarIconColor"
|
|
||||||
param(ExpandedNotificationClass.clazz)
|
|
||||||
}
|
|
||||||
replaceAny {
|
|
||||||
hookIgnoreStatusBarIconColor(
|
|
||||||
context = globalContext ?: error("GlobalContext got null"),
|
|
||||||
expandedNf = firstArgs as? StatusBarNotification?
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/** 强制回写系统的状态栏图标样式为原生 */
|
/** 强制回写系统的状态栏图标样式为原生 */
|
||||||
injectMember {
|
injectMember {
|
||||||
var isUseLegacy = false
|
var isUseLegacy = false
|
||||||
@@ -534,6 +523,19 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
StatusBarIconViewClass.hook {
|
||||||
|
/** Hook 状态栏图标的颜色 */
|
||||||
|
injectMember {
|
||||||
|
method { name = "updateIconColor" }
|
||||||
|
afterHook {
|
||||||
|
instance<ImageView>().also {
|
||||||
|
if (hasIgnoreStatusBarIconColor(it.context, field { name = "mNotification" }
|
||||||
|
.of<StatusBarNotification>(instance))) it.colorFilter = null
|
||||||
|
else it.setColorFilter(field { name = "mCurrentSetColor" }.of<Int>(instance) ?: 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
NotificationHeaderViewWrapperClass.hook {
|
NotificationHeaderViewWrapperClass.hook {
|
||||||
/** 修复下拉通知图标自动设置回 APP 图标的方法 */
|
/** 修复下拉通知图标自动设置回 APP 图标的方法 */
|
||||||
injectMember {
|
injectMember {
|
||||||
|
@@ -20,15 +20,15 @@
|
|||||||
*
|
*
|
||||||
* This file is Created by fankes on 2022/1/24.
|
* This file is Created by fankes on 2022/1/24.
|
||||||
*/
|
*/
|
||||||
|
@file:Suppress("MemberVisibilityCanBePrivate")
|
||||||
|
|
||||||
package com.fankes.miui.notify.params
|
package com.fankes.miui.notify.params
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import com.fankes.miui.notify.bean.IconDataBean
|
import com.fankes.miui.notify.bean.IconDataBean
|
||||||
import com.fankes.miui.notify.hook.HookConst.NOTIFY_ICON_DATAS
|
import com.fankes.miui.notify.hook.HookConst.NOTIFY_ICON_DATAS
|
||||||
import com.fankes.miui.notify.utils.bitmap
|
import com.fankes.miui.notify.utils.*
|
||||||
import com.fankes.miui.notify.utils.safeOf
|
|
||||||
import com.fankes.miui.notify.utils.safeOfNan
|
|
||||||
import com.highcapable.yukihookapi.hook.factory.modulePrefs
|
import com.highcapable.yukihookapi.hook.factory.modulePrefs
|
||||||
import com.highcapable.yukihookapi.hook.param.PackageParam
|
import com.highcapable.yukihookapi.hook.param.PackageParam
|
||||||
import org.json.JSONArray
|
import org.json.JSONArray
|
||||||
@@ -47,7 +47,7 @@ class IconPackParams(private val context: Context? = null, private val param: Pa
|
|||||||
* 已存储的 JSON 数据
|
* 已存储的 JSON 数据
|
||||||
* @return [String]
|
* @return [String]
|
||||||
*/
|
*/
|
||||||
private val storageDataJson get() = (context?.modulePrefs ?: param?.prefs)?.getString(NOTIFY_ICON_DATAS)
|
internal val storageDataJson get() = (context?.modulePrefs ?: param?.prefs)?.getString(NOTIFY_ICON_DATAS)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取图标数据
|
* 获取图标数据
|
||||||
@@ -59,25 +59,32 @@ class IconPackParams(private val context: Context? = null, private val param: Pa
|
|||||||
if (it.isNotBlank()) runCatching {
|
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 {
|
add(convertToBean(array.get(i) as JSONObject)!!)
|
||||||
add(
|
}.onFailure { context?.snake(msg = "部分规则加载失败") }
|
||||||
IconDataBean(
|
|
||||||
appName = getString("appName"),
|
|
||||||
packageName = getString("packageName"),
|
|
||||||
isEnabled = getBoolean("isEnabled"),
|
|
||||||
isEnabledAll = getBoolean("isEnabledAll"),
|
|
||||||
iconBitmap = getString("iconBitmap").bitmap,
|
|
||||||
iconColor = safeOfNan { Color.parseColor(getString("iconColor")) },
|
|
||||||
contributorName = getString("contributorName")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}.onFailure { context?.snake(msg = "规则加载发生错误") }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换为 [IconDataBean]
|
||||||
|
* @param jsonObject Json 实例
|
||||||
|
* @return [IconDataBean] or null
|
||||||
|
*/
|
||||||
|
private fun convertToBean(jsonObject: JSONObject) = safeOfNull {
|
||||||
|
jsonObject.let {
|
||||||
|
IconDataBean(
|
||||||
|
appName = it.getString("appName"),
|
||||||
|
packageName = it.getString("packageName"),
|
||||||
|
isEnabled = it.getBoolean("isEnabled"),
|
||||||
|
isEnabledAll = it.getBoolean("isEnabledAll"),
|
||||||
|
iconBitmap = it.getString("iconBitmap").bitmap,
|
||||||
|
iconColor = safeOfNan { Color.parseColor(it.getString("iconColor")) },
|
||||||
|
contributorName = it.getString("contributorName")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 拼接图标数组数据
|
* 拼接图标数组数据
|
||||||
* @param dataJson1 图标数据 JSON
|
* @param dataJson1 图标数据 JSON
|
||||||
@@ -93,7 +100,21 @@ class IconPackParams(private val context: Context? = null, private val param: Pa
|
|||||||
* @param json 数据
|
* @param json 数据
|
||||||
* @return [Boolean]
|
* @return [Boolean]
|
||||||
*/
|
*/
|
||||||
fun isNotVaildJson(json: String) = json.trim().let { !it.startsWith("[") || !it.endsWith("]") }
|
fun isNotVaildJson(json: String) = !isJsonArray(json) && !isJsonObject(json)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否为 JSON 数组
|
||||||
|
* @param json 数据
|
||||||
|
* @return [Boolean]
|
||||||
|
*/
|
||||||
|
fun isJsonArray(json: String) = json.trim().let { it.startsWith("[") && it.endsWith("]") }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否为 JSON 实例
|
||||||
|
* @param json 数据
|
||||||
|
* @return [Boolean]
|
||||||
|
*/
|
||||||
|
fun isJsonObject(json: String) = json.trim().let { it.startsWith("{") && it.endsWith("}") }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否为异常地址
|
* 是否为异常地址
|
||||||
|
@@ -294,22 +294,42 @@ class ConfigureActivity : BaseActivity() {
|
|||||||
invalidate()
|
invalidate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
confirmButton {
|
IconPackParams(context = this@ConfigureActivity).also { params ->
|
||||||
IconPackParams(context = this@ConfigureActivity).also { params ->
|
confirmButton(text = "合并") {
|
||||||
when {
|
editText.text.toString().also { jsonString ->
|
||||||
editText.text.toString().isNotBlank() && params.isNotVaildJson(editText.text.toString()) ->
|
when {
|
||||||
snake(msg = "不是有效的 JSON 数据")
|
jsonString.isNotBlank() && params.isNotVaildJson(jsonString) -> snake(msg = "不是有效的 JSON 数据")
|
||||||
editText.text.toString().isNotBlank() -> {
|
jsonString.isNotBlank() -> {
|
||||||
params.save(editText.text.toString())
|
params.save(
|
||||||
filterText = ""
|
params.splicingJsonArray(
|
||||||
mockLocalData()
|
dataJson1 = params.storageDataJson ?: "[]",
|
||||||
SystemUITool.showNeedUpdateApplySnake(context = this@ConfigureActivity)
|
dataJson2 = jsonString.takeIf { params.isJsonArray(it) } ?: "[$jsonString]"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
filterText = ""
|
||||||
|
mockLocalData()
|
||||||
|
SystemUITool.showNeedUpdateApplySnake(context = this@ConfigureActivity)
|
||||||
|
}
|
||||||
|
else -> snake(msg = "请输入有效内容")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cancelButton(text = "覆盖") {
|
||||||
|
editText.text.toString().also { jsonString ->
|
||||||
|
when {
|
||||||
|
jsonString.isNotBlank() && params.isNotVaildJson(jsonString) -> snake(msg = "不是有效的 JSON 数据")
|
||||||
|
jsonString.isNotBlank() -> {
|
||||||
|
params.save(dataJson = jsonString.takeIf { params.isJsonArray(it) } ?: "[$jsonString]")
|
||||||
|
filterText = ""
|
||||||
|
mockLocalData()
|
||||||
|
SystemUITool.showNeedUpdateApplySnake(context = this@ConfigureActivity)
|
||||||
|
}
|
||||||
|
else -> snake(msg = "请输入有效内容")
|
||||||
}
|
}
|
||||||
else -> snake(msg = "规则数组内容为空")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cancelButton()
|
neutralButton(text = "取消")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -19,7 +19,7 @@
|
|||||||
android:layout_height="150dp"
|
android:layout_height="150dp"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:gravity="center|start|top"
|
android:gravity="center|start|top"
|
||||||
android:hint="请粘贴 JSON 规则数组到此处"
|
android:hint="请粘贴 JSON 规则到此处"
|
||||||
android:textSize="14sp" />
|
android:textSize="14sp" />
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
@@ -5,8 +5,8 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
appVersionName = "1.9"
|
appVersionName = "1.95"
|
||||||
appVersionCode = 21
|
appVersionCode = 22
|
||||||
}
|
}
|
||||||
|
|
||||||
task clean(type: Delete) {
|
task clean(type: Delete) {
|
||||||
|
Reference in New Issue
Block a user