61 Commits
1.0 ... 1.25

Author SHA1 Message Date
485f85873c Update version to 1.25,fix more bugs. 2022-02-05 22:57:04 +08:00
8202239f57 通知优化图标展示界面顶部增加适配的图标个数展示 2022-02-05 22:39:19 +08:00
7e4cd7f71a 增加“下载管理程序”、“MIUI天气”、“米家”、“和平精英”、“起点读书”、“高德地图”、“百度地图”、“招商银行”、“人民日报”、“即可”通知优化图标 2022-02-05 22:30:53 +08:00
f6c4448eed 适配 MIUI 12,修复在 MIUI 12 上不生效的问题,加入最低 MIUI 版本判断 2022-02-05 21:42:35 +08:00
45dde844b7 Update version to 1.2,fix more bugs. 2022-02-03 22:04:09 +08:00
8e987897fc 增加帮助文案 2022-02-03 21:58:27 +08:00
60e2a5b6ea 增加模块设置缓存功能,防止通知图标过多造成下拉通知栏卡顿 2022-02-03 21:34:02 +08:00
8a31373ebd 优化代码 2022-02-03 21:27:18 +08:00
963933f168 修改“微信”通知优化小图标配置 2022-02-03 21:23:51 +08:00
a72e89e57c 增加“QQ邮箱”通知优化小图标 2022-02-03 21:23:17 +08:00
c40b1bf3ee 增加“多看阅读”、“闲鱼”、“美团”、“美团外卖”通知优化小图标 2022-02-03 21:19:19 +08:00
3045c90580 优化淘宝、抖音通知优化图标大小 2022-02-03 21:06:22 +08:00
8e9c0127fa 待发布版本 2022-02-02 15:59:47 +08:00
7da1949de3 默认关闭模块调试日志输出 2022-02-02 15:53:08 +08:00
1bbacad3d2 默认关闭模块调试日志输出 2022-02-02 15:52:46 +08:00
6e6b566ea1 优化 lamprose 提交的通知优化图标,增加“大众点评”、“小米视频”、“腾讯视频”、“QQ音乐”、“酷狗音乐”、“滴滴出行”、“菜鸟”通知优化图标 2022-02-02 15:51:57 +08:00
bf5cd8de2b 修复 2022-02-02 15:07:26 +08:00
Fankesyooni
ec5796f37e Merge pull request #2 from lamprose/master
增加”小米商城“,”饿了么“,”小米有品“,”携程“,”App分享“,”小米社区“,”网易云音乐“,”什么值得买“,”王者荣耀“通知优化图标
2022-02-02 02:50:39 +08:00
lamprose
51353caec2 增加”小米商城“,”饿了么“,”小米有品“,”携程“,”App分享“,”小米社区“,”网易云音乐“,”什么值得买“,”王者荣耀“通知优化图标 2022-02-02 02:28:17 +08:00
f3ca453a9a Fix a commit 2022-02-02 00:40:24 +08:00
29df754513 Update version to 1.15 fix more bugs. 2022-02-01 23:19:04 +08:00
cd60ec7ac4 修复一个执行顺序问题 2022-02-01 23:16:04 +08:00
4129794bbb 增加“快手”、“小红书”通知优化图标 2022-02-01 23:11:47 +08:00
7fc8d2828a 增加“知乎”、“浏览器”通知优化图标 2022-02-01 23:03:09 +08:00
780e78909a 增加“智能服务”通知优化图标 2022-02-01 22:54:22 +08:00
b40cb86d77 增加“智能服务”通知优化图标 2022-02-01 22:50:57 +08:00
2ab36dd2f3 修复一个问题 2022-02-01 22:48:27 +08:00
95160d30b3 关闭混淆功能 2022-02-01 22:44:00 +08:00
5c42934bf2 增加调试日志功能 2022-02-01 22:41:04 +08:00
e939121d86 增加“音质音效”通知优化图标 2022-02-01 22:25:56 +08:00
f243a0de76 增加详细模块运行日志并改善 Hook 方案 2022-02-01 22:16:49 +08:00
97757c3d65 增加详细模块运行日志并改善 Hook 方案 2022-02-01 22:15:42 +08:00
1df34bac1c Update Version to 1.1 Fix more bugs. 2022-01-31 04:11:31 +08:00
0ab45aa6d1 Update Version to 1.1 Fix more bugs. 2022-01-31 03:49:57 +08:00
edc089475d Update Version to 1.1 Fix more bugs. 2022-01-31 03:48:01 +08:00
f96e20ea8a Update Version to 1.1 Fix more bugs. 2022-01-31 03:43:59 +08:00
ae42952c34 修正一些文案 2022-01-31 03:33:09 +08:00
3ad3022ae1 修正一些文案 2022-01-31 03:30:38 +08:00
79e87c583c 更新通知图标优化名单功能并优化代码和相关功能 2022-01-31 03:27:35 +08:00
6c041ac4d5 更新通知图标优化名单功能并优化代码和相关功能 2022-01-31 02:18:13 +08:00
e651e39b1d 更新通知图标优化名单功能并优化代码和相关功能 2022-01-31 01:11:16 +08:00
d8ccf23b48 更新通知图标优化名单功能并优化代码和相关功能 2022-01-31 00:55:45 +08:00
13aa2cc9da 更新通知图标优化名单功能并优化代码和相关功能 2022-01-31 00:49:24 +08:00
d346a97d87 更新通知图标优化名单功能并优化代码和相关功能 2022-01-31 00:43:20 +08:00
c9bc9987a7 更新通知图标优化名单功能并优化代码和相关功能 2022-01-31 00:42:33 +08:00
ae1c27aaec 更新通知图标优化名单功能并优化代码和相关功能 2022-01-31 00:03:11 +08:00
638f8f86fb 更新许可证日期 2022-01-30 22:24:58 +08:00
8655d532cc 自动区分推送通知的包名 2022-01-30 21:47:05 +08:00
ce9a29e74b 修复 MIUI 版本显示问题 2022-01-30 21:42:42 +08:00
db4096db5c 修改了文案 2022-01-30 21:32:02 +08:00
7deb9c2e0a 修改了文案 2022-01-30 21:30:22 +08:00
24e7f9149d 修改了文案 2022-01-30 21:29:35 +08:00
14821c3ef1 修改了文案 2022-01-30 21:27:42 +08:00
2cbe3e2cd0 修改了文案 2022-01-30 21:25:53 +08:00
a72cbe01c8 适配最低基于 Android 9 的 MIUI 2022-01-30 21:14:40 +08:00
755570c00e 适配系统深色模式的图标颜色,修复之前的 MIUI 版本通知图标 Hook 失败的问题 2022-01-30 20:51:15 +08:00
362b553c24 修复 Android 11 MIUI 旧版本通知图标的问题 2022-01-30 20:14:30 +08:00
20210166c5 适配夜间模式以及 Material3 2022-01-30 19:21:49 +08:00
80d539c469 Update README.md 2022-01-26 06:55:29 +08:00
761c0846c2 Update README.md 2022-01-26 06:32:14 +08:00
8309b7e45c Update README.md 2022-01-26 03:12:18 +08:00
51 changed files with 2776 additions and 425 deletions

6
.idea/misc.xml generated
View File

@@ -3,8 +3,14 @@
<component name="DesignSurface">
<option name="filePathToZoomLevelMap">
<map>
<entry key="app/src/main/res/drawable-night/dark_round.xml" value="0.256" />
<entry key="app/src/main/res/drawable-night/permotion_round.xml" value="0.256" />
<entry key="app/src/main/res/drawable-v24/ic_launcher_foreground.xml" value="0.44871794871794873" />
<entry key="app/src/main/res/drawable/permotion_round.xml" value="0.256" />
<entry key="app/src/main/res/drawable/white_round.xml" value="0.256" />
<entry key="app/src/main/res/layout/activity_config.xml" value="0.42168674698795183" />
<entry key="app/src/main/res/layout/activity_main.xml" value="0.4036346245815399" />
<entry key="app/src/main/res/layout/adapter_config.xml" value="0.4375" />
<entry key="app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml" value="0.44871794871794873" />
</map>
</option>

42
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,42 @@
# 开始贡献
欢迎为通知图标优化名单贡献宝贵资源!<br/>
## 分支规定
不管是直接 Push 代码还是提交 Pull Request都必须使 commit 指向 master 分支。
## 代码格式规范
- 1.全部提交代码必须使用 IDE(Android Studio 或 IDEA) 进行格式化,未经格式化的代码将拒绝合并提交请求
- 2.代码必须使用 4 spaces 缩进格式化
## 贡献方法
- 在下方的类中添加新的 APP 通知图标适配条目
- [IconPackParams.kt](https://github.com/fankes/MIUINativeNotifyIcon/blob/master/app/src/main/java/com/fankes/miui/notify/params/IconPackParams.kt)
- 使用灰度位图转 Base64 来得到 Base64 的位图数据字符串
- [BitmapToBase64](https://github.com/fankes/BitmapToBase64)
- 新增条目的模板如下所示
```kotlin
IconDataBean(
isEnabled = true, // 是否默认启用替换
isEnabledAll = false, // 是否默认启用完全替换
appName = "", // APP 名称
packageName = "", // APP 包名
iconBitmap = ("").bitmap, // 位图数据 Base64
contributorName = "" // 贡献者昵称
)
```
- 提交时请将后方的注释删除,否则不予合并代码
## 其它要求
- 1.调试性质或大批量注释代码,禁止提交
- 2.类名和方法名仅能由开发者进行修改和提交,禁止随意修改项目名称、方法名称以及类名
- 3.禁止随意更新项目依赖以及增加新的依赖,有问题请提前提交到 issues 进行说明
- 4.禁止更新项目版本号,版本号交由开发者合并代码并发布 release 版本
- 5.代码语言要求,请统一使用 Kotlin除特殊情况外不接受其他语言的提交
- 6.以上

View File

@@ -2,30 +2,73 @@
![Eclipse Marketplace](https://img.shields.io/badge/build-passing-brightgreen)
![Eclipse Marketplace](https://img.shields.io/badge/license-GPL3.0-blue)
![Eclipse Marketplace](https://img.shields.io/badge/version-v1.0-green)
![Eclipse Marketplace](https://img.shields.io/badge/version-v1.25-green)
<br/><br/>
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/app/src/main/ic_launcher-playstore.png" width = "100" height = "100"/>
<br/>
Fix the native notification bar icon function abandoned by the MIUI development team.<br/>
修复被 MIUI 开发组丢弃的原生通知图标,支持 MIUI 12.5、13 以及最新版本。
修复被 MIUI 开发组丢弃的原生通知图标,支持 MIUI 12、12.5、13 以及最新版本。
# 开始使用
点击下载最新版本
<a href='https://github.com/fankes/MIUINativeNotifyIcon/releases'>![Eclipse Marketplace](https://img.shields.io/badge/download-v1.0-green)</a>
<a href='https://github.com/fankes/MIUINativeNotifyIcon/releases'>![Eclipse Marketplace](https://img.shields.io/badge/download-v1.25-green)</a>
<br/><br/>
⚠️适配说明:此模块仅支持 Lsposed(作用域“系统界面”)、EdXposed(不推荐)、不支持太极无极(阴)
⚠️ 适配说明<br/>
- 此模块仅支持 Lsposed(作用域“系统界面”)、EdXposed(不推荐)、不支持太极无极(阴)
- 目前最低支持基于 Android 9 版本的 MIUI12 或 MIUI12.5(建议)
- 使用 Zygisk 方式运行的 Lsposed 可能会发生 Hook 不生效的问题,若出现问题请使用 Ramdisk 版本的 Lsposed
# 禁止任何商业用途
本模块完全开源免费,如果好用你可以打赏支持开发,严禁未经许可进行二改贩卖,违者必惩必究。
# 背景历史
# 开始贡献
由于国内厂商 APP 的不规范彩色图标影响整体图标的美观,现在开放第三方 APP 的通知图标适配。<br/>
欢迎为通知图标优化名单贡献宝贵资源!<br/>
- [CONTRIBUTING](https://github.com/fankes/MIUINativeNotifyIcon/blob/master/CONTRIBUTING.md)
# 历史背景
这个模块诞生来源于 MIUI 的乱改和不规范,本来 MIUI 9 之后,官方给出了原生通知图标样式,后面由于用户反应通知栏经常出现黑白块。 这当然不是系统的错,而是国内 APP 极其不规范的通知图标设计,于是 MIUI
选择直接忽略这个问题把全部图标都改成了 APP 的彩色图标, 使得之前拥有自有样式的原生图标也被破坏通知中“setSmallIcon”不再有效这个模块就是为了修复被 MIUI 开发组忽略的图标问题, 并完美地给 MIUI 修复了黑白块图标的问题。
<br/>
# 探索历程
- 原生 Android 的小图标和通知图标具有状态性<br/>
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/images/native.jpg" height = "35"/><br/>
- 而 MIUI 最近的版本直接破坏了这一状态性,全部设置为 APP 的图标,不仅难看而且你无法下拉通知栏区别这些图标代表什么<br/>
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/images/miui.jpg" height = "40"/><br/>
- 同样地,通知面板的图标同样遵守这一状态性<br/>
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/images/native_n_1.jpg" height = "100"/><br/>
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/images/native_n_2.jpg" height = "100"/><br/>
- 而 MIUI 做了什么呢<br/>
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/images/miui_n_1.jpg" height = "100"/><br/>
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/images/miui_n_2.jpg" height = "100"/><br/>
- 不曾记得是什么版本开始MIUI 把通知图标改成了这个鬼样子,寻找开发组提案也是无人问津,最后转念一想,自己干吧。
- 由于目前大量通知图标都来自 MIPUSH 发出的营销通知,而 MIPUSH 的图标都是统一的彩色应用图标,很多应用也没有适配这一特性, 在通知栏广告满天飞的情况下MIUI
选择放弃原生通知功能,而做出这种违反原生通知规则的做法,而这些彩色图标被设置为单色调图标,也确实会发生黑白块的问题,但是同时又会破坏遵守规范的图标。
- 真的没有办法了吗?在不断探索下,我找到了原生支持色彩判断的类
```
com.android.internal.util.ContrastColorUtil
```
- 这个类中有一个方法可以拿出来判断图标的灰度效果
```
ContrastColorUtil.getInstance().isGrayscaleIcon(drawable);
```
- 问题就被解决了,顺便修了一下被 MIUI 破坏的通知图标以及优化了一下应用本身方块图标的圆角...
- 最后,我想大声问一句 MIUI 开发组:“就这?” 就这么简单的问题为什么拖了这么长时间也没有结论,还要交给用户去修复,这真的是一种负责任的表现吗?
- 后来一想,也是啊,被国内生态毒害的用户,怎么可能会去想到这些问题呢,最后只能是我自作多情,还对 MIUI 留有一点情怀吧。
- ——来自一个无可奈何的 MIUI 老用户
# 许可证
- [GPL-3.0](https://www.gnu.org/licenses/gpl-3.0.html)

View File

@@ -19,10 +19,10 @@ android {
defaultConfig {
applicationId "com.fankes.miui.notify"
minSdk 29
minSdk 26
targetSdk 26
versionCode 1
versionName "1.0"
versionCode 5
versionName "1.25"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

View File

@@ -4,7 +4,7 @@
package="com.fankes.miui.notify">
<application
android:name=".application.MNvApplication"
android:name=".application.MNNApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
@@ -31,7 +31,6 @@
<activity
android:name="com.fankes.miui.notify.ui.MainActivity"
android:exported="true"
android:label="@string/app_name"
android:screenOrientation="behind">
<intent-filter>
@@ -53,5 +52,10 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity
android:name="com.fankes.miui.notify.ui.ConfigureActivity"
android:exported="false"
android:screenOrientation="behind" />
</application>
</manifest>

View File

@@ -1,5 +1,5 @@
/**
* Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
*
* This file is part of MIUINativeNotifyIcon.
*
@@ -25,22 +25,27 @@ package com.fankes.miui.notify.application
import android.app.Application
import androidx.appcompat.app.AppCompatDelegate
class MNvApplication : Application() {
class MNNApplication : Application() {
companion object {
/** 全局静态实例 */
private var context: MNvApplication? = null
private var context: MNNApplication? = null
/** 调用全局静态实例 */
val appContext get() = context ?: error("App is death")
/** 自身 APP 是否已启动 */
var isMineStarted = false
}
override fun onCreate() {
super.onCreate()
/** 设置状态 */
isMineStarted = true
/** 设置静态实例 */
context = this
/** 禁止系统夜间模式对自己造成干扰 - 模块要什么夜间模式?😅 (其实是我懒) */
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
/** 跟随系统夜间模式 */
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
}
}

View File

@@ -0,0 +1,46 @@
/**
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
*
* This file is part of MIUINativeNotifyIcon.
*
* MIUINativeNotifyIcon is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MIUINativeNotifyIcon is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file is Created by fankes on 2022/1/30.
*/
package com.fankes.miui.notify.bean
import android.graphics.Bitmap
import com.fankes.miui.notify.utils.base64
import java.io.Serializable
/**
* 通知栏小图标 bean
* @param appName APP 名称 - 仅限默认语言区域
* @param packageName 包名
* @param iconBitmap 图标位图
* @param contributorName 贡献者昵称
* @param isEnabled 是否默认启用替换
* @param isEnabledAll 是否默认启用完全替换
*/
data class IconDataBean(
var appName: String,
var packageName: String,
var iconBitmap: Bitmap,
var contributorName: String,
var isEnabled: Boolean,
var isEnabledAll: Boolean,
) : Serializable {
fun toEnabledName() = ("$appName$packageName").base64 + "_enable"
fun toEnabledAllName() = ("$appName$packageName").base64 + "_enable_all"
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
*
* This file is part of MIUINativeNotifyIcon.
*
@@ -18,17 +18,16 @@
*
* This file is Created by fankes on 2022/01/24.
*/
@file:Suppress("DEPRECATION", "SameParameterValue")
@file:Suppress("SameParameterValue", "DEPRECATION")
package com.fankes.miui.notify.hook
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.Outline
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.Icon
import android.os.Build
import android.service.notification.StatusBarNotification
import android.util.Log
import android.view.View
@@ -36,13 +35,10 @@ import android.view.ViewOutlineProvider
import android.widget.ImageView
import androidx.annotation.Keep
import androidx.core.graphics.drawable.toBitmap
import com.fankes.miui.notify.hook.HookMedium.QQ_PACKAGE_NAME
import com.fankes.miui.notify.hook.HookMedium.SELF_PACKAGE_NAME
import com.fankes.miui.notify.hook.HookMedium.SYSTEMUI_PACKAGE_NAME
import com.fankes.miui.notify.utils.XPrefUtils
import com.fankes.miui.notify.utils.dp
import com.fankes.miui.notify.utils.isNotMIUI
import com.fankes.miui.notify.utils.round
import com.fankes.miui.notify.params.IconPackParams
import com.fankes.miui.notify.utils.*
import de.robv.android.xposed.*
import de.robv.android.xposed.callbacks.XC_LoadPackage
@@ -51,18 +47,24 @@ class HookMain : IXposedHookLoadPackage {
companion object {
private const val NotificationUtilClass =
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.NotificationUtil"
private const val SystemUIApplicationClass = "$SYSTEMUI_PACKAGE_NAME.SystemUIApplication"
private const val NotificationHeaderViewWrapperInjectorClass =
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.row.wrapper.NotificationHeaderViewWrapperInjector"
private const val ExpandedNotificationClass =
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.ExpandedNotification"
private const val SystemUIApplicationClass = "$SYSTEMUI_PACKAGE_NAME.SystemUIApplication"
private const val StatusBarIconViewClass = "$SYSTEMUI_PACKAGE_NAME.statusbar.StatusBarIconView"
private const val ContrastColorUtilClass = "com.android.internal.util.ContrastColorUtil"
private val NotificationUtilClass = Pair(
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.NotificationUtil",
"$SYSTEMUI_PACKAGE_NAME.miui.statusbar.notification.NotificationUtil"
)
private val ExpandedNotificationClass = Pair(
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.ExpandedNotification",
"$SYSTEMUI_PACKAGE_NAME.miui.statusbar.ExpandedNotification"
)
}
/** 仅作用于替换的 Hook 方法体 */
@@ -88,25 +90,25 @@ class HookMain : IXposedHookLoadPackage {
/**
* 忽略异常运行
* @param error 错误信息
* @param it 正常回调
*/
private fun runWithoutError(error: String, it: () -> Unit) {
private fun runWithoutError(error: String = "", it: () -> Unit) {
try {
it()
} catch (e: Error) {
logE("hookFailed: $error", e)
} catch (e: Exception) {
logE("hookFailed: $error", e)
} catch (e: Throwable) {
logE("hookFailed: $error", e)
logE(content = "hookFailed: $error", e)
}
}
/**
* Print the log
* @param content
* @param it 继续执行的方法
*/
private fun logD(content: String) {
private fun logD(content: String, it: () -> Unit = {}) {
it()
if (!HookMedium.getBoolean(HookMedium.ENABLE_MODULE_LOG, default = false)) return
XposedBridge.log("[MIUINativeNotifyIcon][D]>$content")
Log.d("MIUINativeNotifyIcon", content)
}
@@ -114,13 +116,84 @@ class HookMain : IXposedHookLoadPackage {
/**
* Print the log
* @param content
* @param it 继续执行的方法
*/
private fun logE(content: String, e: Throwable? = null) {
private fun logW(content: String, it: () -> Unit = {}) {
it()
if (!HookMedium.getBoolean(HookMedium.ENABLE_MODULE_LOG, default = false)) return
XposedBridge.log("[MIUINativeNotifyIcon][W]>$content")
Log.d("MIUINativeNotifyIcon", content)
}
/**
* Print the log
* @param content
* @param e 异常
* @param it 继续执行的方法
*/
private fun logE(content: String, e: Throwable? = null, it: () -> Unit = {}) {
it()
XposedBridge.log("[MIUINativeNotifyIcon][E]>$content")
XposedBridge.log(e)
Log.e("MIUINativeNotifyIcon", content, e)
}
/**
* 目标类是否存在
* @param name 类名
* @return [Boolean]
*/
private fun XC_LoadPackage.LoadPackageParam.isClassExist(name: String) = try {
classLoader.loadClass(name)
true
} catch (_: Throwable) {
false
}
/**
* 目标方法是否存在
* @param classPair 类数组
* @param name 方法名
* @param param 方法参数类型数组
* @return [Boolean]
*/
private fun XC_LoadPackage.LoadPackageParam.isMethodExist(
classPair: Pair<String, String>,
name: String, vararg param: Class<*>
) = try {
(try {
classLoader.loadClass(classPair.first)
} catch (_: Throwable) {
try {
classLoader.loadClass(classPair.second)
} catch (_: Throwable) {
null
}
})?.getDeclaredMethod(name, *param)
true
} catch (_: Throwable) {
false
}
/**
* 目标方法是否存在
* @param className 类名
* @param name 方法名
* @param param 方法参数类型数组
* @return [Boolean]
*/
private fun XC_LoadPackage.LoadPackageParam.isMethodExist(className: String, name: String, vararg param: Class<*>) =
try {
(try {
classLoader.loadClass(className)
} catch (_: Throwable) {
null
})?.getDeclaredMethod(name, *param)
true
} catch (_: Throwable) {
false
}
/**
* 查找目标类
* @param name 类名
@@ -129,6 +202,40 @@ class HookMain : IXposedHookLoadPackage {
private fun XC_LoadPackage.LoadPackageParam.findClass(name: String) =
classLoader.loadClass(name)
/**
* 查找目标类 - 两个类都没找到才会报错
* @param pair 类名数组
* @return [Class]
*/
private fun XC_LoadPackage.LoadPackageParam.findClass(pair: Pair<String, String>) = try {
classLoader.loadClass(pair.first)
} catch (_: Throwable) {
try {
classLoader.loadClass(pair.second)
} catch (e: Throwable) {
logE(content = "Cannot find Class ${pair.first} and ${pair.second}", e)
error("[Throwable] Cannot find Class ${pair.first} and ${pair.second}")
}
}
/**
* 存在目标类的类名 - 两个类都没找到会抛出异常
* @param pair 类名数组
* @return [String] 目标类名
*/
private fun XC_LoadPackage.LoadPackageParam.existClass(pair: Pair<String, String>) = try {
classLoader.loadClass(pair.first)
pair.first
} catch (_: Throwable) {
try {
classLoader.loadClass(pair.second)
pair.second
} catch (_: Throwable) {
logE(content = "Cannot find Class ${pair.first} and ${pair.second}")
error("[Throwable] Cannot find Class ${pair.first} and ${pair.second}")
}
}
/**
* ⚠️ 这个是修复彩色图标的关键核心代码判断
* 判断是否为灰度图标 - 反射执行系统方法
@@ -144,6 +251,20 @@ class HookMain : IXposedHookLoadPackage {
.apply { isAccessible = true }.invoke(instance, icon) as Boolean
}
/**
* 获取 [ExpandedNotificationClass] 的应用名称
* @param instance 通知实例
* @return [String]
*/
private fun XC_LoadPackage.LoadPackageParam.findAppName(instance: Any?) = try {
findClass(ExpandedNotificationClass).getDeclaredMethod("getAppName").let {
it.isAccessible = true
it.invoke(instance) as? String ?: "unknown"
}
} catch (_: Throwable) {
"unknown"
}
/**
* 获取全局上下文
* @return [Context]
@@ -153,171 +274,394 @@ class HookMain : IXposedHookLoadPackage {
.getDeclaredMethod("getContext").apply { isAccessible = true }
.invoke(null) as Context
/**
* Hook 状态栏小图标
* 区分系统版本 - 由于每个系统版本的方法不一样这里单独拿出来进行 Hook
* @param param Hook Param
*/
private fun XC_LoadPackage.LoadPackageParam.hookSmallIconOnSet(param: XC_MethodHook.MethodHookParam) =
runWithoutError(error = "GetSmallIconOnSet") {
/** 获取通知小图标 */
val iconDrawable = (param.result as Icon).loadDrawable(globalContext)
/** 判断是否不是灰度图标 */
val isNotGrayscaleIcon = !isGrayscaleIcon(globalContext, iconDrawable)
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
(param.args?.get(0) as? StatusBarNotification?)?.also { notifyInstance ->
/** 目标彩色通知 APP 图标 */
var customIcon: Icon? = null
if (HookMedium.getBoolean(HookMedium.ENABLE_COLOR_ICON_HOOK, default = true))
run {
IconPackParams.iconDatas.forEach {
if ((notifyInstance.opPkgName == it.packageName ||
findAppName(notifyInstance) == it.appName) &&
HookMedium.isAppNotifyHookOf(it)
) {
if (isNotGrayscaleIcon || HookMedium.isAppNotifyHookAllOf(it))
customIcon = Icon.createWithBitmap(it.iconBitmap)
return@run
}
}
}
when {
/** 如果开启了修复 APP 的彩色图标 */
customIcon != null && HookMedium.getBoolean(HookMedium.ENABLE_NOTIFY_ICON_HOOK, default = true) ->
logD(
content = "GetSmallIconOnSet -> " +
"hook Custom AppIcon [pkgName] ${notifyInstance.opPkgName} " +
"[appName] ${findAppName(notifyInstance)}"
) { param.result = customIcon }
/** 若不是灰度图标自动处理为圆角 */
isNotGrayscaleIcon ->
logD(
content = "GetSmallIconOnSet -> " +
"hook Color AppIcon [pkgName] ${notifyInstance.opPkgName} " +
"[appName] ${findAppName(notifyInstance)}"
) {
param.result = Icon.createWithBitmap(
iconDrawable.toBitmap().round(15.dp(globalContext))
)
}
}
} ?: logW(content = "GetSmallIconOnSet -> StatusBarNotification got null")
}
/**
* Hook 通知栏小图标
* 区分系统版本 - 由于每个系统版本的方法不一样这里单独拿出来进行 Hook
* @param param Hook Param
* @param isNew 是否为新版方式
*/
private fun XC_LoadPackage.LoadPackageParam.hookNotifyIconOnSet(param: XC_MethodHook.MethodHookParam, isNew: Boolean) =
runWithoutError(error = "AutoSetAppIconOnSet") {
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
(param.args?.get(if (isNew) 2 else 1) as? StatusBarNotification?)?.let { notifyInstance ->
/** 是否 Hook 彩色通知图标 */
val isHookColorIcon = HookMedium.getBoolean(HookMedium.ENABLE_COLOR_ICON_HOOK, default = true)
/** 获取 [Context] */
val context = if (isNew) param.args[0] as Context else globalContext
/** 新版风格反色 */
val newStyle = if (context.isSystemInDarkMode) 0xFF2D2D2D.toInt() else Color.WHITE
/** 旧版风格反色 */
val oldStyle = if (context.isNotSystemInDarkMode) 0xFF515151.toInt() else Color.WHITE
/** 获取图标框 */
val iconImageView = param.args[if (isNew) 1 else 0] as ImageView
/** 获取通知小图标 */
val iconDrawable = notifyInstance.notification.smallIcon.loadDrawable(context)
/** 判断图标风格 */
val isGrayscaleIcon = isGrayscaleIcon(context, iconDrawable)
/** 自定义默认小图标 */
var customIcon: Bitmap? = null
if (isHookColorIcon)
run {
IconPackParams.iconDatas.forEach {
if ((notifyInstance.opPkgName == it.packageName ||
findAppName(notifyInstance) == it.appName) &&
HookMedium.isAppNotifyHookOf(it)
) {
if (!isGrayscaleIcon || HookMedium.isAppNotifyHookAllOf(it))
customIcon = it.iconBitmap
return@run
}
}
}
/** 如果开启了修复 APP 的彩色图标 */
if (customIcon != null && HookMedium.getBoolean(HookMedium.ENABLE_NOTIFY_ICON_HOOK, default = true))
iconImageView.apply {
/** 设置自定义小图标 */
setImageBitmap(customIcon)
/** 上色 */
setColorFilter(if (isUpperOfAndroidS) newStyle else oldStyle)
/** 输出调试日志 */
logD(
content = "AutoSetAppIconOnSet -> " +
"hook Custom AppIcon [pkgName] ${notifyInstance.opPkgName} " +
"[appName] ${findAppName(notifyInstance)}"
)
}
else {
/** 重新设置图标 - 防止系统更改它 */
iconImageView.setImageDrawable(iconDrawable)
/** 判断是否开启 Hook 彩色图标 */
if (isHookColorIcon) {
/** 判断如果是灰度图标就给他设置一个白色颜色遮罩 */
if (isGrayscaleIcon)
logD(
content = "AutoSetAppIconOnSet -> " +
"hook Grayscale AppIcon [pkgName] ${notifyInstance.opPkgName} " +
"[appName] ${findAppName(notifyInstance)}"
) { iconImageView.setColorFilter(if (isUpperOfAndroidS) newStyle else oldStyle) }
else
iconImageView.apply {
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
/** 输出调试日志 */
logD(
content = "AutoSetAppIconOnSet -> " +
"hook Color AppIcon [pkgName] ${notifyInstance.opPkgName} " +
"[appName] ${findAppName(notifyInstance)}"
)
}
/** 否则一律设置灰度图标 */
} else
logD(
content = "AutoSetAppIconOnSet -> " +
"hook NonColor AppIcon [pkgName] ${notifyInstance.opPkgName} " +
"[appName] ${findAppName(notifyInstance)}"
) { iconImageView.setColorFilter(if (isUpperOfAndroidS) newStyle else oldStyle) }
}
} ?: logW(content = "AutoSetAppIconOnSet -> StatusBarNotification got null")
}
/**
* Hook 通知栏小图标颜色
* 区分系统版本 - 由于每个系统版本的方法不一样这里单独拿出来进行 Hook
* @param expandedNf 状态栏实例
* @return [Boolean] 是否忽略通知图标颜色
*/
private fun XC_LoadPackage.LoadPackageParam.hookIgnoreStatusBarIconColor(expandedNf: StatusBarNotification?) =
if (HookMedium.getBoolean(HookMedium.ENABLE_COLOR_ICON_HOOK, default = true))
try {
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
expandedNf?.let { notifyInstance ->
/** 获取通知小图标 */
val iconDrawable =
notifyInstance.notification.smallIcon.loadDrawable(globalContext)
/** 判断是否不是灰度图标 */
val isNotGrayscaleIcon = !isGrayscaleIcon(globalContext, iconDrawable)
/** 获取目标修复彩色图标的 APP */
var isTargetApp = false
run {
IconPackParams.iconDatas.forEach {
if ((notifyInstance.opPkgName == it.packageName ||
findAppName(notifyInstance) == it.appName) &&
HookMedium.isAppNotifyHookOf(it)
) {
if (isNotGrayscaleIcon || HookMedium.isAppNotifyHookAllOf(it)) isTargetApp = true
return@run
}
}
}
/** 如果开启了修复 APP 的彩色图标 */
if (isTargetApp && HookMedium.getBoolean(HookMedium.ENABLE_NOTIFY_ICON_HOOK, default = true)) let {
logD(
content = "IgnoreStatusBarIconColor -> " +
"hook Color AppIcon [pkgName] ${notifyInstance.opPkgName} " +
"[appName] ${findAppName(notifyInstance)}"
)
false
}
else let {
logD(
content = "IgnoreStatusBarIconColor -> " +
"hook Grayscale[${!isNotGrayscaleIcon}] AppIcon " +
"[pkgName] ${notifyInstance.opPkgName} " +
"[appName] ${findAppName(notifyInstance)}"
)
/** 只要不是灰度就返回彩色图标 */
isNotGrayscaleIcon
}
} ?: let {
logW(content = "IgnoreStatusBarIconColor -> StatusBarNotification got null")
/** 否则不对颜色进行反色处理防止一些系统图标出现异常 */
true
}
} catch (e: Exception) {
logE("Failed to hook ignoreStatusBarIconColor", e)
false
}
else let {
logD(content = "IgnoreStatusBarIconColor -> hook NonColor AppIcon")
false
}
override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) {
if (lpparam == null) return
when (lpparam.packageName) {
/** Hook 自身 */
SELF_PACKAGE_NAME ->
XposedHelpers.findAndHookMethod(
"$SELF_PACKAGE_NAME.hook.HookMedium",
lpparam.classLoader,
"isHooked",
replaceToTrue
)
runWithoutError(error = "HookModuleSelf") {
XposedHelpers.findAndHookMethod(
"$SELF_PACKAGE_NAME.hook.HookMedium",
lpparam.classLoader,
"isHooked",
replaceToTrue
)
}
/** Hook 系统 UI */
SYSTEMUI_PACKAGE_NAME -> {
/** 若不是 MIUI 系统直接停止 Hook */
if (isNotMIUI) return
/** 若没开启模块直接停止 Hook */
if (!XPrefUtils.getBoolean(HookMedium.ENABLE_MODULE, default = true)) return
/** 强制回写系统的状态栏图标样式为原生 */
runWithoutError("SubstituteSmallIcon") {
XposedHelpers.findAndHookMethod(
NotificationUtilClass,
lpparam.classLoader,
"shouldSubstituteSmallIcon",
lpparam.findClass(ExpandedNotificationClass),
replaceToFalse
)
}
/** 修复通知图标为彩色 */
runWithoutError("IgnoreStatusBarIconColor") {
XposedHelpers.findAndHookMethod(
NotificationUtilClass,
lpparam.classLoader,
"ignoreStatusBarIconColor",
lpparam.findClass(ExpandedNotificationClass),
object : XC_MethodReplacement() {
override fun replaceHookedMethod(param: MethodHookParam) =
if (XPrefUtils.getBoolean(HookMedium.ENABLE_COLOR_ICON_HOOK, default = true))
try {
/** 获取发送通知的 APP */
val packageName = (param.args[0] as StatusBarNotification).opPkg
/** 获取通知小图标 */
val iconDrawable = (param.args[0] as StatusBarNotification)
.notification.smallIcon.loadDrawable(lpparam.globalContext)
/** 如果开启了修复聊天 APP 的图标 */
if (packageName == QQ_PACKAGE_NAME &&
XPrefUtils.getBoolean(HookMedium.ENABLE_CHAT_ICON_HOOK, default = true)
) false
/** 只要不是灰度就返回彩色图标 */
else !lpparam.isGrayscaleIcon(lpparam.globalContext, iconDrawable)
} catch (e: Exception) {
logE("Failed to hook ignoreStatusBarIconColor", e)
false
}
else false
SYSTEMUI_PACKAGE_NAME ->
when {
/** 不是 MIUI 系统停止 Hook */
isNotMIUI ->
logW(content = "Aborted Hook -> This System is not MIUI")
/** 系统版本低于 Android P 停止 Hook */
isLowerAndroidP ->
logW(content = "Aborted Hook -> This System is lower than Android P")
/** 不是支持的 MIUI 系统停止 Hook */
isNotSupportMiuiVersion ->
logW(content = "Aborted Hook -> This MIUI Version $miuiVersion not supported")
/** Hook 被手动关闭停止 Hook */
!HookMedium.getBoolean(HookMedium.ENABLE_MODULE, default = true) ->
logW(content = "Aborted Hook -> Hook Closed")
else -> {
/** 强制回写系统的状态栏图标样式为原生 */
runWithoutError(error = "SubstituteSmallIcon") {
XposedHelpers.findAndHookMethod(
lpparam.existClass(NotificationUtilClass),
lpparam.classLoader,
"shouldSubstituteSmallIcon",
lpparam.findClass(ExpandedNotificationClass),
replaceToFalse
)
}
)
}
/** 强制回写系统的状态栏图标样式为原生 */
runWithoutError("GetSmallIcon") {
XposedHelpers.findAndHookMethod(
NotificationUtilClass,
lpparam.classLoader,
"getSmallIcon",
lpparam.findClass(ExpandedNotificationClass),
Int::class.java,
object : XC_MethodHook() {
override fun afterHookedMethod(param: MethodHookParam) {
runWithoutError("GetSmallIconOnSet") {
/** 获取通知小图标 */
val iconDrawable = (param.result as Icon).loadDrawable(lpparam.globalContext)
/** 判断要设置的图标 */
when {
/** 如果开启了修复聊天 APP 的图标 */
(param.args[0] as StatusBarNotification).opPkg == QQ_PACKAGE_NAME &&
XPrefUtils.getBoolean(HookMedium.ENABLE_CHAT_ICON_HOOK, default = true) ->
param.result = Icon.createWithBitmap(IconPackParams.qqSmallIcon)
/** 若不是灰度图标自动处理为圆角 */
!lpparam.isGrayscaleIcon(lpparam.globalContext, iconDrawable) ->
param.result = Icon.createWithBitmap(
iconDrawable.toBitmap().round(15.dp(lpparam.globalContext))
)
/** 修复通知图标为彩色 */
if (lpparam.isMethodExist(NotificationUtilClass, name = "ignoreStatusBarIconColor"))
runWithoutError(error = "IgnoreStatusBarIconColor") {
XposedHelpers.findAndHookMethod(
lpparam.existClass(NotificationUtilClass),
lpparam.classLoader,
"ignoreStatusBarIconColor",
lpparam.findClass(ExpandedNotificationClass),
object : XC_MethodReplacement() {
override fun replaceHookedMethod(param: MethodHookParam) =
lpparam.hookIgnoreStatusBarIconColor(param.args?.get(0) as? StatusBarNotification?)
}
}
)
}
}
)
}
/** 干掉下拉通知图标自动设置回 APP 图标的方法 - Android 12 */
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R)
runWithoutError("ResetIconBgAndPaddings") {
XposedHelpers.findAndHookMethod(
NotificationHeaderViewWrapperInjectorClass,
lpparam.classLoader,
"resetIconBgAndPaddings",
ImageView::class.java,
lpparam.findClass(ExpandedNotificationClass),
replaceToNull
)
}
/** 修复下拉通知图标自动设置回 APP 图标的方法 - Android 12 */
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R)
runWithoutError("AutoSetAppIcon") {
XposedHelpers.findAndHookMethod(
NotificationHeaderViewWrapperInjectorClass,
lpparam.classLoader,
"setAppIcon",
Context::class.java,
ImageView::class.java,
lpparam.findClass(ExpandedNotificationClass),
object : XC_MethodReplacement() {
override fun replaceHookedMethod(param: MethodHookParam): Any? {
runWithoutError("AutoSetAppIconOnSet") {
/** 获取 [Context] */
val context = param.args[0] as Context
else
runWithoutError(error = "UpdateIconColor") {
XposedHelpers.findAndHookMethod(
StatusBarIconViewClass,
lpparam.classLoader, "updateIconColor",
object : XC_MethodHook() {
override fun afterHookedMethod(param: MethodHookParam) =
runWithoutError(error = "UpdateIconColorOnSet") {
/** 是否忽略图标颜色 */
val isIgnoredColor = lpparam.hookIgnoreStatusBarIconColor(
param.thisObject.javaClass.getDeclaredField("mNotification").apply {
isAccessible = true
}[param.thisObject] as? StatusBarNotification?
)
/** 获取图标框 */
val iconImageView = param.args[1] as ImageView
/** 获取通知小图标 */
val iconDrawable = (param.args[2] as StatusBarNotification)
.notification.smallIcon.loadDrawable(context)
/** 获取发送通知的 APP */
val packageName = (param.args[2] as StatusBarNotification).opPkg
/** 如果开启了修复聊天 APP 的图标 */
if (packageName == QQ_PACKAGE_NAME &&
XPrefUtils.getBoolean(HookMedium.ENABLE_CHAT_ICON_HOOK, default = true)
)
iconImageView.apply {
/** 设置自定义小图标 */
setImageDrawable(BitmapDrawable(IconPackParams.qqSmallIcon))
/** 上色 */
setColorFilter(Color.WHITE)
/** 当前着色颜色 */
val currentColor =
param.thisObject.javaClass.getDeclaredField("mCurrentSetColor").apply {
isAccessible = true
}[param.thisObject] as? Int ?: Color.WHITE
/** 判断并设置颜色 */
if (isIgnoredColor)
(param.thisObject as? ImageView?)?.colorFilter = null
else (param.thisObject as? ImageView?)?.setColorFilter(currentColor)
logD(content = "IgnoreStatusBarIconColor[UseOldWay] -> isIgnored[$isIgnoredColor]")
}
else {
/** 重新设置图标 - 防止系统更改它 */
iconImageView.setImageDrawable(iconDrawable)
/** 判断如果是灰度图标就给他设置一个白色颜色遮罩 */
if (lpparam.isGrayscaleIcon(context, iconDrawable))
iconImageView.setColorFilter(Color.WHITE)
else
iconImageView.apply {
clipToOutline = true
/** 设置一个圆角轮廓裁切 */
outlineProvider = object : ViewOutlineProvider() {
override fun getOutline(view: View, out: Outline) {
out.setRoundRect(0, 0, view.width, view.height, 5.dp(context))
}
}
/** 清除原生的背景边距设置 */
setPadding(0, 0, 0, 0)
/** 清除原生的主题色背景圆圈颜色 */
setBackgroundDrawable(null)
}
}
}
return null
)
}
/** 强制回写系统的状态栏图标样式为原生 */
runWithoutError(error = "GetSmallIcon") {
try {
/** 新版方法 */
lpparam.findClass(NotificationUtilClass)
.getDeclaredMethod(
"getSmallIcon",
lpparam.findClass(ExpandedNotificationClass),
Int::class.java
).apply { isAccessible = true }
} catch (_: Throwable) {
try {
/** 旧版方法 */
lpparam.findClass(NotificationUtilClass)
.getDeclaredMethod("getSmallIcon", lpparam.findClass(ExpandedNotificationClass))
.apply { isAccessible = true }
} catch (_: Throwable) {
/** 超旧版方法 */
lpparam.findClass(NotificationUtilClass)
.getDeclaredMethod(
"getSmallIcon",
Context::class.java,
lpparam.findClass(ExpandedNotificationClass)
).apply { isAccessible = true }
}
}.also {
XposedBridge.hookMethod(it, object : XC_MethodHook() {
override fun afterHookedMethod(param: MethodHookParam) {
lpparam.hookSmallIconOnSet(param)
}
})
}
}
/** 修复下拉通知图标自动设置回 APP 图标的方法 */
if (lpparam.isClassExist(NotificationHeaderViewWrapperInjectorClass))
runWithoutError(error = "AutoSetAppIcon") {
var isNewWay = true
try {
/** 新版方法 */
lpparam.findClass(NotificationHeaderViewWrapperInjectorClass)
.getDeclaredMethod(
"setAppIcon",
Context::class.java,
ImageView::class.java,
lpparam.findClass(ExpandedNotificationClass)
).apply { isAccessible = true }
} catch (_: Throwable) {
isNewWay = false
/** 旧版方法 */
lpparam.findClass(NotificationHeaderViewWrapperInjectorClass)
.getDeclaredMethod(
"setAppIcon",
ImageView::class.java,
lpparam.findClass(ExpandedNotificationClass)
).apply { isAccessible = true }
}.also {
XposedBridge.hookMethod(it, object : XC_MethodReplacement() {
override fun replaceHookedMethod(param: MethodHookParam): Any? {
lpparam.hookNotifyIconOnSet(param, isNew = isNewWay)
return null
}
})
}
}
)
else logW(content = "Your MIUI Version $miuiVersion is too old and not support for RowsIcon")
/** 干掉下拉通知图标自动设置回 APP 图标的方法 - Android 12 */
if (isUpperOfAndroidS &&
lpparam.isMethodExist(
NotificationHeaderViewWrapperInjectorClass,
name = "resetIconBgAndPaddings"
)
) runWithoutError(error = "ResetIconBgAndPaddings") {
XposedHelpers.findAndHookMethod(
NotificationHeaderViewWrapperInjectorClass,
lpparam.classLoader,
"resetIconBgAndPaddings",
ImageView::class.java,
lpparam.findClass(ExpandedNotificationClass),
replaceToNull
)
}
logD(content = "hook Completed!")
}
logD("hook Completed!")
}
}
}
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
*
* This file is part of MIUINativeNotifyIcon.
*
@@ -18,22 +18,33 @@
*
* This file is Created by fankes on 2022/1/24.
*/
@file:Suppress("DEPRECATION", "SetWorldReadable")
package com.fankes.miui.notify.hook
import android.content.Context
import android.os.Handler
import android.util.Log
import android.widget.Toast
import androidx.annotation.Keep
import com.fankes.miui.notify.application.MNNApplication.Companion.appContext
import com.fankes.miui.notify.application.MNNApplication.Companion.isMineStarted
import com.fankes.miui.notify.bean.IconDataBean
import com.fankes.miui.notify.utils.FileUtils
import com.fankes.miui.notify.utils.XPrefUtils
import java.io.File
@Keep
object HookMedium {
const val ENABLE_MODULE = "_enable_module"
const val ENABLE_MODULE_LOG = "_enable_module_log"
const val ENABLE_HIDE_ICON = "_hide_icon"
const val ENABLE_COLOR_ICON_HOOK = "_color_icon_hook"
const val ENABLE_CHAT_ICON_HOOK = "_chat_icon_hook"
const val ENABLE_NOTIFY_ICON_HOOK = "_notify_icon_hook"
const val SELF_PACKAGE_NAME = "com.fankes.miui.notify"
const val SYSTEMUI_PACKAGE_NAME = "com.android.systemui"
const val QQ_PACKAGE_NAME = "com.tencent.mobileqq"
/**
* 判断模块是否激活
@@ -44,4 +55,83 @@ object HookMedium {
Log.d("MIUINativeNotifyIcon", "isHooked: true")
return false
}
/**
* 获取此 APP 的通知图标是否被 Hook
* @param bean 图标 bean
*/
fun isAppNotifyHookOf(bean: IconDataBean) = getBoolean(key = bean.toEnabledName(), default = bean.isEnabled)
/**
* 设置 Hook 此 APP 的通知图标
* @param bean 图标 bean
* @param isHook 是否 Hook
*/
fun putAppNotifyHookOf(bean: IconDataBean, isHook: Boolean) = putBoolean(key = bean.toEnabledName(), bool = isHook)
/**
* 获取此 APP 的通知图标是否被全部 Hook
* @param bean 图标 bean
*/
fun isAppNotifyHookAllOf(bean: IconDataBean) = getBoolean(key = bean.toEnabledAllName(), default = bean.isEnabledAll)
/**
* 设置全部 Hook 此 APP 的通知图标
* @param bean 图标 bean
* @param isHook 是否 Hook
*/
fun putAppNotifyHookAllOf(bean: IconDataBean, isHook: Boolean) = putBoolean(key = bean.toEnabledAllName(), bool = isHook)
/**
* 获取保存的值
* @param key 名称
* @param default 默认值
* @return [Boolean] 保存的值
*/
fun getBoolean(key: String, default: Boolean = false) =
if (isMineStarted)
appContext.getSharedPreferences(
appContext.packageName + "_preferences",
Context.MODE_PRIVATE
).getBoolean(key, default)
else XPrefUtils.getBoolean(key, default)
/**
* 保存值
* @param key 名称
* @param bool 值
*/
fun putBoolean(key: String, bool: Boolean) {
appContext.getSharedPreferences(
appContext.packageName + "_preferences",
Context.MODE_PRIVATE
).edit().putBoolean(key, bool).apply()
setWorldReadable(appContext)
/** 延迟继续设置强制允许 SP 可读可写 */
Handler().postDelayed({ setWorldReadable(appContext) }, 500)
Handler().postDelayed({ setWorldReadable(appContext) }, 1000)
Handler().postDelayed({ setWorldReadable(appContext) }, 1500)
}
/**
* 强制设置 Sp 存储为全局可读可写
* 以供模块使用
* @param context 实例
*/
fun setWorldReadable(context: Context) {
try {
if (FileUtils.getDefaultPrefFile(context).exists()) {
for (file in arrayOf<File>(
FileUtils.getDataDir(context),
FileUtils.getPrefDir(context),
FileUtils.getDefaultPrefFile(context)
)) {
file.setReadable(true, false)
file.setExecutable(true, false)
}
}
} catch (_: Exception) {
Toast.makeText(context, "无法写入模块设置,请检查权限\n如果此提示一直显示,请不要双开模块", Toast.LENGTH_SHORT).show()
}
}
}

View File

@@ -1,59 +0,0 @@
/**
* Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
*
* This file is part of MIUINativeNotifyIcon.
*
* MIUINativeNotifyIcon is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MIUINativeNotifyIcon is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file is Created by fankes on 2022/1/24.
*/
package com.fankes.miui.notify.hook
import android.graphics.Bitmap
import com.fankes.miui.notify.utils.bitmap
import com.fankes.miui.notify.utils.unbase64
object IconPackParams {
/**
* QQ 通知栏小图标
* @return [Bitmap]
*/
val qqSmallIcon by lazy {
("iVBORw0KGgoAAAANSUhEUgAAAEwAAABMCAYAAADHl1ErAAAAAXNSR0IArs4c6QAAAARzQklUCAgI\n" +
"CHwIZIgAAATZSURBVHic7ZxNjF5TGMd/T6uliBk1pSgtxQwlqo2gKghiU4ZaCOIjRGwIiY8QCRs7\n" +
"S4suRJBYkUgXMiIipBYTiZmuKtRHW0biK8xrNE2l9be4d5LpeN/33nue877n3tHf5p259zzPfc4/\n" +
"z7kf5wuOUglLeXFJw8BmYD0wApwBrACW5UUOANPAPuAb4HNg0sx29j/aREgakvSUpHGFMyHpBUln\n" +
"p65Pz5C0VNJLkmYcQs3nkKRtkoZS1y8qkkYl/RBRqPlMS3oodT2jIOnlHgo1nzdT19eFpHf6KNYs\n" +
"O1LXO4hEYs0ynrr+lZD0SkKxZtmeWodSSLoztVJzeC52/aK+uEoaBP6I6TMC55nZt7GcLYrlKOeN\n" +
"yP5i8HZMZ9EEk7QRGI3lLyIbJG2N5Sxak1T2ZLoylr/ITJnZWTEcRckwSeuor1gAqyTdHMNRrCb5\n" +
"TCQ/veT5GE7cTVLSUuBP4Fh/OD1npZn97HEQI8O20AyxAO71OoghWB2fjJ1w38diNMk9wBqvnz5x\n" +
"EDjFzPaHOnBlmLIu5qaIBdmtY7PHgbdJXu60T8ElHmOvYCNO+xQkFWzYaZ+CCzzGXsHOddqnYK2k\n" +
"4HoHG+YXPTXUPiHLycY+g/Bk2EnAoMM+FYtxxO0V7ESHfUqODzX0CLbEYZua40INY/e4LniOClYR\n" +
"j2CtaFH0n99DDT2CneawTU3w969HsEcdtql5PNQwqHunYb2snQjqfQ3NsNtptlgAD4YYhWZYnYfU\n" +
"yhI09FY5wyStpfliQTb0dm1Vo5Am+USATV15sqpBpSaZ91C0aO43ZDtWmNlvZQtXzbC7WVhiATxc\n" +
"pXDVDNsBXFMpnPqz18zOKVu4tGDK5sTvCwqp/mwys1LTPKs0yXsCg2kC95UtWCXDdgPnB4VTf/4C\n" +
"Bszsn6KCpTIsn860UMWC7EF2U5mCZZvkXeGxNIb7yxQq1SQXeHOcpWVmhYMjhRmWPx0XulgAA2U+\n" +
"lco0ySZNZ/JyS1GBMoLdECGQpnB9UYGu97D82/EnHCPFDaTrt2VRhl3G/0ssgKu7nSwSbH3EQJrC\n" +
"pd1OFgl2YYfjh4GpoHDqwRTZ9M12dJ0/ViTYRR2OPwK8WmBbZ94j66pqR6ckAYoFW93m2F4ze61M\n" +
"VDVmwMzeBT5tc25VN8Miwdrd8Lfkvz+WCKyufJf/tlu0tbibYZFgy+b9/7SZ7cr//qREYHXlQ4D8\n" +
"9eGOaF515B4T/1kSLGl3j1fU9oIZZQPRc+sxd8n1TDdNijLsQP47aWa3tTn/eoF9HXnLzP6ee8DM\n" +
"HgPez//tOmZR9Ka/DVgH3Dj/Ivn5IeDXSuGmZ8TMvmp3QtIYcMjMbu3Z1VWPHQTKMuatb4y1RieQ\n" +
"jVV2fbrUhNVm9r3HgXsGYr7Q6QGvnz7wolcsiLvmezv17TubNLONMRzFFGwR8CX1651tAWvMbDqG\n" +
"s2iTgvMhqk3U66P8IHBFLLGgR1v6SZoANvTCdwW+Bi5u9zrk4ZiYziRdBVxHPWYnLgGelfSZmX2Q\n" +
"OpgjkLRV0sfpXq8KmVAddrCTNChpLLEYVRhXNoMymOB7mLIX1p3U76lYRAsYDt2/wvOUXEnzxAIY\n" +
"wLH02nPT30O2ccYoWVf2mYR/Hh0m23dsP9myltlXk9PJlhkuB052+v8F+AL4CGjWln9N5l/CCEZS\n" +
"HWRiiAAAAABJRU5ErkJggg==").unbase64.bitmap
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,125 @@
/**
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
*
* This file is part of MIUINativeNotifyIcon.
*
* MIUINativeNotifyIcon is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MIUINativeNotifyIcon is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file is Created by fankes on 2022/01/30.
*/
@file:Suppress("SetTextI18n", "InflateParams")
package com.fankes.miui.notify.ui
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.ListView
import android.widget.TextView
import android.widget.Toast
import androidx.constraintlayout.utils.widget.ImageFilterView
import com.fankes.miui.notify.R
import com.fankes.miui.notify.hook.HookMedium
import com.fankes.miui.notify.params.IconPackParams
import com.fankes.miui.notify.ui.base.BaseActivity
import com.fankes.miui.notify.view.MaterialSwitch
class ConfigureActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_config)
/** 返回按钮点击事件 */
findViewById<View>(R.id.title_back_icon).setOnClickListener { onBackPressed() }
/** 设置标题个数文本 */
findViewById<TextView>(R.id.config_title_count_text).text = "已适配 ${IconPackParams.iconDatas.size} 个 APP 的通知图标"
/** 设置列表元素和 Adapter */
findViewById<ListView>(R.id.config_list_view).apply {
adapter = object : BaseAdapter() {
private val inflater = LayoutInflater.from(context)
override fun getCount() = IconPackParams.iconDatas.size
override fun getItem(position: Int) = IconPackParams.iconDatas[position]
override fun getItemId(position: Int) = position.toLong()
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
var cView = convertView
val holder: ViewHolder
if (convertView == null) {
holder = ViewHolder()
cView = inflater.inflate(R.layout.adapter_config, null).also {
holder.appIcon = it.findViewById(R.id.adp_app_icon)
holder.appName = it.findViewById(R.id.adp_app_name)
holder.pkgName = it.findViewById(R.id.adp_app_pkg_name)
holder.cbrName = it.findViewById(R.id.adp_cbr_name)
holder.switchOpen = it.findViewById(R.id.adp_app_open_switch)
holder.switchAll = it.findViewById(R.id.adp_app_all_switch)
}
cView.tag = holder
} else holder = convertView.tag as ViewHolder
getItem(position).also {
holder.appIcon.setImageBitmap(it.iconBitmap)
holder.appName.text = it.appName
holder.pkgName.text = it.packageName
holder.cbrName.text = "贡献者:" + it.contributorName
HookMedium.isAppNotifyHookOf(it).also { e ->
holder.switchOpen.isChecked = e
holder.switchAll.isEnabled = e
}
holder.switchOpen.setOnCheckedChangeListener { btn, b ->
if (!btn.isPressed) return@setOnCheckedChangeListener
HookMedium.putAppNotifyHookOf(it, b)
holder.switchAll.isEnabled = b
}
holder.switchAll.isChecked = HookMedium.isAppNotifyHookAllOf(it)
holder.switchAll.setOnCheckedChangeListener { btn, b ->
if (!btn.isPressed) return@setOnCheckedChangeListener
HookMedium.putAppNotifyHookAllOf(it, b)
}
}
return cView!!
}
inner class ViewHolder {
lateinit var appIcon: ImageFilterView
lateinit var appName: TextView
lateinit var pkgName: TextView
lateinit var cbrName: TextView
lateinit var switchOpen: MaterialSwitch
lateinit var switchAll: MaterialSwitch
}
}
}
/** 设置点击事件 */
findViewById<View>(R.id.config_cbr_button).setOnClickListener {
try {
startActivity(Intent().apply {
action = "android.intent.action.VIEW"
data = Uri.parse("https://github.com/fankes/MIUINativeNotifyIcon")
/** 防止顶栈一样重叠在自己的 APP 中 */
flags = Intent.FLAG_ACTIVITY_NEW_TASK
})
} catch (e: Exception) {
Toast.makeText(this, "无法启动系统默认浏览器", Toast.LENGTH_SHORT).show()
}
}
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
*
* This file is part of MIUINativeNotifyIcon.
*
@@ -18,103 +18,110 @@
*
* This file is Created by fankes on 2022/01/24.
*/
@file:Suppress("DEPRECATION", "SetWorldReadable", "SetTextI18n")
@file:Suppress("SetTextI18n")
package com.fankes.miui.notify.ui
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
import android.os.Handler
import android.view.View
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.SwitchCompat
import androidx.constraintlayout.utils.widget.ImageFilterView
import androidx.core.view.isVisible
import com.fankes.miui.notify.BuildConfig
import com.fankes.miui.notify.R
import com.fankes.miui.notify.hook.HookMedium
import com.fankes.miui.notify.ui.base.BaseActivity
import com.fankes.miui.notify.utils.*
import com.gyf.immersionbar.ImmersionBar
import java.io.File
class MainActivity : AppCompatActivity() {
class MainActivity : BaseActivity() {
companion object {
/** 模块版本 */
private const val moduleVersion = BuildConfig.VERSION_NAME
/** MIUI 版本 */
private val miuiVersion by lazy {
if (isMIUI)
findPropString(key = "ro.miui.ui.version.code", default = "无法获取") +
" " + findPropString(key = "ro.system.build.version.incremental")
else "不是 MIUI 系统"
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
/** 隐藏系统的标题栏 */
supportActionBar?.hide()
/** 初始化沉浸状态栏 */
ImmersionBar.with(this)
.statusBarColor(R.color.white)
.autoDarkModeEnable(false)
.statusBarDarkFont(true)
.navigationBarColor(R.color.white)
.navigationBarDarkIcon(true)
.fitsSystemWindows(true)
.init()
/** 设置文本 */
findViewById<TextView>(R.id.main_text_version).text = "当前版本:$moduleVersion"
findViewById<TextView>(R.id.main_text_miui_version).text = "MIUI 版本:$miuiVersion"
/** 判断是否为 MIUI 系统 */
if (isNotMIUI) {
showDialog {
title = "不是 MIUI 系统"
msg = "此模块专为 MIUI 系统打造,当前无法识别你的系统为 MIUI所以模块无法工作。\n" +
"如有问题请联系 酷安 @星夜不荟"
confirmButton(text = "退出") { finish() }
noCancelable()
findViewById<TextView>(R.id.main_text_miui_version).text = "MIUI 版本:$miuiFullVersion"
when {
/** 判断是否为 MIUI 系统 */
isNotMIUI ->
showDialog {
title = "不是 MIUI 系统"
msg = "此模块专为 MIUI 系统打造,当前无法识别你的系统为 MIUI所以模块无法工作。\n" +
"如有问题请联系 酷安 @星夜不荟"
confirmButton(text = "退出") { finish() }
noCancelable()
}
/** 判断最低 Android 系统版本 */
isLowerAndroidP ->
showDialog {
title = "Android 系统版本过低"
msg = "此模块最低支持基于 Android 9 的 MIUI 系统,你的系统版本过低不再进行适配。\n" +
"如有问题请联系 酷安 @星夜不荟"
confirmButton(text = "退出") { finish() }
noCancelable()
}
/** 判断最低 MIUI 版本 */
isNotSupportMiuiVersion ->
showDialog {
title = "MIUI 版本过低"
msg = "此模块最低支持 MIUI 12 系统,你的 MIUI 版本为 ${miuiVersion},不再进行适配。\n" +
"如有问题请联系 酷安 @星夜不荟"
confirmButton(text = "退出") { finish() }
noCancelable()
}
/** 判断是否 Hook */
isHooked() -> {
findViewById<LinearLayout>(R.id.main_lin_status).setBackgroundResource(R.drawable.green_round)
findViewById<ImageFilterView>(R.id.main_img_status).setImageResource(R.mipmap.succcess)
findViewById<TextView>(R.id.main_text_status).text = "模块已激活"
}
return
else ->
showDialog {
title = "模块没有激活"
msg = "检测到模块没有激活,模块需要 Xposed 环境依赖," +
"同时需要系统拥有 Root 权限," +
"请自行查看本页面使用帮助与说明第二条。\n" +
"由于需要修改系统应用达到效果,模块不支持太极阴、应用转生。"
confirmButton(text = "我知道了")
noCancelable()
}
}
/** 判断 Hook 状态 */
if (isHooked()) {
findViewById<LinearLayout>(R.id.main_lin_status).setBackgroundResource(R.drawable.green_round)
findViewById<ImageFilterView>(R.id.main_img_status).setImageResource(R.mipmap.succcess)
findViewById<TextView>(R.id.main_text_status).text = "模块已激活"
} else
showDialog {
title = "模块没有激活"
msg = "检测到模块没有激活,模块需要 Xposed 环境依赖," +
"同时需要系统拥有 Root 权限," +
"请自行查看本页面使用帮助与说明第二条。\n" +
"由于需要修改系统应用达到效果,模块不支持太极阴、应用转生。"
confirmButton(text = "我知道了")
noCancelable()
}
/** 初始化 View */
val moduleEnableSwitch = findViewById<SwitchCompat>(R.id.module_enable_switch)
val moduleEnableLogSwitch = findViewById<SwitchCompat>(R.id.module_enable_log_switch)
val notifyIconConfigItem = findViewById<View>(R.id.config_item_notify)
val hideIconInLauncherSwitch = findViewById<SwitchCompat>(R.id.hide_icon_in_launcher_switch)
val colorIconHookSwitch = findViewById<SwitchCompat>(R.id.color_icon_fix_switch)
val chatIconHookSwitch = findViewById<SwitchCompat>(R.id.chat_icon_fix_switch)
val notifyIconHookSwitch = findViewById<SwitchCompat>(R.id.notify_icon_fix_switch)
/** 获取 Sp 存储的信息 */
notifyIconConfigItem.isVisible = getBoolean(HookMedium.ENABLE_COLOR_ICON_HOOK, default = true)
moduleEnableLogSwitch.isVisible = getBoolean(HookMedium.ENABLE_MODULE, default = true)
moduleEnableSwitch.isChecked = getBoolean(HookMedium.ENABLE_MODULE, default = true)
moduleEnableLogSwitch.isChecked = getBoolean(HookMedium.ENABLE_MODULE_LOG, default = false)
hideIconInLauncherSwitch.isChecked = getBoolean(HookMedium.ENABLE_HIDE_ICON)
colorIconHookSwitch.isChecked = getBoolean(HookMedium.ENABLE_COLOR_ICON_HOOK, default = true)
chatIconHookSwitch.isChecked = getBoolean(HookMedium.ENABLE_CHAT_ICON_HOOK, default = true)
notifyIconHookSwitch.isChecked = getBoolean(HookMedium.ENABLE_NOTIFY_ICON_HOOK, default = true)
moduleEnableSwitch.setOnCheckedChangeListener { btn, b ->
if (!btn.isPressed) return@setOnCheckedChangeListener
putBoolean(HookMedium.ENABLE_MODULE, b)
moduleEnableLogSwitch.isVisible = b
}
moduleEnableLogSwitch.setOnCheckedChangeListener { btn, b ->
if (!btn.isPressed) return@setOnCheckedChangeListener
putBoolean(HookMedium.ENABLE_MODULE_LOG, b)
}
hideIconInLauncherSwitch.setOnCheckedChangeListener { btn, b ->
if (!btn.isPressed) return@setOnCheckedChangeListener
@@ -128,20 +135,26 @@ class MainActivity : AppCompatActivity() {
colorIconHookSwitch.setOnCheckedChangeListener { btn, b ->
if (!btn.isPressed) return@setOnCheckedChangeListener
putBoolean(HookMedium.ENABLE_COLOR_ICON_HOOK, b)
notifyIconConfigItem.isVisible = b
}
chatIconHookSwitch.setOnCheckedChangeListener { btn, b ->
notifyIconHookSwitch.setOnCheckedChangeListener { btn, b ->
if (!btn.isPressed) return@setOnCheckedChangeListener
putBoolean(HookMedium.ENABLE_CHAT_ICON_HOOK, b)
putBoolean(HookMedium.ENABLE_NOTIFY_ICON_HOOK, b)
}
/** 重启按钮点击事件 */
findViewById<View>(R.id.title_restart_icon).setOnClickListener {
showDialog {
title = "重启系统界面"
msg = "你确定要立即重启系统界面吗?"
msg = "你确定要立即重启系统界面吗?\n\n" +
"部分 MIUI 系统使用了状态栏主题可能会发生主题失效的情况,这种情况请再重启一次即可。"
confirmButton { restartSystemUI() }
cancelButton()
}
}
/** 通知图标优化名单按钮点击事件 */
findViewById<View>(R.id.config_notify_app_button).setOnClickListener {
startActivity(Intent(this, ConfigureActivity::class.java))
}
/** 恰饭! */
findViewById<View>(R.id.link_with_follow_me).setOnClickListener {
try {
@@ -185,73 +198,18 @@ class MainActivity : AppCompatActivity() {
else Toast.makeText(this, "ROOT 权限获取失败", Toast.LENGTH_SHORT).show()
}
override fun onResume() {
super.onResume()
setWorldReadable()
}
override fun onRestart() {
super.onRestart()
setWorldReadable()
}
override fun onPause() {
super.onPause()
setWorldReadable()
}
/**
* 获取保存的值
* @param key 名称
* @param default 默认值
* @return [Boolean] 保存的值
*/
private fun getBoolean(key: String, default: Boolean = false) =
getSharedPreferences(
packageName + "_preferences",
Context.MODE_PRIVATE
).getBoolean(key, default)
private fun getBoolean(key: String, default: Boolean = false) = HookMedium.getBoolean(key, default)
/**
* 保存值
* @param key 名称
* @param bool 值
*/
private fun putBoolean(key: String, bool: Boolean) {
getSharedPreferences(
packageName + "_preferences",
Context.MODE_PRIVATE
).edit().putBoolean(key, bool).apply()
setWorldReadable()
/** 延迟继续设置强制允许 SP 可读可写 */
Handler().postDelayed({ setWorldReadable() }, 500)
Handler().postDelayed({ setWorldReadable() }, 1000)
Handler().postDelayed({ setWorldReadable() }, 1500)
}
/**
* 强制设置 Sp 存储为全局可读可写
* 以供模块使用
*/
private fun setWorldReadable() {
try {
if (FileUtils.getDefaultPrefFile(this).exists()) {
for (file in arrayOf<File>(
FileUtils.getDataDir(this),
FileUtils.getPrefDir(this),
FileUtils.getDefaultPrefFile(this)
)) {
file.setReadable(true, false)
file.setExecutable(true, false)
}
}
} catch (_: Exception) {
Toast.makeText(this, "无法写入模块设置,请检查权限\n如果此提示一直显示,请不要双开模块", Toast.LENGTH_SHORT).show()
}
}
override fun onBackPressed() {
setWorldReadable()
super.onBackPressed()
}
private fun putBoolean(key: String, bool: Boolean) = HookMedium.putBoolean(key, bool)
}

View File

@@ -0,0 +1,66 @@
/**
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
*
* This file is part of MIUINativeNotifyIcon.
*
* MIUINativeNotifyIcon is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MIUINativeNotifyIcon is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* This file is Created by fankes on 2022/01/30.
*/
package com.fankes.miui.notify.ui.base
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.fankes.miui.notify.R
import com.fankes.miui.notify.hook.HookMedium
import com.fankes.miui.notify.utils.isNotSystemInDarkMode
import com.gyf.immersionbar.ktx.immersionBar
abstract class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
/** 隐藏系统的标题栏 */
supportActionBar?.hide()
/** 初始化沉浸状态栏 */
immersionBar {
statusBarColor(R.color.colorThemeBackground)
autoDarkModeEnable(true)
statusBarDarkFont(isNotSystemInDarkMode)
navigationBarColor(R.color.colorThemeBackground)
navigationBarDarkIcon(isNotSystemInDarkMode)
fitsSystemWindows(true)
}
}
override fun onResume() {
super.onResume()
HookMedium.setWorldReadable(this)
}
override fun onRestart() {
super.onRestart()
HookMedium.setWorldReadable(this)
}
override fun onPause() {
super.onPause()
HookMedium.setWorldReadable(this)
}
override fun onBackPressed() {
HookMedium.setWorldReadable(this)
super.onBackPressed()
}
}

View File

@@ -1,5 +1,5 @@
/**
* Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
*
* This file is part of MIUINativeNotifyIcon.
*

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
*
* This file is part of MIUINativeNotifyIcon.
*

View File

@@ -1,5 +1,5 @@
/**
* Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
*
* This file is part of MIUINativeNotifyIcon.
*
@@ -25,13 +25,52 @@ package com.fankes.miui.notify.utils
import android.content.Context
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.graphics.*
import android.graphics.Bitmap.createBitmap
import android.os.Build
import android.service.notification.StatusBarNotification
import android.util.Base64
import com.fankes.miui.notify.application.MNvApplication.Companion.appContext
import com.fankes.miui.notify.application.MNNApplication.Companion.appContext
import java.io.DataInputStream
import java.io.DataOutputStream
/**
* 系统深色模式是否开启
* @return [Boolean] 是否开启
*/
val isSystemInDarkMode
get() = (appContext.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
/**
* 系统深色模式是否没开启
* @return [Boolean] 是否开启
*/
inline val isNotSystemInDarkMode get() = !isSystemInDarkMode
/**
* 系统深色模式是否开启
* @return [Boolean] 是否开启
*/
val Context.isSystemInDarkMode get() = (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
/**
* 系统深色模式是否没开启
* @return [Boolean] 是否开启
*/
inline val Context.isNotSystemInDarkMode get() = !isSystemInDarkMode
/**
* 系统版本是否高于或等于 Android 12
* @return [Boolean] 是否符合条件
*/
inline val isUpperOfAndroidS get() = Build.VERSION.SDK_INT > Build.VERSION_CODES.R
/**
* 系统版本是否低于 Android 9
* @return [Boolean] 是否符合条件
*/
inline val isLowerAndroidP get() = Build.VERSION.SDK_INT < Build.VERSION_CODES.P
/**
* 当前设备是否是 MIUI 定制 Android 系统
@@ -52,6 +91,59 @@ val isMIUI by lazy {
*/
inline val isNotMIUI get() = !isMIUI
/**
* 是否为支持的 MIUI 版本
* @return [Boolean]
*/
val isSupportMiuiVersion
get() = when (miuiVersion) {
"12" -> true
"12.5" -> true
"13" -> true
else -> false
}
/**
* 是否不为支持的 MIUI 版本
* @return [Boolean]
*/
inline val isNotSupportMiuiVersion get() = !isSupportMiuiVersion
/**
* 获取 MIUI 版本
* @return [String]
*/
val miuiVersion
get() =
if (isMIUI)
findPropString(key = "ro.miui.ui.version.name", default = "V无法获取").let {
when (it) {
"V110" -> "11"
"V11" -> "11"
"V120" -> "12"
"V12" -> "12"
"V125" -> "12.5"
"V130" -> "13"
"V13" -> "13"
else -> it.replace(oldValue = "V", newValue = "")
}
}.trim()
else "NULL"
/**
* 获取 MIUI 完全版本
* @return [String]
*/
val miuiFullVersion
get() = if (isMIUI) (miuiVersion + " " + findPropString(key = "ro.system.build.version.incremental"))
else "不是 MIUI 系统"
/**
* 获取推送通知的包名
* @return [String]
*/
val StatusBarNotification.opPkgName get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) opPkg else packageName ?: ""
/**
* 得到安装包信息
* @return [PackageInfo]
@@ -99,6 +191,12 @@ val Number.dp get() = (toFloat() * appContext.resources.displayMetrics.density).
*/
fun Number.dp(context: Context) = toFloat() * context.resources.displayMetrics.density
/**
* Base64 加密
* @return [String]
*/
val String.base64: String get() = Base64.encodeToString(toByteArray(), Base64.DEFAULT)
/**
* Base64 解密为字节流
* @return [ByteArray]
@@ -111,6 +209,12 @@ val String.unbase64 get() = Base64.decode(this, Base64.DEFAULT) ?: ByteArray(0)
*/
val ByteArray.bitmap: Bitmap get() = BitmapFactory.decodeByteArray(this, 0, size)
/**
* 字符串解析为位图
* @return [Bitmap]
*/
val String.bitmap: Bitmap get() = unbase64.bitmap
/**
* 圆角图片
* @param radius 圆角度

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
*
* This file is part of MIUINativeNotifyIcon.
*
@@ -25,7 +25,15 @@ import de.robv.android.xposed.XSharedPreferences
object XPrefUtils {
fun getBoolean(key: String, default: Boolean = false) = pref.getBoolean(key, default)
private var xPrefCacheKeyValueBooleans = HashMap<String, Boolean>()
fun getBoolean(key: String, default: Boolean = false) =
xPrefCacheKeyValueBooleans[key].let {
it ?: pref.getBoolean(key, default).let { e ->
xPrefCacheKeyValueBooleans[key] = e
e
}
}
private val pref: XSharedPreferences
get() {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
*
* This file is part of MIUINativeNotifyIcon.
*

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
*
* This file is part of MIUINativeNotifyIcon.
*

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
*
* This file is part of MIUINativeNotifyIcon.
*

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
*
* This file is part of MIUINativeNotifyIcon.
*

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
*
* This file is part of MIUINativeNotifyIcon.
*

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
*
* This file is part of MIUINativeNotifyIcon.
*

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
*
* This file is part of MIUINativeNotifyIcon.
*

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
*
* This file is part of MIUINativeNotifyIcon.
*

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
*
* This file is part of MIUINativeNotifyIcon.
*

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
*
* This file is part of MIUINativeNotifyIcon.
*

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
*
* This file is part of MIUINativeNotifyIcon.
*

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
*
* This file is part of MIUINativeNotifyIcon.
*

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
*
* This file is part of MIUINativeNotifyIcon.
*

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2021. Fankes Studio(qzmmcn@163.com)
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
*
* This file is part of MIUINativeNotifyIcon.
*

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#FFFFFF" />
<solid android:color="#66A6A6A6" />
<corners android:radius="15dp" />
</shape>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#FF786F" />
<corners android:radius="30dp" />
<solid android:color="#666E6E6E" />
<corners android:radius="15dp" />
</shape>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#777777">
<item>
<shape android:shape="rectangle">
<solid android:color="#66DAD9D9" />
<corners android:radius="15dp" />
</shape>
</item>
</ripple>

View File

@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorThemeBackground"
android:orientation="vertical"
tools:context=".ui.MainActivity"
tools:ignore="HardcodedText,UseCompoundDrawables,ContentDescription">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:elevation="0dp"
android:gravity="center|start"
android:paddingLeft="15dp"
android:paddingTop="13dp"
android:paddingRight="15dp"
android:paddingBottom="5dp">
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/title_back_icon"
style="?android:attr/selectableItemBackgroundBorderless"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="25dp"
android:src="@mipmap/back"
android:tint="@color/colorTextGray" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center|start"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:singleLine="true"
android:text="通知图标优化名单"
android:textColor="@color/colorTextGray"
android:textSize="19sp"
android:textStyle="bold" />
<TextView
android:id="@+id/config_title_count_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:text="..."
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="10dp"
android:layout_marginRight="15dp"
android:background="@drawable/permotion_round"
android:elevation="0dp"
android:gravity="center"
android:orientation="horizontal"
android:padding="15dp">
<androidx.constraintlayout.utils.widget.ImageFilterView
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_marginEnd="10dp"
android:alpha="0.85"
android:src="@mipmap/about"
android:tint="@color/colorTextDark" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="0.6"
android:lineSpacingExtra="5dp"
android:text="启用替换后 APP 的彩色通知图标将被替换为预设的小图标。\n启用完全替换将忽略 APP 非彩色图标,强制将全部通知图标替换为列表中预设的小图标。"
android:textColor="@color/colorTextGray"
android:textSize="11sp"
tools:ignore="SmallSp" />
</LinearLayout>
<ListView
android:id="@+id/config_list_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:divider="@color/trans"
android:dividerHeight="15dp"
android:fadingEdgeLength="10dp"
android:listSelector="@null"
android:padding="15dp"
android:requiresFadingEdge="vertical"
android:scrollbars="none" />
<TextView
android:id="@+id/config_cbr_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginBottom="15dp"
android:background="@drawable/button_round"
android:gravity="center"
android:padding="10dp"
android:singleLine="true"
android:text="贡献通知图标优化名单"
android:textColor="@color/colorTextGray"
android:textSize="15sp" />
</LinearLayout>

View File

@@ -4,6 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorThemeBackground"
android:orientation="vertical"
tools:context=".ui.MainActivity"
tools:ignore="HardcodedText,UseCompoundDrawables,ContentDescription">
@@ -11,7 +12,6 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:elevation="0dp"
android:gravity="center|start"
android:paddingLeft="15dp"
@@ -25,8 +25,8 @@
android:layout_weight="1"
android:singleLine="true"
android:text="MIUI 原生通知图标"
android:textColor="#FF323B42"
android:textSize="30sp"
android:textColor="@color/colorTextGray"
android:textSize="25sp"
android:textStyle="bold" />
<androidx.constraintlayout.utils.widget.ImageFilterView
@@ -36,7 +36,7 @@
android:layout_height="25dp"
android:layout_marginEnd="5dp"
android:src="@mipmap/restart"
android:tint="#FF323B42" />
android:tint="@color/colorTextGray" />
</LinearLayout>
<LinearLayout
@@ -110,6 +110,7 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:orientation="vertical">
<LinearLayout
@@ -130,7 +131,7 @@
android:layout_marginEnd="10dp"
android:alpha="0.85"
android:src="@mipmap/about"
android:tint="#FF777777" />
android:tint="@color/colorTextDark" />
<TextView
android:layout_width="wrap_content"
@@ -138,7 +139,7 @@
android:alpha="0.6"
android:lineSpacingExtra="5dp"
android:text="修改设置或开启关闭模块请点击右上角重启系统界面才能生效。"
android:textColor="#FF323B42"
android:textColor="@color/colorTextGray"
android:textSize="11sp"
tools:ignore="SmallSp" />
</LinearLayout>
@@ -149,6 +150,7 @@
android:layout_marginLeft="15dp"
android:layout_marginTop="10dp"
android:layout_marginRight="15dp"
android:animateLayoutChanges="true"
android:background="@drawable/permotion_round"
android:elevation="0dp"
android:gravity="center"
@@ -159,9 +161,19 @@
<com.fankes.miui.notify.view.MaterialSwitch
android:id="@+id/module_enable_switch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="40dp"
android:layout_marginTop="5dp"
android:text="启用模块"
android:textColor="#FF323B42"
android:textColor="@color/colorTextGray"
android:textSize="15sp" />
<com.fankes.miui.notify.view.MaterialSwitch
android:id="@+id/module_enable_log_switch"
android:layout_width="match_parent"
android:layout_height="35dp"
android:layout_marginBottom="5dp"
android:text="启用调试日志"
android:textColor="@color/colorTextGray"
android:textSize="15sp" />
<TextView
@@ -170,8 +182,8 @@
android:layout_marginBottom="10dp"
android:alpha="0.6"
android:lineSpacingExtra="6dp"
android:text="关闭后模块将彻底停止工作,以下选项都将不再生效。"
android:textColor="#777777"
android:text="模块关闭后功能都将彻底停止工作,以下选项都将不再生效。"
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
</LinearLayout>
@@ -192,8 +204,8 @@
android:id="@+id/color_icon_fix_switch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="修复彩色通知图标"
android:textColor="#FF323B42"
android:text="忽略彩色通知图标"
android:textColor="@color/colorTextGray"
android:textSize="15sp" />
<TextView
@@ -202,17 +214,18 @@
android:layout_marginBottom="10dp"
android:alpha="0.6"
android:lineSpacingExtra="6dp"
android:text="此选项默认开启,开启后将自动对应用通知图标进行判断,保持彩色图标不被着色为白色或黑色色块,包括高版本 API 仍然不遵守原生通知图标规范的种种 APP 都将进行修复。"
android:textColor="#777777"
android:text="此选项默认开启,开启后将自动对 APP 通知图标进行判断,保持高版本 API 的 APP 不规范的彩色图标不被着色为白、黑色块并对图标进行圆角优化,关闭后将按照 Android API 规范对 APP 通知进行图标着色,可能会出现着色为黑白、色块情况。"
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/config_item_notify"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginLeft="10dp"
android:layout_marginTop="15dp"
android:layout_marginRight="15dp"
android:layout_marginRight="10dp"
android:background="@drawable/permotion_round"
android:elevation="0dp"
android:gravity="center"
@@ -221,21 +234,38 @@
android:paddingRight="15dp">
<com.fankes.miui.notify.view.MaterialSwitch
android:id="@+id/chat_icon_fix_switch"
android:id="@+id/notify_icon_fix_switch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="优化社交应用通知图标"
android:textColor="#FF323B42"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:text="启用通知图标优化"
android:textColor="@color/colorTextGray"
android:textSize="15sp" />
<TextView
android:id="@+id/config_notify_app_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:background="@drawable/button_round"
android:gravity="center"
android:padding="10dp"
android:singleLine="true"
android:text="配置通知图标优化名单"
android:textColor="@color/colorTextGray"
android:textSize="15sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginBottom="10dp"
android:alpha="0.6"
android:lineSpacingExtra="6dp"
android:text="此选项默认开启,开启后将对 QQ 和微信的消息图标进行色彩修复,使得它们的图标看起来更加美观。"
android:textColor="#777777"
android:text="此选项默认开启,开启后将对优化名单内 APP 通知小图标进行色彩修复,使得它们的图标看起来更加美观。"
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
</LinearLayout>
@@ -257,7 +287,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="在桌面隐藏模块图标"
android:textColor="#FF323B42"
android:textColor="@color/colorTextGray"
android:textSize="15sp" />
<TextView
@@ -266,8 +296,8 @@
android:layout_marginBottom="10dp"
android:alpha="0.6"
android:lineSpacingExtra="6dp"
android:text="隐藏模块图标后,模块不会再在桌面显示,你可以在 EdXposed、太极、LsPosed 中找到模块设置并打开,对原生系统无效。"
android:textColor="#777777"
android:text="隐藏模块图标后界面可能会被关闭,将不会再在桌面显示,你可以在 EdXposed、LsPosed 中找到模块设置并打开。"
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
</LinearLayout>
@@ -295,7 +325,7 @@
android:layout_marginEnd="5dp"
android:alpha="0.85"
android:src="@mipmap/about"
android:tint="#FF323B42" />
android:tint="@color/colorTextGray" />
<TextView
android:layout_width="match_parent"
@@ -303,7 +333,7 @@
android:alpha="0.85"
android:singleLine="true"
android:text="使用帮助与说明"
android:textColor="#FF323B42"
android:textColor="@color/colorTextGray"
android:textSize="12sp" />
</LinearLayout>
@@ -314,7 +344,7 @@
android:alpha="0.8"
android:lineSpacingExtra="6dp"
android:text="Q.这个模块是如何诞生的?\nA.这个模块诞生来源于 MIUI 的乱改和不规范,本来 MIUI 9 之后,官方给出了原生通知图标样式,后面由于用户反应通知栏经常出现黑白块,这当然不是系统的错,而是国内 APP 极其不规范的通知图标设计,于是 MIUI 选择直接忽略这个问题把全部图标都改成了 APP 的彩色图标使得之前拥有自有样式的原生图标也被破坏通知中“setSmallIcon”不再有效这个模块就是为了修复被 MIUI 开发组忽略的图标问题,并完美地给 MIUI 修复了黑白块图标的问题。"
android:textColor="#777777"
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
<TextView
@@ -324,7 +354,7 @@
android:alpha="0.8"
android:lineSpacingExtra="6dp"
android:text="Q.如何使用?\nA.模块仅支持 EdXposed、LsPosed由于涉及到修改系统应用不支持太极(阴)框架,在 LsPosed 的作用域中,只需勾选“系统界面”即可,应用设置后需要重启系统界面。"
android:textColor="#777777"
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
<TextView
@@ -333,8 +363,8 @@
android:layout_marginBottom="10dp"
android:alpha="0.8"
android:lineSpacingExtra="6dp"
android:text="Q.哪些是已知问题?\nA.MIUI 自己的系统应用的通知图标仍然可能出现黑白块的情况,暂时只能等官方修复。"
android:textColor="#777777"
android:text="Q.哪些是已知问题?\nA.以下是问题描述列表:\n(1) MIUI 自己的系统应用的通知图标仍然可能出现黑白块的情况,可使用通知图标优化暂时修复其图标问题,后期只能等官方修复(基本上没什么可能性)。\n(2) 动态小图标可能会在高版本系统中闪烁,这是 MIUI 的问题,后期仍在想解决办法。\n(3) 使用 Zygisk 方式运行的 Lsposed 可能会发生通知优化图标 Hook 不生效的问题(出现黑白块),仅在最新版本的 MIUI 13 开发内测版中遇到,若出现问题请使用 Ramdisk 版本的 Lsposed。"
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
<TextView
@@ -343,7 +373,7 @@
android:alpha="0.8"
android:lineSpacingExtra="6dp"
android:text="Q.如何反馈问题?\nA.酷安关注 @星夜不荟"
android:textColor="#777777"
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
</LinearLayout>
@@ -372,7 +402,7 @@
android:layout_marginEnd="5dp"
android:alpha="0.85"
android:src="@mipmap/about"
android:tint="#FF323B42" />
android:tint="@color/colorTextGray" />
<TextView
android:layout_width="match_parent"
@@ -380,7 +410,7 @@
android:alpha="0.85"
android:singleLine="true"
android:text="项目地址"
android:textColor="#FF323B42"
android:textColor="@color/colorTextGray"
android:textSize="12sp" />
</LinearLayout>
@@ -390,7 +420,7 @@
android:alpha="0.8"
android:lineSpacingExtra="6dp"
android:text="本软件是免费开源项目,遵循 GPL 协议,你可以点击这里前往 Github 查看源码以及获取模块更新。\n严禁以任何形式贩卖、商用本软件否则开发者有权追究其法律责任。"
android:textColor="#777777"
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
</LinearLayout>
@@ -417,7 +447,7 @@
android:gravity="center"
android:lineSpacingExtra="6dp"
android:text="恰饭时间\n点击前往酷安关注我获取我的更多应用"
android:textColor="#FF323B42"
android:textColor="@color/colorTextGray"
android:textSize="16sp" />
<androidx.cardview.widget.CardView
@@ -440,7 +470,7 @@
android:gravity="center"
android:lineSpacingExtra="6dp"
android:text="开发者 酷安 @星夜不荟\n未经允许不得转载、修改复制我的劳动成果"
android:textColor="#FF323B42"
android:textColor="@color/colorTextGray"
android:textSize="16sp" />
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/permotion_round"
android:baselineAligned="false"
android:gravity="center|start"
android:orientation="horizontal"
android:padding="15dp"
tools:ignore="HardcodedText">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center|start"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:gravity="center|start">
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/adp_app_icon"
android:layout_width="15dp"
android:layout_height="15dp"
android:layout_marginEnd="8dp"
android:src="@mipmap/about"
android:tint="@color/colorTextGray" />
<TextView
android:id="@+id/adp_app_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:text="APP 名称"
android:textColor="@color/colorTextGray"
android:textSize="14sp" />
</LinearLayout>
<TextView
android:id="@+id/adp_app_pkg_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:alpha="0.75"
android:singleLine="true"
android:text="com.xxx.xxx"
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
<TextView
android:id="@+id/adp_cbr_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:text="贡献者noname"
android:textColor="@color/colorTextDark"
android:textSize="13sp" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.fankes.miui.notify.view.MaterialSwitch
android:id="@+id/adp_app_open_switch"
android:layout_width="wrap_content"
android:layout_height="30dp"
android:layout_marginBottom="5dp"
android:text="启用替换 "
android:textColor="@color/colorTextGray"
android:textSize="13sp" />
<com.fankes.miui.notify.view.MaterialSwitch
android:id="@+id/adp_app_all_switch"
android:layout_width="wrap_content"
android:layout_height="30dp"
android:text="完全替换 "
android:textColor="@color/colorTextGray"
android:textSize="13sp" />
</LinearLayout>
</LinearLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorThemeBackground">#FF2D2D2D</color>
<color name="colorTextDark">#FFCFCFCF</color>
<color name="colorTextGray">#FFD3D3D3</color>
</resources>

View File

@@ -1,6 +1,6 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.MIUINativeNotifyIcon" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<style name="Theme.MIUINativeNotifyIcon" parent="Theme.Material3.DayNight">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_200</item>
<item name="colorPrimaryVariant">@color/purple_700</item>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorThemeBackground">#FFFFFFFF</color>
<color name="colorTextDark">#FF777777</color>
<color name="colorTextGray">#FF323B42</color>
</resources>

View File

@@ -7,4 +7,5 @@
<color name="teal_700">#656565</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<color name="trans">#00000000</color>
</resources>

View File

@@ -1,6 +1,6 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.MIUINativeNotifyIcon" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<style name="Theme.MIUINativeNotifyIcon" parent="Theme.Material3.DayNight">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>

BIN
images/miui.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

BIN
images/miui_n_1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

BIN
images/miui_n_2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

BIN
images/native.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

BIN
images/native_n_1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

BIN
images/native_n_2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB