Compare commits
261 Commits
Author | SHA1 | Date | |
---|---|---|---|
2e5284ebe9 | |||
abffc4d853 | |||
5d81b8ff87 | |||
d91d2736e6 | |||
72169989f2 | |||
c85da002f5 | |||
c09a1b5760 | |||
c30e56c5aa | |||
822e988c16 | |||
fc728a75a4 | |||
256e2ebfce | |||
be4b952f62 | |||
c7263c6d94 | |||
4733578912 | |||
87879301f0 | |||
c9be72e5f7 | |||
0b6f55c49a | |||
226d9395b6 | |||
9877bf902f | |||
0e43a7ce8c | |||
d256c8024d | |||
686671d2b8 | |||
b2031f95a4 | |||
d943aa6184 | |||
21aa563a5f | |||
009982c26f | |||
47461809dc | |||
e7dae611ba | |||
da1f390d39 | |||
48ec0f9a72 | |||
9393a87c63 | |||
2fde4ae833 | |||
bee5b21097 | |||
bdda054d3a | |||
66d578f172 | |||
c8e3e67ce0 | |||
378edf92eb | |||
7d4db23346 | |||
8f40f4b30c | |||
442e57fd0a | |||
6e3c627ad2 | |||
299e93b25c | |||
b8894e3bc0 | |||
85a49122d0 | |||
dba85cca89 | |||
6b10523fb0 | |||
048d7e4284 | |||
bc2dd8a973 | |||
646f30d05a | |||
361b07a909 | |||
8e3b575d38 | |||
dff2c4d0c8 | |||
6700ad96ad | |||
cb6fdefee0 | |||
3631d5e8c3 | |||
e5af34d6db | |||
abd7546dfe | |||
12ce701334 | |||
16e3780c97 | |||
ca27c17c46 | |||
cf80becf4e | |||
a3689b4aaa | |||
cd628e9329 | |||
a36b1a8ba2 | |||
5db1671a97 | |||
af3dace9d9 | |||
7616bf9370 | |||
b124355601 | |||
09a8f5644f | |||
387bdd197b | |||
3c8d358c63 | |||
8c9dcc1706 | |||
b9a9979ef8 | |||
8809573353 | |||
0b7cb8f567 | |||
1b49271fd2 | |||
9492ae6022 | |||
e509f0e6db | |||
b610eca3b2 | |||
3aff10fed5 | |||
f29a0a9c64 | |||
44dfb5abfe | |||
e80b95004a | |||
9b90004bff | |||
84bbaa5d8d | |||
2d98fd0e1a | |||
0f2da2077e | |||
b8a843906a | |||
2a76d8e3f0 | |||
f0f3a37402 | |||
3e50ca6db7 | |||
c27f124b25 | |||
|
09be1ea2c2 | ||
f5f90d712a | |||
7a1f139adc | |||
3ed382165b | |||
5173051e66 | |||
c30ee53796 | |||
ae2fcda709 | |||
1a077259d1 | |||
6e95239d94 | |||
c1b08c93d0 | |||
90dda0aa52 | |||
4699eb137e | |||
ef47eef989 | |||
7a5df6457f | |||
3d977998c1 | |||
014e073af6 | |||
0be6b9c910 | |||
3816aab335 | |||
3b77a1cd82 | |||
5c5fae4ef6 | |||
ea665fdc30 | |||
740a250a59 | |||
f433da040c | |||
00bf1acdb8 | |||
099886b0b2 | |||
4109a25b5d | |||
db93f8d48e | |||
e6cff940a7 | |||
3f7ea97812 | |||
8f8810e92a | |||
e65624c044 | |||
eabac2bd2d | |||
bde952c72c | |||
|
3e362591b6 | ||
|
ea29c089f6 | ||
cff1eb1958 | |||
83c98b2ad3 | |||
0d7f323232 | |||
0d63b0a14d | |||
6684d7f376 | |||
89321af1ce | |||
d7a9f1e413 | |||
edf199d9a6 | |||
8d6a05e02c | |||
c7d9b2661b | |||
d0a32e08d9 | |||
b0f9e44f8a | |||
1e749d2f64 | |||
c886bbd6cf | |||
ec45839029 | |||
6fd2294529 | |||
|
5913da8183 | ||
|
fcf2889668 | ||
|
6d784f1283 | ||
cd8ceec765 | |||
5325ac37d6 | |||
07fa6965ad | |||
4c88a5fbc6 | |||
da61a52c13 | |||
3314f9fb57 | |||
ebb1bec36f | |||
|
d5d2e2107c | ||
|
c39d03f8c9 | ||
|
e20dfab5b1 | ||
|
ffc9be3721 | ||
|
126aedabfd | ||
56661b03e6 | |||
|
c45658be68 | ||
e0443ff97c | |||
9af735e252 | |||
c67fe2fa31 | |||
b03cf30e0a | |||
09191802ad | |||
64f252986b | |||
c073d350d0 | |||
cbeaaa8733 | |||
3b5e066e2d | |||
79843eb0d0 | |||
7a4e254230 | |||
0534ab9218 | |||
5cee229a99 | |||
b6920e3ca1 | |||
|
a4f7c95f84 | ||
38803846cd | |||
fb44c4e945 | |||
a2fc95d765 | |||
0e3ef5418c | |||
4e5e2cee09 | |||
7b4b728523 | |||
9b6540df65 | |||
3e8982aad0 | |||
085f2498c8 | |||
a1e01d1d33 | |||
03aa550487 | |||
ea632b8892 | |||
|
69847a0b0b | ||
|
4cdbfa944d | ||
|
9edb04cf08 | ||
|
071c98e8f3 | ||
|
a317cc07f5 | ||
ef0392a168 | |||
32e9ee3c8b | |||
296f12d07a | |||
df99256231 | |||
60128bcb1a | |||
54aec1051f | |||
121170ba65 | |||
a2d282c3f1 | |||
4d0098f1b8 | |||
49f6bc921c | |||
f94286351b | |||
faad964359 | |||
78308ac558 | |||
03fd389e13 | |||
fb067577af | |||
da5d4eba1b | |||
|
aa22ee05c6 | ||
08873b3e1f | |||
7bfd2046ca | |||
f57e658900 | |||
|
b7ec4559cf | ||
c707f8a3f7 | |||
|
350823f4ec | ||
|
26c6241d38 | ||
|
6e0c42638f | ||
|
8c6d7d7258 | ||
8b9ecc1d87 | |||
df1df6aabf | |||
e618efe29e | |||
9468c0b696 | |||
9bf843eef4 | |||
a0f40012c6 | |||
b82e6d8bff | |||
d117a9a6e9 | |||
850a382025 | |||
5623f5f261 | |||
c706ee377a | |||
547d90c01f | |||
f0391b1875 | |||
7faa4ede7d | |||
c865b39c97 | |||
b8b23c3398 | |||
bdd53eba88 | |||
83a15171e2 | |||
|
12485db355 | ||
1d0b97e8a3 | |||
18ce5f66c5 | |||
8725dabe85 | |||
44e68ceca1 | |||
5497ac7912 | |||
60115b9ecf | |||
b43975e4e8 | |||
d346b9c0d2 | |||
8f8c260069 | |||
3461a28881 | |||
b1b99ccdfe | |||
3aa7ee2a6a | |||
1829a44eb3 | |||
b5219a00cc | |||
da81e12a60 | |||
57a14fdaf1 | |||
be18502fd8 | |||
4914ae20b2 | |||
3b338214fc | |||
3a484e4a63 | |||
199ad9fc66 | |||
51e3eb8784 | |||
e05d65e7e5 | |||
2fb557afd8 |
29
.github/ISSUE_TEMPLATE/----------.md
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
---
|
||||
name: 通知图标优化适配反馈
|
||||
about: 提交通知图标优化适配必须使用此模板提交
|
||||
title: "[通知图标优化适配反馈]"
|
||||
labels: To be adapted
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**需要适配的 APP 名称/包名/通知图标颜色 (必填)**
|
||||
|
||||
* (示例:小米音乐/com.miui.player/#fff16033)
|
||||
|
||||
*
|
||||
|
||||
**提供相关 APP 的下载渠道截图以及简要说明用途 (必填)**
|
||||
|
||||
*
|
||||
|
||||
**提供相关 APP 的通知单色图标适配素材 大小 50x50 (选填)**
|
||||
|
||||
* (可填写资源下载地址或直接添加附件提交,不接受百度网盘、天翼云盘以及各种快传、私有云盘)
|
||||
|
||||
* (若直接在附件提交这里可不填)
|
||||
|
||||
<!--- 提交时请将括号内容包括括号全部删除,填入你自己的内容 --->
|
||||
<!--- 请保留模板原始标题 --->
|
||||
<!--- 不按规定提交的 issues 将直接被关闭 --->
|
||||
<!--- Create by Template --->
|
54
.github/ISSUE_TEMPLATE/----bug---.md
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
---
|
||||
name: 问题与 BUG 反馈
|
||||
about: 问题反馈必须使用此模板进行提交
|
||||
title: "[问题与 BUG 反馈] *简要描述问题原因*"
|
||||
labels: bug
|
||||
assignees: fankes
|
||||
|
||||
---
|
||||
|
||||
**MIUI 版本(必填)**
|
||||
|
||||
*
|
||||
|
||||
**MIUI 版本类型(请保留一个)**
|
||||
|
||||
* 公测版/内测版/稳定版
|
||||
|
||||
**Android 版本(必填)**
|
||||
|
||||
*
|
||||
|
||||
**模块版本(必填)**
|
||||
|
||||
*
|
||||
|
||||
**使用的 Xposed 框架名称与框架版本(必填)**
|
||||
|
||||
* (例如:LSPosed Zygisk/Riru 版本号)
|
||||
|
||||
**同时使用的带有系统界面作用域的 Xposed 模块(选填)**
|
||||
|
||||
* (没有可空)
|
||||
|
||||
**问题的具体描述**
|
||||
|
||||
* (复现步骤、前提以及详细截图和录屏演示)
|
||||
|
||||
|
||||
**提供模块问题 Log 或必要 Log**
|
||||
|
||||
* (LSPosed 可在日志管理中查看并筛选包含 `MIUINativeNotifyIcon` 的日志)
|
||||
|
||||
<details><summary>展开查看</summary><pre><code>
|
||||
|
||||
(此处粘贴问题Log)
|
||||
|
||||
</code></pre></details>
|
||||
|
||||
<!--- 注意:只接受 MIUI 正规官方版本系统,如果你正在使用 MIUI 官改(第三方改版)请不要提交任何 BUG 与问题,开发者无义务解决 --->
|
||||
|
||||
<!--- 提交时请将括号内容包括括号全部删除,填入你自己的内容 --->
|
||||
<!--- 请保留模板原始标题 --->
|
||||
<!--- 不按规定提交的 issues 将直接被关闭 --->
|
||||
<!--- Create by Template --->
|
2
.idea/gradle.xml
generated
@@ -7,13 +7,13 @@
|
||||
<option name="testRunner" value="GRADLE" />
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="gradleJvm" value="11" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/app" />
|
||||
</set>
|
||||
</option>
|
||||
<option name="resolveModulePerSourceSet" value="false" />
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
|
25
.idea/misc.xml
generated
@@ -6,16 +6,35 @@
|
||||
<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/bg_dark_round.xml" value="0.2325" />
|
||||
<entry key="app/src/main/res/drawable/bg_dialog_background.xml" value="0.2325" />
|
||||
<entry key="app/src/main/res/drawable/bg_green_round.xml" value="0.255" />
|
||||
<entry key="app/src/main/res/drawable/bg_orange_round.xml" value="0.2325" />
|
||||
<entry key="app/src/main/res/drawable/bg_warn_round.xml" value="0.2325" />
|
||||
<entry key="app/src/main/res/drawable/bg_yellow_round.xml" value="0.255" />
|
||||
<entry key="app/src/main/res/drawable/ic_nf_icon_refresh.xml" value="0.2325" />
|
||||
<entry key="app/src/main/res/drawable/ic_nf_icon_update.xml" value="0.2325" />
|
||||
<entry key="app/src/main/res/drawable/ic_notify_icon.xml" value="0.2325" />
|
||||
<entry key="app/src/main/res/drawable/ic_system_clock.xml" value="0.2325" />
|
||||
<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-w1240dp/dia_source_from.xml" value="0.36484375" />
|
||||
<entry key="app/src/main/res/layout-w1240dp/dia_source_from_string.xml" value="0.36484375" />
|
||||
<entry key="app/src/main/res/layout-w936dp/dia_status_icon_cout.xml" value="0.935546875" />
|
||||
<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/layout/activity_login.xml" value="0.4375" />
|
||||
<entry key="app/src/main/res/layout/activity_main.xml" value="0.32507739938080493" />
|
||||
<entry key="app/src/main/res/layout/adapter_config.xml" value="0.375" />
|
||||
<entry key="app/src/main/res/layout/dia_icon_filter.xml" value="0.4307692307692308" />
|
||||
<entry key="app/src/main/res/layout/dia_icon_search.xml" value="0.4307692307692308" />
|
||||
<entry key="app/src/main/res/layout/dia_source_from.xml" value="0.3591278324070115" />
|
||||
<entry key="app/src/main/res/layout/dia_source_from_string.xml" value="0.4307692307692308" />
|
||||
<entry key="app/src/main/res/layout/dia_status_icon_count.xml" value="0.45" />
|
||||
<entry key="app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml" value="0.44871794871794873" />
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="Android Studio default JDK" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
|
@@ -1,42 +0,0 @@
|
||||
# 开始贡献
|
||||
|
||||
欢迎为通知图标优化名单贡献宝贵资源!<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.以上
|
123
README.md
@@ -1,94 +1,115 @@
|
||||
# MIUI 原生通知图标
|
||||
|
||||

|
||||

|
||||

|
||||
[](https://github.com/fankes/MIUINativeNotifyIcon)
|
||||
[](https://github.com/fankes/MIUINativeNotifyIcon/blob/master/LICENSE)
|
||||
[](https://github.com/fankes/MIUINativeNotifyIcon/releases)
|
||||
[](https://github.com/fankes/MIUINativeNotifyIcon/releases)
|
||||
[](https://github.com/Xposed-Modules-Repo/com.fankes.miui.notify/releases)
|
||||
[](https://t.me/XiaofangInternet)
|
||||
<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、12.5、13 以及最新版本。
|
||||
|
||||
# 开始使用
|
||||
# Developer
|
||||
|
||||
点击下载最新版本
|
||||
<a href='https://github.com/fankes/MIUINativeNotifyIcon/releases'></a>
|
||||
<br/><br/>
|
||||
⚠️ 适配说明<br/>
|
||||
[酷安 @星夜不荟](http://www.coolapk.com/u/876977)
|
||||
|
||||
- 此模块仅支持 Lsposed(作用域“系统界面”)、EdXposed(不推荐)、不支持太极无极(阴)
|
||||
- 目前最低支持基于 Android 9 版本的 MIUI12 或 MIUI12.5(建议)
|
||||
- 使用 Zygisk 方式运行的 Lsposed 可能会发生 Hook 不生效的问题,若出现问题请使用 Ramdisk 版本的 Lsposed
|
||||
# 适配说明
|
||||
|
||||
# 禁止任何商业用途
|
||||
- 此模块仅支持 <b>LSPosed</b>(作用域“系统界面”)、<b>~~EdXposed(随时停止支持)~~</b>、不支持<b>太极、无极</b>
|
||||
- 请确保你使用的是 MIUI 官方版本,任何第三方官改包发生的问题,开发者没有义务去解决和修复,请自求多福
|
||||
- 目前最低支持基于 Android 9 版本的 MIUI 12 或 MIUI 12.5(最低建议)
|
||||
- 建议最低从 MIUI 12.5 `2021-5-18` 开发版以后开始使用模块,之前的版本可能或多或少存在 MIUI 自身 BUG 不生效、黑白块的问题
|
||||
- 请始终保持最新版本的 LSPosed,旧版本可能会出现 Hook 不生效的问题,若最新版本依然不生效请在作用域中长按“系统界面”(“系统 UI”)选择重新优化
|
||||
|
||||
本模块完全开源免费,如果好用你可以打赏支持开发,严禁未经许可进行二改贩卖,违者必惩必究。
|
||||
# 请勿用于非法用途
|
||||
|
||||
# 开始贡献
|
||||
- 本模块完全开源免费,如果好用你可以打赏支持开发,但是请不要用于非法用途。
|
||||
- 本模块发布地址仅有 [Xposed-Modules-Repo](https://github.com/Xposed-Modules-Repo/com.fankes.miui.notify/releases)、
|
||||
[Release](https://github.com/fankes/MIUINativeNotifyIcon/releases)
|
||||
及 [蓝奏云](https://fankes.lanzouy.com/b030o2e8h),从其他非正规渠道下载到的版本或对您造成任何影响均与我们无关。
|
||||
|
||||
由于国内厂商 APP 的不规范彩色图标影响整体图标的美观,现在开放第三方 APP 的通知图标适配。<br/>
|
||||
欢迎为通知图标优化名单贡献宝贵资源!<br/>
|
||||
# 贡献通知图标优化名单
|
||||
|
||||
- [CONTRIBUTING](https://github.com/fankes/MIUINativeNotifyIcon/blob/master/CONTRIBUTING.md)
|
||||
此项目是 `AndroidNotifyIconAdapt` 项目的一部分,详情请参考下方。<br/>
|
||||
|
||||
- [Android 通知图标规范适配计划](https://github.com/fankes/AndroidNotifyIconAdapt)
|
||||
|
||||
# 历史背景
|
||||
|
||||
这个模块诞生来源于 MIUI 的乱改和不规范,本来 MIUI 9 之后,官方给出了原生通知图标样式,后面由于用户反应通知栏经常出现黑白块。 这当然不是系统的错,而是国内 APP 极其不规范的通知图标设计,于是 MIUI
|
||||
选择直接忽略这个问题把全部图标都改成了 APP 的彩色图标, 使得之前拥有自有样式的原生图标也被破坏,通知中“setSmallIcon”不再有效,这个模块就是为了修复被 MIUI 开发组忽略的图标问题, 并完美地给 MIUI 修复了黑白块图标的问题。
|
||||
这个模块诞生来源于 MIUI 的乱改和不规范,本来 MIUI 9 之后,官方给出了原生通知图标样式,后面由于用户反应通知栏经常出现黑白块。<br/><br/>
|
||||
这当然不是系统的错,而是国内 APP 和 `MIPUSH` 的通知极其不规范的通知图标设计。<br/><br/>
|
||||
但是呢,接到反馈后 MIUI 开发组选择直接忽略这个问题,在 `2021-5-18` 的开发版开始,把全部通知图标都改成了 APP 的彩色图标,使得之前拥有自有样式的原生图标也被破坏。<br/><br/>
|
||||
对于 Android 开发者来说,官方文档中的 `setSmallIcon` 不再适用于魔改后的 MIUI,这将会严重破坏非常多的状态图标。<br/><br/>
|
||||
当然,国内的手机生态除了 `MIPUSH` 的营销通知就是社交软件的通知,可能大部分人都不会在意这件事情。<br/><br/>
|
||||
但是,这个模块就是为了修复被 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
|
||||
选择放弃原生通知功能,而做出这种违反原生通知规则的做法,而这些彩色图标被设置为单色调图标,也确实会发生黑白块的问题,但是同时又会破坏遵守规范的图标。
|
||||
- 真的没有办法了吗?在不断探索下,我找到了原生支持色彩判断的类
|
||||
原生 Android 的小图标和通知图标具有状态性。<br/><br/>
|
||||
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/images/native.jpg" height = "35"/><br/><br/>
|
||||
而 MIUI 最近的版本直接破坏了这一状态性,全部设置为 APP 的图标,不仅难看而且你无法下拉通知栏区别这些图标代表什么。<br/><br/>
|
||||
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/images/miui.jpg" height = "40"/><br/><br/>
|
||||
同样地,通知面板的图标同样遵守这一状态性。<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/><br/>
|
||||
而 MIUI 做了什么呢?<br/><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/><br/>
|
||||
不曾记得是什么版本开始,MIUI 把通知图标改成了这个鬼样子,寻找开发组提案也是无人问津,最后转念一想,自己干吧。<br/><br/>
|
||||
由于目前大量通知图标都来自 `MIPUSH` 发出的营销通知,而 `MIPUSH` 的图标都是统一的彩色应用图标,很多应用也没有适配这一特性, 在通知栏广告满天飞的情况下,MIUI
|
||||
选择放弃原生通知功能,而做出这种违反原生通知规则的做法,而这些彩色图标被设置为单色调图标,也确实会发生黑白块的问题,但是同时又会破坏遵守规范的图标。<br/><br/>
|
||||
真的没有办法了吗?在不断探索下,我找到了原生支持色彩判断的类。
|
||||
|
||||
```
|
||||
```kotlin
|
||||
com.android.internal.util.ContrastColorUtil
|
||||
```
|
||||
|
||||
- 这个类中有一个方法可以拿出来判断图标的灰度效果
|
||||
这个类中有一个方法可以拿出来判断图标的灰度效果。
|
||||
|
||||
```
|
||||
ContrastColorUtil.getInstance().isGrayscaleIcon(drawable);
|
||||
```kotlin
|
||||
ContrastColorUtil.getInstance().isGrayscaleIcon(drawable)
|
||||
```
|
||||
|
||||
- 问题就被解决了,顺便修了一下被 MIUI 破坏的通知图标以及优化了一下应用本身方块图标的圆角...
|
||||
- 最后,我想大声问一句 MIUI 开发组:“就这?” 就这么简单的问题为什么拖了这么长时间也没有结论,还要交给用户去修复,这真的是一种负责任的表现吗?
|
||||
- 后来一想,也是啊,被国内生态毒害的用户,怎么可能会去想到这些问题呢,最后只能是我自作多情,还对 MIUI 留有一点情怀吧。
|
||||
- ——来自一个无可奈何的 MIUI 老用户
|
||||
问题就被解决了,顺便修了一下被 MIUI 破坏的通知图标以及优化了一下应用本身方块图标的圆角......<br/><br/>
|
||||
最后,我想大声问一句 MIUI 开发组:“就这?” 就这么简单的问题为什么拖了这么长时间也没有结论,还要交给用户去修复,这真的是一种负责任的表现吗?<br/><br/>
|
||||
后来一想,也是啊,被国内生态毒害的用户,怎么可能会去想到这些问题呢,最后只能是我自作多情,还对 MIUI 留有一点情怀吧。<br/><br/>
|
||||
——来自一个无可奈何的 MIUI 老用户
|
||||
|
||||
# 后记
|
||||
|
||||
- 近期重新适配了 MIUI 12、12.5、13 版本,每个版本的图标设置方法都不一样,而且改的乱七八糟的,我都要无语了,只能用了很多折中方案,毕竟我也没有那么大精力每个版本去修复,实在是累了
|
||||
- 特地的把自己能有的小米手机刷成各种 MIUI 版本去为酷友做专项适配,我也是很累了,也希望你们能够多多支持,也能让 MIUI 做得更好
|
||||
- MIUI 再不重写,怕是永远会变成安卓之光。雷军,金凡!!
|
||||
近期重新适配了 MIUI 12、12.5、13 版本,每个版本的图标设置方法都不一样,而且改的乱七八糟的,我都要无语了,只能用了很多折中方案,毕竟我也没有那么大精力每个版本去修复,实在是累了。<br/><br/>
|
||||
特地的把自己能有的小米手机刷成各种 MIUI 版本去为酷友做专项适配,我也是很累了,也希望你们能够多多支持,也能让 MIUI 做得更好。<br/><br/>
|
||||
MIUI 再不重写,怕是永远会变成安卓之光。雷军,金凡!!
|
||||
|
||||
# 捐赠支持
|
||||
|
||||
- 工作不易,无意外情况此项目将继续维护下去,提供更多可能,欢迎打赏。<br/><br/>
|
||||
<img src="https://github.com/fankes/YuKiHookAPI/blob/master/img-src/wechat_code.jpg" width = "200" height = "200"/>
|
||||
|
||||
# 许可证
|
||||
|
||||
- [GPL-3.0](https://www.gnu.org/licenses/gpl-3.0.html)
|
||||
- [AGPL-3.0](https://www.gnu.org/licenses/agpl-3.0.html)
|
||||
|
||||
```
|
||||
Copyright (C) 2020-2022 Fankes Studio(qzmmcn@163.com)
|
||||
Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
|
||||
This program 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.
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program 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.
|
||||
```
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
```
|
||||
|
||||
Powered by [YukiHookAPI](https://github.com/fankes/YukiHookAPI)<br/><br/>
|
||||
版权所有 © 2019-2022 Fankes Studio(qzmmcn@163.com)
|
@@ -1,6 +1,7 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'com.google.devtools.ksp' version '1.6.10-1.0.4'
|
||||
}
|
||||
|
||||
android {
|
||||
@@ -19,10 +20,18 @@ android {
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.fankes.miui.notify"
|
||||
minSdk 26
|
||||
targetSdk 26
|
||||
versionCode 6
|
||||
versionName "1.3"
|
||||
minSdk 28
|
||||
targetSdk 31
|
||||
versionCode rootProject.ext.appVersionCode
|
||||
versionName rootProject.ext.appVersionName
|
||||
|
||||
kotlinOptions {
|
||||
freeCompilerArgs = [
|
||||
'-Xno-param-assertions',
|
||||
'-Xno-call-assertions',
|
||||
'-Xno-receiver-assertions'
|
||||
]
|
||||
}
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
@@ -35,28 +44,46 @@ android {
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
sourceCompatibility JavaVersion.VERSION_11
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
jvmTarget = '11'
|
||||
}
|
||||
buildFeatures {
|
||||
viewBinding true
|
||||
}
|
||||
}
|
||||
|
||||
/** 移除无效耗时 lint Task */
|
||||
tasks.whenTaskAdded {
|
||||
task -> if (task.name == "lintVitalRelease") task.enabled = false
|
||||
}
|
||||
|
||||
/** 移除无效耗时 lint Task */
|
||||
tasks.whenTaskAdded {
|
||||
task -> if (task.name == "lintVitalAnalyzeRelease") task.enabled = false
|
||||
}
|
||||
|
||||
/** 移除无效耗时 lint Task */
|
||||
tasks.whenTaskAdded {
|
||||
task -> if (task.name == "lintVitalReportRelease") task.enabled = false
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly 'de.robv.android.xposed:api:82'
|
||||
// 基础依赖包
|
||||
implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
|
||||
// Fragment 快速实现
|
||||
implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0'
|
||||
// Kotlin 扩展
|
||||
implementation 'com.gyf.immersionbar:immersionbar-ktx:3.0.0'
|
||||
implementation 'com.highcapable.yukihookapi:api:1.0.70'
|
||||
ksp 'com.highcapable.yukihookapi:ksp-xposed:1.0.70'
|
||||
implementation "com.github.topjohnwu.libsu:core:3.1.2"
|
||||
implementation 'androidx.annotation:annotation:1.3.0'
|
||||
implementation 'com.geyifeng.immersionbar:immersionbar:3.2.0'
|
||||
implementation 'com.geyifeng.immersionbar:immersionbar-ktx:3.2.0'
|
||||
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
|
||||
implementation 'androidx.core:core-ktx:1.7.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.4.1'
|
||||
implementation 'com.google.android.material:material:1.5.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
|
||||
//noinspection GradleDynamicVersion
|
||||
testImplementation 'junit:junit:4.+'
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
||||
}
|
18
app/proguard-rules.pro
vendored
@@ -27,22 +27,26 @@
|
||||
-dontoptimize
|
||||
-verbose
|
||||
-overloadaggressively
|
||||
-repackageclasses o
|
||||
-allowaccessmodification
|
||||
-adaptclassstrings
|
||||
-adaptresourcefilenames
|
||||
-adaptresourcefilecontents
|
||||
|
||||
#-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*
|
||||
-renamesourcefileattribute H
|
||||
-renamesourcefileattribute P
|
||||
-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
-keep class android.support**
|
||||
-keep class androidx**
|
||||
|
||||
-keep public class * extends android.app.Activity
|
||||
-keep public class * extends android.app.Application
|
||||
-keep public class * extends android.app.Service
|
||||
-keep public class * extends android.content.ContentProvider
|
||||
-keep public class * extends android.app.backup.BackupAgentHelper
|
||||
-keep public class * extends android.preference.Preference
|
||||
-keep public class * extends android.preference.Preference
|
||||
|
||||
-assumenosideeffects class kotlin.jvm.internal.Intrinsics {
|
||||
public static *** throwUninitializedProperty(...);
|
||||
public static *** throwUninitializedPropertyAccessException(...);
|
||||
}
|
||||
|
||||
-keepclassmembers class * implements androidx.viewbinding.ViewBinding {
|
||||
*** inflate(android.view.LayoutInflater);
|
||||
}
|
@@ -3,6 +3,9 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.fankes.miui.notify">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
|
||||
<application
|
||||
android:name=".application.MNNApplication"
|
||||
android:allowBackup="true"
|
||||
@@ -11,51 +14,70 @@
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.MIUINativeNotifyIcon"
|
||||
tools:ignore="AllowBackup">
|
||||
android:usesCleartextTraffic="true"
|
||||
tools:ignore="AllowBackup,ExportedService">
|
||||
|
||||
<!-- 是否是xposed模块 -->
|
||||
<meta-data
|
||||
android:name="xposedmodule"
|
||||
android:value="true" />
|
||||
|
||||
<!-- 模块描述 -->
|
||||
<meta-data
|
||||
android:name="xposeddescription"
|
||||
android:value="MIUI 状态栏原生图标,修复 12.5、13 后期被破坏的彩色图标。\n开发者:酷安 @星夜不荟" />
|
||||
|
||||
<!-- 最低xposed版本号 -->
|
||||
android:value="为金凡教我做事的 MIUI 修复 12.5、13 后期被破坏的彩色图标。\n开发者:酷安 @星夜不荟" />
|
||||
<meta-data
|
||||
android:name="xposedminversion"
|
||||
android:value="82" />
|
||||
android:value="93" />
|
||||
<meta-data
|
||||
android:name="xposedscope"
|
||||
android:resource="@array/module_scope" />
|
||||
|
||||
<activity
|
||||
android:name="com.fankes.miui.notify.ui.MainActivity"
|
||||
android:name=".ui.activity.MainActivity"
|
||||
android:exported="true"
|
||||
android:screenOrientation="behind">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="de.robv.android.xposed.category.MODULE_SETTINGS" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity-alias
|
||||
android:name="com.fankes.miui.notify.Home"
|
||||
android:name=".Home"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:screenOrientation="behind"
|
||||
android:targetActivity="com.fankes.miui.notify.ui.MainActivity">
|
||||
android:targetActivity=".ui.activity.MainActivity">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
<activity
|
||||
android:name="com.fankes.miui.notify.ui.ConfigureActivity"
|
||||
android:exported="false"
|
||||
android:name=".ui.activity.ConfigureActivity"
|
||||
android:exported="true"
|
||||
android:screenOrientation="behind" />
|
||||
|
||||
<activity
|
||||
android:name=".ui.activity.auto.NotifyIconRuleUpdateActivity"
|
||||
android:excludeFromRecents="true"
|
||||
android:exported="true"
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
|
||||
|
||||
<service
|
||||
android:name=".service.QuickStartTileService"
|
||||
android:exported="true"
|
||||
android:icon="@drawable/ic_notify_icon"
|
||||
android:label="@string/tile_name"
|
||||
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.service.quicksettings.action.QS_TILE" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
</application>
|
||||
</manifest>
|
@@ -1 +1 @@
|
||||
com.fankes.miui.notify.hook.HookMain
|
||||
com.fankes.miui.notify.hook.HookEntry_YukiHookXposedInit
|
1
app/src/main/assets/yukihookapi_init
Normal file
@@ -0,0 +1 @@
|
||||
com.fankes.miui.notify.hook.HookEntry
|
@@ -1,22 +1,24 @@
|
||||
/**
|
||||
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This file is part of MIUINativeNotifyIcon.
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* 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,
|
||||
* This software 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.
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/01/24.
|
||||
* This file is Created by fankes on 2022/1/24.
|
||||
*/
|
||||
@file:Suppress("unused")
|
||||
|
||||
@@ -34,15 +36,10 @@ class MNNApplication : Application() {
|
||||
|
||||
/** 调用全局静态实例 */
|
||||
val appContext get() = context ?: error("App is death")
|
||||
|
||||
/** 自身 APP 是否已启动 */
|
||||
var isMineStarted = false
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
/** 设置状态 */
|
||||
isMineStarted = true
|
||||
/** 设置静态实例 */
|
||||
context = this
|
||||
/** 跟随系统夜间模式 */
|
||||
|
@@ -1,34 +1,37 @@
|
||||
/**
|
||||
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This file is part of MIUINativeNotifyIcon.
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* 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,
|
||||
* This software 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.
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://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 com.fankes.miui.notify.utils.factory.base64
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* 通知栏小图标 bean
|
||||
* @param appName APP 名称 - 仅限默认语言区域
|
||||
* @param appName APP 名称
|
||||
* @param packageName 包名
|
||||
* @param iconBitmap 图标位图
|
||||
* @param iconColor 通知栏中显示的图标颜色 - 设置为 0 使用系统默认颜色
|
||||
* @param contributorName 贡献者昵称
|
||||
* @param isEnabled 是否默认启用替换彩色图标 - 关闭后将全部停止替换
|
||||
* @param isEnabledAll 是否默认启用替换全部图标
|
||||
@@ -37,10 +40,20 @@ data class IconDataBean(
|
||||
var appName: String,
|
||||
var packageName: String,
|
||||
var iconBitmap: Bitmap,
|
||||
var iconColor: Int = 0,
|
||||
var contributorName: String,
|
||||
var isEnabled: Boolean,
|
||||
var isEnabledAll: Boolean,
|
||||
) : Serializable {
|
||||
fun toEnabledName() = ("$appName$packageName").base64 + "_enable"
|
||||
fun toEnabledAllName() = ("$appName$packageName").base64 + "_enable_all"
|
||||
override fun toString() = "{\n" +
|
||||
" \"appName\": \"$appName\",\n" +
|
||||
" \"packageName\": \"$packageName\",\n" +
|
||||
" \"iconBitmap\": \"${iconBitmap.base64}\",\n" +
|
||||
" \"iconColor\": \"#${Integer.toHexString(iconColor)}\",\n" +
|
||||
" \"contributorName\": \"$contributorName\",\n" +
|
||||
" \"isEnabled\": $isEnabled,\n" +
|
||||
" \"isEnabledAll\": $isEnabledAll\n" +
|
||||
" }"
|
||||
}
|
60
app/src/main/java/com/fankes/miui/notify/const/Const.kt
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/3/24.
|
||||
*/
|
||||
@file:Suppress("MemberVisibilityCanBePrivate")
|
||||
|
||||
package com.fankes.miui.notify.const
|
||||
|
||||
import com.fankes.miui.notify.BuildConfig
|
||||
|
||||
/**
|
||||
* 存储一些静态编译后的值
|
||||
*/
|
||||
object Const {
|
||||
|
||||
/** 当前模块的包名 */
|
||||
const val MODULE_PACKAGE_NAME = BuildConfig.APPLICATION_ID
|
||||
|
||||
/** 当前模块的版本名称 */
|
||||
const val MODULE_VERSION_NAME = BuildConfig.VERSION_NAME
|
||||
|
||||
/** 当前模块的版本号 */
|
||||
const val MODULE_VERSION_CODE = BuildConfig.VERSION_CODE
|
||||
|
||||
/** 当前模块的版本校验 */
|
||||
const val MODULE_VERSION_VERIFY = "${MODULE_VERSION_NAME}_${MODULE_VERSION_CODE}_202204041350"
|
||||
|
||||
/** 当前模块的版本校验标签 */
|
||||
const val MODULE_VERSION_VERIFY_TAG = "module_version_verify"
|
||||
|
||||
/** 发送通讯广播号标签 - 模块激活状态 */
|
||||
const val ACTION_MODULE_CHECKING_RECEIVER = "mnn_module_checking_action"
|
||||
|
||||
/** 接收通讯广播号标签 - 模块激活状态 */
|
||||
const val ACTION_MODULE_HANDLER_RECEIVER = "mnn_module_handler_action"
|
||||
|
||||
/** 发送通讯广播号标签 - 通知系统界面刷新 */
|
||||
const val ACTION_REMIND_CHECKING_RECEIVER = "mnn_remind_checking_action"
|
||||
|
||||
/** 接收通讯广播号标签 - 通知系统界面刷新 */
|
||||
const val ACTION_REMIND_HANDLER_RECEIVER = "mnn_remind_handler_action"
|
||||
}
|
44
app/src/main/java/com/fankes/miui/notify/data/DataConst.kt
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/3/26.
|
||||
*/
|
||||
package com.fankes.miui.notify.data
|
||||
|
||||
import com.fankes.miui.notify.hook.HookConst
|
||||
import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
|
||||
|
||||
object DataConst {
|
||||
|
||||
val ENABLE_MODULE = PrefsData("_enable_module", true)
|
||||
val ENABLE_MODULE_LOG = PrefsData("_enable_module_log", false)
|
||||
val ENABLE_HIDE_ICON = PrefsData("_hide_icon", false)
|
||||
val ENABLE_COLOR_ICON_COMPAT = PrefsData("_color_icon_compat", false)
|
||||
val ENABLE_NOTIFY_ICON_FIX = PrefsData("_notify_icon_fix", true)
|
||||
val ENABLE_NOTIFY_ICON_FIX_NOTIFY = PrefsData("_notify_icon_fix_notify", true)
|
||||
val ENABLE_HOOK_STATUS_ICON_COUNT = PrefsData("_enable_hook_status_icon_count", true)
|
||||
val ENABLE_NOTIFY_ICON_FIX_AUTO = PrefsData("_enable_notify_icon_fix_auto", true)
|
||||
val NOTIFY_ICON_DATAS = PrefsData("_notify_icon_datas", "")
|
||||
val NOTIFY_ICON_FIX_AUTO_TIME = PrefsData("_notify_icon_fix_auto_time", "07:00")
|
||||
val HOOK_STATUS_ICON_COUNT = PrefsData("_hook_status_icon_count", 5)
|
||||
|
||||
val SOURCE_SYNC_WAY = PrefsData("_rule_source_sync_way", HookConst.TYPE_SOURCE_SYNC_WAY_1)
|
||||
val SOURCE_SYNC_WAY_CUSTOM_URL = PrefsData("_rule_source_sync_way_custom_url", "")
|
||||
}
|
34
app/src/main/java/com/fankes/miui/notify/hook/HookConst.kt
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/24.
|
||||
*/
|
||||
@file:Suppress("SetWorldReadable")
|
||||
|
||||
package com.fankes.miui.notify.hook
|
||||
|
||||
object HookConst {
|
||||
|
||||
const val TYPE_SOURCE_SYNC_WAY_1 = 1000
|
||||
const val TYPE_SOURCE_SYNC_WAY_2 = 2000
|
||||
const val TYPE_SOURCE_SYNC_WAY_3 = 3000
|
||||
|
||||
const val SYSTEMUI_PACKAGE_NAME = "com.android.systemui"
|
||||
}
|
60
app/src/main/java/com/fankes/miui/notify/hook/HookEntry.kt
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/2/15.
|
||||
*/
|
||||
package com.fankes.miui.notify.hook
|
||||
|
||||
import com.fankes.miui.notify.data.DataConst
|
||||
import com.fankes.miui.notify.hook.HookConst.SYSTEMUI_PACKAGE_NAME
|
||||
import com.fankes.miui.notify.hook.entity.SystemUIHooker
|
||||
import com.fankes.miui.notify.utils.factory.isLowerAndroidP
|
||||
import com.fankes.miui.notify.utils.factory.isNotMIUI
|
||||
import com.fankes.miui.notify.utils.factory.isNotSupportMiuiVersion
|
||||
import com.fankes.miui.notify.utils.factory.miuiVersion
|
||||
import com.highcapable.yukihookapi.annotation.xposed.InjectYukiHookWithXposed
|
||||
import com.highcapable.yukihookapi.hook.factory.configs
|
||||
import com.highcapable.yukihookapi.hook.factory.encase
|
||||
import com.highcapable.yukihookapi.hook.log.loggerW
|
||||
import com.highcapable.yukihookapi.hook.xposed.proxy.YukiHookXposedInitProxy
|
||||
|
||||
@InjectYukiHookWithXposed
|
||||
class HookEntry : YukiHookXposedInitProxy {
|
||||
|
||||
override fun onInit() = configs {
|
||||
debugTag = "MIUINativeNotifyIcon"
|
||||
isDebug = false
|
||||
}
|
||||
|
||||
override fun onHook() = encase {
|
||||
when {
|
||||
/** 不是 MIUI 系统停止 Hook */
|
||||
isNotMIUI -> loggerW(msg = "Aborted Hook -> This System is not MIUI")
|
||||
/** 系统版本低于 Android P 停止 Hook */
|
||||
isLowerAndroidP -> loggerW(msg = "Aborted Hook -> This System is lower than Android P")
|
||||
/** 不是支持的 MIUI 系统停止 Hook */
|
||||
isNotSupportMiuiVersion -> loggerW(msg = "Aborted Hook -> This MIUI Version $miuiVersion not supported")
|
||||
/** Hook 被手动关闭停止 Hook */
|
||||
prefs.get(DataConst.ENABLE_MODULE).not() -> loggerW(msg = "Aborted Hook -> Hook Closed")
|
||||
/** 开始 Hook */
|
||||
else -> loadApp(SYSTEMUI_PACKAGE_NAME, SystemUIHooker())
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,790 +0,0 @@
|
||||
/**
|
||||
* 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/24.
|
||||
*/
|
||||
@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.Drawable
|
||||
import android.graphics.drawable.Icon
|
||||
import android.service.notification.StatusBarNotification
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
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.SELF_PACKAGE_NAME
|
||||
import com.fankes.miui.notify.hook.HookMedium.SYSTEMUI_PACKAGE_NAME
|
||||
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
|
||||
|
||||
@Keep
|
||||
class HookMain : IXposedHookLoadPackage {
|
||||
|
||||
companion object {
|
||||
|
||||
/** 一直存在的类 */
|
||||
private const val SystemUIApplicationClass = "$SYSTEMUI_PACKAGE_NAME.SystemUIApplication"
|
||||
|
||||
/** MIUI 新版本存在的类 */
|
||||
private const val NotificationHeaderViewWrapperInjectorClass =
|
||||
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.row.wrapper.NotificationHeaderViewWrapperInjector"
|
||||
|
||||
/** 一直存在的类 */
|
||||
private const val NotificationHeaderViewWrapperClass =
|
||||
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.NotificationHeaderViewWrapper"
|
||||
|
||||
/** 一直存在的类 */
|
||||
private const val NotificationViewWrapperClass =
|
||||
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.NotificationViewWrapper"
|
||||
|
||||
/** 原生存在的类 */
|
||||
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 方法体 */
|
||||
private val replaceToNull = object : XC_MethodReplacement() {
|
||||
override fun replaceHookedMethod(param: MethodHookParam?): Any? {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/** 仅作用于替换的 Hook 方法体 */
|
||||
private val replaceToTrue = object : XC_MethodReplacement() {
|
||||
override fun replaceHookedMethod(param: MethodHookParam?): Any {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 忽略异常运行
|
||||
* @param error 错误信息
|
||||
* @param it 正常回调
|
||||
*/
|
||||
private fun runWithoutError(error: String = "", it: () -> Unit) {
|
||||
try {
|
||||
it()
|
||||
} catch (e: Throwable) {
|
||||
logE(content = "hookFailed: $error", e)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the log
|
||||
* @param content
|
||||
* @param it 继续执行的方法
|
||||
*/
|
||||
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)
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the log
|
||||
* @param content
|
||||
* @param it 继续执行的方法
|
||||
*/
|
||||
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 类名
|
||||
* @return [Class]
|
||||
*/
|
||||
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}")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* - 这个是修复彩色图标的关键核心代码判断
|
||||
*
|
||||
* 判断是否为灰度图标 - 反射执行系统方法
|
||||
* @param context 实例
|
||||
* @param icon 要判断的图标
|
||||
* @return [Boolean]
|
||||
*/
|
||||
private fun XC_LoadPackage.LoadPackageParam.isGrayscaleIcon(context: Context, icon: Drawable) =
|
||||
findClass(ContrastColorUtilClass).let {
|
||||
val instance = it.getDeclaredMethod("getInstance", Context::class.java)
|
||||
.apply { isAccessible = true }.invoke(null, context)
|
||||
it.getDeclaredMethod("isGrayscaleIcon", Drawable::class.java)
|
||||
.apply { isAccessible = true }.invoke(instance, icon) as Boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前通知栏的样式
|
||||
*
|
||||
* 判断是否为灰度图标 - 反射执行系统方法
|
||||
* @return [Boolean]
|
||||
*/
|
||||
private fun XC_LoadPackage.LoadPackageParam.isShowMiuiStyle() = try {
|
||||
findClass(NotificationUtilClass).let {
|
||||
it.getDeclaredMethod("showMiuiStyle")
|
||||
.apply { isAccessible = true }.invoke(null) as Boolean
|
||||
}
|
||||
} catch (_: Throwable) {
|
||||
false
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为新版本 MIUI 方案
|
||||
*
|
||||
* 拥有状态栏图标颜色检查功能
|
||||
* @return [Boolean]
|
||||
*/
|
||||
private fun XC_LoadPackage.LoadPackageParam.hasIgnoreStatusBarIconColor() =
|
||||
isMethodExist(NotificationUtilClass, name = "ignoreStatusBarIconColor")
|
||||
|
||||
/**
|
||||
* 获取 [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] or null
|
||||
*/
|
||||
private val XC_LoadPackage.LoadPackageParam.globalContext
|
||||
get() = try {
|
||||
findClass(SystemUIApplicationClass)
|
||||
.getDeclaredMethod("getContext").apply { isAccessible = true }
|
||||
.invoke(null) as? Context?
|
||||
} catch (_: Throwable) {
|
||||
null
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook 状态栏小图标
|
||||
*
|
||||
* 区分系统版本 - 由于每个系统版本的方法不一样这里单独拿出来进行 Hook
|
||||
* @param context 实例
|
||||
* @param expandedNf 通知实例
|
||||
* @param param Hook Param
|
||||
*/
|
||||
private fun XC_LoadPackage.LoadPackageParam.hookSmallIconOnSet(
|
||||
context: Context,
|
||||
expandedNf: StatusBarNotification?,
|
||||
param: XC_MethodHook.MethodHookParam
|
||||
) {
|
||||
runWithoutError(error = "GetSmallIconOnSet") {
|
||||
/** 获取通知小图标 */
|
||||
val iconDrawable = (param.result as Icon).loadDrawable(context)
|
||||
|
||||
/** 判断是否不是灰度图标 */
|
||||
val isNotGrayscaleIcon = !isGrayscaleIcon(context, iconDrawable)
|
||||
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
|
||||
expandedNf?.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(context))
|
||||
)
|
||||
}
|
||||
}
|
||||
} ?: logW(content = "GetSmallIconOnSet -> StatusBarNotification got null")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook 通知栏小图标
|
||||
*
|
||||
* 区分系统版本 - 由于每个系统版本的方法不一样这里单独拿出来进行 Hook
|
||||
* @param context 实例
|
||||
* @param expandedNf 通知实例
|
||||
* @param iconImageView 通知图标实例
|
||||
*/
|
||||
private fun XC_LoadPackage.LoadPackageParam.hookNotifyIconOnSet(
|
||||
context: Context,
|
||||
expandedNf: StatusBarNotification?,
|
||||
iconImageView: ImageView
|
||||
) {
|
||||
runWithoutError(error = "AutoSetAppIconOnSet") {
|
||||
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
|
||||
expandedNf?.let { notifyInstance ->
|
||||
/** 是否 Hook 彩色通知图标 */
|
||||
val isHookColorIcon = HookMedium.getBoolean(HookMedium.ENABLE_COLOR_ICON_HOOK, default = true)
|
||||
|
||||
/** 新版风格反色 */
|
||||
val newStyle = if (context.isSystemInDarkMode) 0xFF2D2D2D.toInt() else Color.WHITE
|
||||
|
||||
/** 旧版风格反色 */
|
||||
val oldStyle = if (context.isNotSystemInDarkMode) 0xFF707070.toInt() else Color.WHITE
|
||||
|
||||
/** 获取通知小图标 */
|
||||
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 context 实例
|
||||
* @param expandedNf 状态栏实例
|
||||
* @return [Boolean] 是否忽略通知图标颜色
|
||||
*/
|
||||
private fun XC_LoadPackage.LoadPackageParam.hookIgnoreStatusBarIconColor(
|
||||
context: Context,
|
||||
expandedNf: StatusBarNotification?
|
||||
) = if (HookMedium.getBoolean(HookMedium.ENABLE_COLOR_ICON_HOOK, default = true))
|
||||
try {
|
||||
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
|
||||
expandedNf?.let { notifyInstance ->
|
||||
/** 获取通知小图标 */
|
||||
val iconDrawable =
|
||||
notifyInstance.notification.smallIcon.loadDrawable(context)
|
||||
|
||||
/** 判断是否不是灰度图标 */
|
||||
val isNotGrayscaleIcon = !isGrayscaleIcon(context, 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 ->
|
||||
runWithoutError(error = "HookModuleSelf") {
|
||||
XposedHelpers.findAndHookMethod(
|
||||
"$SELF_PACKAGE_NAME.hook.HookMedium",
|
||||
lpparam.classLoader,
|
||||
"isHooked",
|
||||
replaceToTrue
|
||||
)
|
||||
}
|
||||
/** Hook 系统 UI */
|
||||
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),
|
||||
object : XC_MethodReplacement() {
|
||||
override fun replaceHookedMethod(param: MethodHookParam) =
|
||||
/**
|
||||
* 因为之前的 MIUI 版本的状态栏图标颜色会全部设置为白色的 - 找不到修复的地方就直接判断版本了
|
||||
* 对于之前没有通知图标色彩判断功能的版本判断是 MIUI 样式就停止 Hook
|
||||
*/
|
||||
if (lpparam.hasIgnoreStatusBarIconColor()) false else lpparam.isShowMiuiStyle()
|
||||
}
|
||||
)
|
||||
}
|
||||
/** 修复通知图标为彩色 */
|
||||
if (lpparam.hasIgnoreStatusBarIconColor())
|
||||
runWithoutError(error = "IgnoreStatusBarIconColor") {
|
||||
XposedHelpers.findAndHookMethod(
|
||||
lpparam.existClass(NotificationUtilClass),
|
||||
lpparam.classLoader,
|
||||
"ignoreStatusBarIconColor",
|
||||
lpparam.findClass(ExpandedNotificationClass),
|
||||
object : XC_MethodReplacement() {
|
||||
override fun replaceHookedMethod(param: MethodHookParam) =
|
||||
lpparam.hookIgnoreStatusBarIconColor(
|
||||
context = lpparam.globalContext ?: error("GlobalContext got null"),
|
||||
param.args?.get(0) as? StatusBarNotification?
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
/** 之前的版本解决方案 */
|
||||
else runWithoutError(error = "UpdateIconColor") {
|
||||
XposedHelpers.findAndHookMethod(
|
||||
StatusBarIconViewClass,
|
||||
lpparam.classLoader, "updateIconColor",
|
||||
object : XC_MethodHook() {
|
||||
override fun afterHookedMethod(param: MethodHookParam) =
|
||||
runWithoutError(error = "UpdateIconColorOnSet") hook@{
|
||||
/** 对于之前没有通知图标色彩判断功能的版本判断是 MIUI 样式就停止 Hook */
|
||||
if (lpparam.isShowMiuiStyle()) return@hook
|
||||
/** 获取自身 */
|
||||
val iconImageView = param.thisObject as ImageView
|
||||
|
||||
/** 是否忽略图标颜色 */
|
||||
val isIgnoredColor = lpparam.hookIgnoreStatusBarIconColor(
|
||||
iconImageView.context,
|
||||
param.thisObject.javaClass.getDeclaredField("mNotification").apply {
|
||||
isAccessible = true
|
||||
}[param.thisObject] as? StatusBarNotification?
|
||||
)
|
||||
|
||||
/** 当前着色颜色 */
|
||||
val currentColor =
|
||||
param.thisObject.javaClass.getDeclaredField("mCurrentSetColor").apply {
|
||||
isAccessible = true
|
||||
}[param.thisObject] as? Int ?: Color.WHITE
|
||||
/** 判断并设置颜色 */
|
||||
if (isIgnoredColor)
|
||||
iconImageView.colorFilter = null
|
||||
else iconImageView.setColorFilter(currentColor)
|
||||
logD(content = "IgnoreStatusBarIconColor[UseOldWay] -> isIgnored[$isIgnoredColor]")
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
/** 强制回写系统的状态栏图标样式为原生 */
|
||||
runWithoutError(error = "GetSmallIcon") {
|
||||
var isTooOld: Boolean
|
||||
try {
|
||||
isTooOld = false
|
||||
/** 新版方法 */
|
||||
lpparam.findClass(NotificationUtilClass)
|
||||
.getDeclaredMethod(
|
||||
"getSmallIcon",
|
||||
lpparam.findClass(ExpandedNotificationClass),
|
||||
Int::class.java
|
||||
).apply { isAccessible = true }
|
||||
} catch (_: Throwable) {
|
||||
try {
|
||||
isTooOld = false
|
||||
/** 旧版方法 */
|
||||
lpparam.findClass(NotificationUtilClass)
|
||||
.getDeclaredMethod("getSmallIcon", lpparam.findClass(ExpandedNotificationClass))
|
||||
.apply { isAccessible = true }
|
||||
} catch (_: Throwable) {
|
||||
isTooOld = true
|
||||
/** 超旧版方法 */
|
||||
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) {
|
||||
/** 对于之前没有通知图标色彩判断功能的版本判断是 MIUI 样式就停止 Hook */
|
||||
if (!lpparam.hasIgnoreStatusBarIconColor() && lpparam.isShowMiuiStyle()) return
|
||||
lpparam.hookSmallIconOnSet(
|
||||
context = lpparam.globalContext ?: param.args[0] as Context,
|
||||
param.args?.get(if (isTooOld) 1 else 0) as? StatusBarNotification?, 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? {
|
||||
if (isNewWay)
|
||||
lpparam.hookNotifyIconOnSet(
|
||||
context = param.args?.get(0) as? Context ?: lpparam.globalContext
|
||||
?: error("GlobalContext got null"),
|
||||
param.args?.get(2) as? StatusBarNotification?,
|
||||
param.args?.get(1) as ImageView
|
||||
)
|
||||
else
|
||||
lpparam.hookNotifyIconOnSet(
|
||||
context = lpparam.globalContext ?: error("GlobalContext got null"),
|
||||
param.args?.get(1) as? StatusBarNotification?,
|
||||
param.args?.get(0) as ImageView
|
||||
)
|
||||
return null
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
/** 之前的版本解决方案 */
|
||||
else runWithoutError(error = "AutoSetAppIconOldWay") {
|
||||
XposedHelpers.findAndHookMethod(
|
||||
NotificationHeaderViewWrapperClass,
|
||||
lpparam.classLoader, "handleHeaderViews",
|
||||
object : XC_MethodHook() {
|
||||
override fun afterHookedMethod(param: MethodHookParam) {
|
||||
runWithoutError(error = "AutoSetAppIconOldWayOnSet") hook@{
|
||||
/** 对于之前没有通知图标色彩判断功能的版本判断是 MIUI 样式就停止 Hook */
|
||||
if (!lpparam.hasIgnoreStatusBarIconColor() && lpparam.isShowMiuiStyle()) return@hook
|
||||
/** 从父类中得到 mRow 变量 */
|
||||
lpparam.findClass(NotificationViewWrapperClass).getDeclaredField("mRow")
|
||||
.apply {
|
||||
isAccessible = true
|
||||
}[param.thisObject].apply {
|
||||
/** 获取小图标 */
|
||||
val iconImageView = lpparam.findClass(NotificationHeaderViewWrapperClass)
|
||||
.getDeclaredField("mIcon")
|
||||
.apply {
|
||||
isAccessible = true
|
||||
}[param.thisObject] as ImageView
|
||||
|
||||
/** 获取其中的得到通知方法 */
|
||||
val expandedNf =
|
||||
javaClass.getDeclaredMethod("getStatusBarNotification").apply {
|
||||
isAccessible = true
|
||||
}.invoke(this) as? StatusBarNotification?
|
||||
/** 执行 Hook */
|
||||
lpparam.hookNotifyIconOnSet(
|
||||
iconImageView.context,
|
||||
expandedNf, iconImageView
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
/** 干掉下拉通知图标自动设置回 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!")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,139 +0,0 @@
|
||||
/**
|
||||
* 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/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_NOTIFY_ICON_HOOK = "_notify_icon_hook"
|
||||
|
||||
const val SELF_PACKAGE_NAME = "com.fankes.miui.notify"
|
||||
const val SYSTEMUI_PACKAGE_NAME = "com.android.systemui"
|
||||
|
||||
/**
|
||||
* 判断模块是否激活
|
||||
*
|
||||
* 在 [HookMain] 中 Hook 掉此方法
|
||||
* @return [Boolean] 激活状态
|
||||
*/
|
||||
fun isHooked(): Boolean {
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,957 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/3/25.
|
||||
*/
|
||||
package com.fankes.miui.notify.hook.entity
|
||||
|
||||
import android.app.NotificationManager
|
||||
import android.app.WallpaperManager
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
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.ArraySet
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewOutlineProvider
|
||||
import android.widget.ImageView
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import androidx.core.view.children
|
||||
import com.fankes.miui.notify.bean.IconDataBean
|
||||
import com.fankes.miui.notify.const.Const
|
||||
import com.fankes.miui.notify.data.DataConst
|
||||
import com.fankes.miui.notify.hook.HookConst.SYSTEMUI_PACKAGE_NAME
|
||||
import com.fankes.miui.notify.hook.factory.isAppNotifyHookAllOf
|
||||
import com.fankes.miui.notify.hook.factory.isAppNotifyHookOf
|
||||
import com.fankes.miui.notify.params.IconPackParams
|
||||
import com.fankes.miui.notify.utils.drawable.drawabletoolbox.DrawableBuilder
|
||||
import com.fankes.miui.notify.utils.factory.*
|
||||
import com.fankes.miui.notify.utils.tool.BitmapCompatTool
|
||||
import com.fankes.miui.notify.utils.tool.IconAdaptationTool
|
||||
import com.highcapable.yukihookapi.hook.bean.VariousClass
|
||||
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
|
||||
import com.highcapable.yukihookapi.hook.factory.field
|
||||
import com.highcapable.yukihookapi.hook.factory.hasField
|
||||
import com.highcapable.yukihookapi.hook.factory.hasMethod
|
||||
import com.highcapable.yukihookapi.hook.factory.method
|
||||
import com.highcapable.yukihookapi.hook.log.loggerD
|
||||
import com.highcapable.yukihookapi.hook.log.loggerW
|
||||
import com.highcapable.yukihookapi.hook.type.android.*
|
||||
import com.highcapable.yukihookapi.hook.type.java.BooleanType
|
||||
import com.highcapable.yukihookapi.hook.type.java.IntType
|
||||
|
||||
/**
|
||||
* 系统界面核心 Hook 类
|
||||
*/
|
||||
class SystemUIHooker : YukiBaseHooker() {
|
||||
|
||||
companion object {
|
||||
|
||||
/** MIUI 新版本存在的类 */
|
||||
private const val SystemUIApplicationClass = "$SYSTEMUI_PACKAGE_NAME.SystemUIApplication"
|
||||
|
||||
/** MIUI 新版本存在的类 */
|
||||
private const val NotificationHeaderViewWrapperInjectorClass =
|
||||
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.row.wrapper.NotificationHeaderViewWrapperInjector"
|
||||
|
||||
/** MIUI 新版本存在的类 */
|
||||
private const val MiuiNotificationViewWrapperClass =
|
||||
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.row.wrapper.MiuiNotificationViewWrapper"
|
||||
|
||||
/** MIUI 新版本存在的类 */
|
||||
private const val MiuiNotificationChildrenContainerClass =
|
||||
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.stack.MiuiNotificationChildrenContainer"
|
||||
|
||||
/** 原生存在的类 */
|
||||
private const val NotificationChildrenContainerClass =
|
||||
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.stack.NotificationChildrenContainer"
|
||||
|
||||
/** 原生存在的类 */
|
||||
private const val ContrastColorUtilClass = "com.android.internal.util.ContrastColorUtil"
|
||||
|
||||
/** 原生存在的类 */
|
||||
private const val StatusBarIconViewClass = "$SYSTEMUI_PACKAGE_NAME.statusbar.StatusBarIconView"
|
||||
|
||||
/** 原生存在的类 */
|
||||
private const val NotificationIconContainerClass = "$SYSTEMUI_PACKAGE_NAME.statusbar.phone.NotificationIconContainer"
|
||||
|
||||
/** 原生存在的类 */
|
||||
private const val PluginManagerImplClass = "$SYSTEMUI_PACKAGE_NAME.shared.plugins.PluginManagerImpl"
|
||||
|
||||
/** 根据多个版本存在不同的包名相同的类 */
|
||||
private val MiuiClockClass = VariousClass(
|
||||
"$SYSTEMUI_PACKAGE_NAME.statusbar.views.MiuiClock",
|
||||
"$SYSTEMUI_PACKAGE_NAME.statusbar.policy.MiuiClock"
|
||||
)
|
||||
|
||||
/** 根据多个版本存在不同的包名相同的类 */
|
||||
private val ExpandableNotificationRowClass = VariousClass(
|
||||
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.row.ExpandableNotificationRow",
|
||||
"$SYSTEMUI_PACKAGE_NAME.statusbar.ExpandableNotificationRow"
|
||||
)
|
||||
|
||||
/** 根据多个版本存在不同的包名相同的类 */
|
||||
private val NotificationViewWrapperClass = VariousClass(
|
||||
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.row.wrapper.NotificationViewWrapper",
|
||||
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.NotificationViewWrapper"
|
||||
)
|
||||
|
||||
/** 根据多个版本存在不同的包名相同的类 */
|
||||
private val NotificationHeaderViewWrapperClass = VariousClass(
|
||||
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.row.wrapper.NotificationHeaderViewWrapper",
|
||||
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.NotificationHeaderViewWrapper"
|
||||
)
|
||||
|
||||
/** 根据多个版本存在不同的包名相同的类 */
|
||||
private val NotificationUtilClass = VariousClass(
|
||||
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.NotificationUtil",
|
||||
"$SYSTEMUI_PACKAGE_NAME.miui.statusbar.notification.NotificationUtil"
|
||||
)
|
||||
|
||||
/** 根据多个版本存在不同的包名相同的类 */
|
||||
private val ExpandedNotificationClass = VariousClass(
|
||||
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.ExpandedNotification",
|
||||
"$SYSTEMUI_PACKAGE_NAME.miui.statusbar.ExpandedNotification"
|
||||
)
|
||||
}
|
||||
|
||||
/** 缓存的通知图标优化数组 */
|
||||
private var iconDatas = ArrayList<IconDataBean>()
|
||||
|
||||
/** 是否显示通知图标 - 跟随 Hook 保存 */
|
||||
private var isShowNotificationIcons = true
|
||||
|
||||
/** 是否已经使用过缓存刷新功能 */
|
||||
private var isUsingCachingMethod = false
|
||||
|
||||
/** 状态栏通知图标容器 */
|
||||
private var notificationIconContainer: ViewGroup? = null
|
||||
|
||||
/** 缓存的通知小图标包装纸实例 */
|
||||
private var notificationViewWrappers = ArraySet<Any>()
|
||||
|
||||
/** MIUI 样式下的缓存的通知小图标包装纸实例 */
|
||||
private var miuiNotificationViewWrappers = ArraySet<Any>()
|
||||
|
||||
/** MIUI 样式下的缓存的通知小图标折叠通知实例 */
|
||||
private var miuiNotificationChildrenContainers = ArraySet<ViewGroup>()
|
||||
|
||||
/** 仅监听一次主题壁纸颜色变化 */
|
||||
private var isWallpaperColorListenerSetUp = false
|
||||
|
||||
/** 是否已经注册广播 */
|
||||
private var isRegisterReceiver = false
|
||||
|
||||
/** 用户解锁屏幕广播接收器 */
|
||||
private val userPresentReceiver by lazy {
|
||||
object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
/** 解锁后重新刷新状态栏图标防止系统重新设置它 */
|
||||
if (isUsingCachingMethod) refreshStatusBarIcons()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 模块广播接收器 */
|
||||
private val moduleCheckingReceiver by lazy {
|
||||
object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
context?.sendBroadcast(Intent().apply {
|
||||
action = Const.ACTION_MODULE_HANDLER_RECEIVER
|
||||
putExtra("isRegular", true)
|
||||
putExtra("isValied", intent?.isValiedModule)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 通知广播接收器 */
|
||||
private val remindCheckingReceiver by lazy {
|
||||
object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) = delayedRun(ms = 300) {
|
||||
if (intent?.isValiedModule == true)
|
||||
recachingPrefs(intent.getBooleanExtra("isRefreshCacheOnly", false))
|
||||
context?.sendBroadcast(Intent().apply {
|
||||
action = Const.ACTION_REMIND_HANDLER_RECEIVER
|
||||
putExtra("isGrasp", true)
|
||||
putExtra("isValied", intent?.isValiedModule)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断模块和宿主版本是否一致
|
||||
* @return [Boolean]
|
||||
*/
|
||||
private val Intent.isValiedModule get() = getStringExtra(Const.MODULE_VERSION_VERIFY_TAG) == Const.MODULE_VERSION_VERIFY
|
||||
|
||||
/**
|
||||
* 注册广播接收器
|
||||
* @param context 实例
|
||||
*/
|
||||
private fun registerReceiver(context: Context) {
|
||||
if (isRegisterReceiver) return
|
||||
context.registerReceiver(userPresentReceiver, IntentFilter().apply { addAction(Intent.ACTION_USER_PRESENT) })
|
||||
context.registerReceiver(moduleCheckingReceiver, IntentFilter().apply { addAction(Const.ACTION_MODULE_CHECKING_RECEIVER) })
|
||||
context.registerReceiver(remindCheckingReceiver, IntentFilter().apply { addAction(Const.ACTION_REMIND_CHECKING_RECEIVER) })
|
||||
isRegisterReceiver = true
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否启用通知图标优化功能
|
||||
* @param isHooking 是否判断启用通知功能 - 默认:是
|
||||
* @return [Boolean]
|
||||
*/
|
||||
private fun isEnableHookColorNotifyIcon(isHooking: Boolean = true) =
|
||||
prefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX) && (if (isHooking) prefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX_NOTIFY) else true)
|
||||
|
||||
/**
|
||||
* - 这个是修复彩色图标的关键核心代码判断
|
||||
*
|
||||
* 判断是否为灰度图标 - 反射执行系统方法
|
||||
* @param context 实例
|
||||
* @param drawable 要判断的图标
|
||||
* @return [Boolean]
|
||||
*/
|
||||
private fun isGrayscaleIcon(context: Context, drawable: Drawable) =
|
||||
if (prefs.get(DataConst.ENABLE_COLOR_ICON_COMPAT).not()) safeOfFalse {
|
||||
ContrastColorUtilClass.clazz.let {
|
||||
it.method {
|
||||
name = "isGrayscaleIcon"
|
||||
param(DrawableClass)
|
||||
}.get(it.method {
|
||||
name = "getInstance"
|
||||
param(ContextClass)
|
||||
}.get().invoke(context)).boolean(drawable)
|
||||
}
|
||||
} else BitmapCompatTool.isGrayscaleDrawable(drawable)
|
||||
|
||||
/**
|
||||
* 是否为旧版本 MIUI 方案
|
||||
*
|
||||
* 拥有 “handleHeaderViews” 方法
|
||||
* @return [Boolean]
|
||||
*/
|
||||
private val hasHandleHeaderViews
|
||||
get() = safeOfFalse { NotificationHeaderViewWrapperClass.clazz.hasMethod { name = "handleHeaderViews" } }
|
||||
|
||||
/**
|
||||
* 获取是否存在忽略图标色彩处理的方法
|
||||
* @return [Boolean]
|
||||
*/
|
||||
private val hasIgnoreStatusBarIconColor
|
||||
get() = safeOfFalse {
|
||||
NotificationUtilClass.clazz.hasMethod {
|
||||
name = "ignoreStatusBarIconColor"
|
||||
param(ExpandedNotificationClass)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理为圆角图标
|
||||
* @return [Drawable]
|
||||
*/
|
||||
private fun Drawable.rounded(context: Context) =
|
||||
safeOf(default = this) { BitmapDrawable(context.resources, toBitmap().round(10.dpFloat(context))) }
|
||||
|
||||
/**
|
||||
* 适配通知栏、状态栏来自系统推送的彩色 APP 图标
|
||||
*
|
||||
* 适配第三方图标包对系统包管理器更换图标后的彩色图标
|
||||
* @param context 实例
|
||||
* @param iconDrawable 原始图标
|
||||
* @return [Drawable] 适配的图标
|
||||
*/
|
||||
private fun StatusBarNotification.compatPushingIcon(context: Context, iconDrawable: Drawable) = safeOf(iconDrawable) {
|
||||
/** 给 MIPUSH 设置 APP 自己的图标 */
|
||||
if (isXmsf && nfPkgName.isNotBlank())
|
||||
context.findAppIcon(xmsfPkgName) ?: iconDrawable
|
||||
else iconDrawable
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印日志
|
||||
* @param tag 标识
|
||||
* @param context 实例
|
||||
* @param expandedNf 通知实例
|
||||
* @param isCustom 是否为通知优化生效图标
|
||||
* @param isGrayscale 是否为灰度图标
|
||||
*/
|
||||
private fun printLogcat(
|
||||
tag: String,
|
||||
context: Context,
|
||||
expandedNf: StatusBarNotification?,
|
||||
isCustom: Boolean,
|
||||
isGrayscale: Boolean
|
||||
) {
|
||||
if (prefs.get(DataConst.ENABLE_MODULE_LOG)) loggerD(
|
||||
msg = "$tag --> [${context.findAppName(name = expandedNf?.nfPkgName ?: "")}][${expandedNf?.nfPkgName}] " +
|
||||
"custom [$isCustom] " +
|
||||
"grayscale [$isGrayscale] " +
|
||||
"xmsf [${expandedNf?.isXmsf}]"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取推送通知的包名
|
||||
*
|
||||
* 自动兼容旧版本系统
|
||||
* @return [String]
|
||||
*/
|
||||
private val StatusBarNotification.compatOpPkgName
|
||||
get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) opPkg else packageName ?: ""
|
||||
|
||||
/**
|
||||
* 判断通知是否来自 MIPUSH
|
||||
* @return [Boolean]
|
||||
*/
|
||||
private val StatusBarNotification.isXmsf get() = compatOpPkgName == "com.xiaomi.xmsf"
|
||||
|
||||
/**
|
||||
* 获取推送通知的包名
|
||||
*
|
||||
* 自动判断 MIPUSH
|
||||
* @return [String]
|
||||
*/
|
||||
private val StatusBarNotification.nfPkgName get() = if (isXmsf) xmsfPkgName else packageName
|
||||
|
||||
/**
|
||||
* 获取 MIPUSH 通知真实包名
|
||||
* @return [String]
|
||||
*/
|
||||
private val StatusBarNotification.xmsfPkgName: String
|
||||
get() {
|
||||
val xmsfPkg = notification.extras.getString("xmsf_target_package") ?: ""
|
||||
val targetPkg = notification.extras.getString("target_package") ?: ""
|
||||
return xmsfPkg.ifBlank { targetPkg.ifBlank { packageName } }
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取全局上下文
|
||||
* @return [Context] or null
|
||||
*/
|
||||
private val globalContext
|
||||
get() = safeOfNull {
|
||||
SystemUIApplicationClass.clazz.method { name = "getContext" }.ignoredError().get().invoke<Context>()
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册主题壁纸改变颜色监听
|
||||
*
|
||||
* - 仅限在 Android 12 以下注册
|
||||
* @param view 实例
|
||||
*/
|
||||
private fun registerWallpaperColorChanged(view: View) = runInSafe {
|
||||
if (isWallpaperColorListenerSetUp.not() && isUpperOfAndroidS.not()) view.apply {
|
||||
WallpaperManager.getInstance(context).addOnColorsChangedListener({ _, _ -> refreshNotificationIcons() }, handler)
|
||||
}
|
||||
isWallpaperColorListenerSetUp = true
|
||||
}
|
||||
|
||||
/** 刷新状态栏小图标 */
|
||||
private fun refreshStatusBarIcons() = runInSafe {
|
||||
StatusBarIconViewClass.clazz.field { name = "mNotification" }.also { result ->
|
||||
notificationIconContainer?.children?.forEach {
|
||||
/** 得到通知实例 */
|
||||
val nf = result.get(it).cast<StatusBarNotification>() ?: return
|
||||
/** 刷新状态栏图标 */
|
||||
compatStatusIcon(it.context, nf, nf.notification.smallIcon.loadDrawable(it.context)).also { pair ->
|
||||
pair.first.let { e -> (it as? ImageView?)?.setImageDrawable(e) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 刷新通知小图标 */
|
||||
private fun refreshNotificationIcons() = runInSafe {
|
||||
(if (hasHandleHeaderViews)
|
||||
NotificationHeaderViewWrapperClass.clazz.method { name = "handleHeaderViews" }
|
||||
else NotificationHeaderViewWrapperClass.clazz.method { name = "resolveHeaderViews" }).also { result ->
|
||||
notificationViewWrappers.takeIf { it.isNotEmpty() }?.forEach { result.get(it).call() }
|
||||
}
|
||||
MiuiNotificationViewWrapperClass.clazz.method { name = "handleViews" }.ignoredError().also { result ->
|
||||
miuiNotificationViewWrappers.takeIf { it.isNotEmpty() }?.forEach { result.get(it).call() }
|
||||
}
|
||||
MiuiNotificationChildrenContainerClass.clazz.method {
|
||||
name = "updateAppIcon"
|
||||
param(BooleanType)
|
||||
}.ignoredError().also { result ->
|
||||
miuiNotificationChildrenContainers.takeIf { it.isNotEmpty() }?.forEach { result.get(it).call(true) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动适配状态栏、通知栏自定义小图标
|
||||
* @param isGrayscaleIcon 是否为灰度图标
|
||||
* @param packageName APP 包名
|
||||
* @return [Pair] - ([Bitmap] 位图,[Int] 颜色)
|
||||
*/
|
||||
private fun compatCustomIcon(isGrayscaleIcon: Boolean, packageName: String): Pair<Bitmap?, Int> {
|
||||
var customPair: Pair<Bitmap?, Int>? = null
|
||||
if (prefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX)) run {
|
||||
iconDatas.takeIf { it.isNotEmpty() }?.forEach {
|
||||
if (packageName == it.packageName && isAppNotifyHookOf(it)) {
|
||||
if (isGrayscaleIcon.not() || isAppNotifyHookAllOf(it))
|
||||
customPair = Pair(it.iconBitmap, it.iconColor)
|
||||
return@run
|
||||
}
|
||||
}
|
||||
}
|
||||
return customPair ?: Pair(null, 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook 状态栏小图标
|
||||
*
|
||||
* 区分系统版本 - 由于每个系统版本的方法不一样这里单独拿出来进行 Hook
|
||||
* @param context 实例
|
||||
* @param expandedNf 通知实例
|
||||
* @param iconDrawable 小图标 [Drawable]
|
||||
* @return [Pair] 回调小图标 - ([Drawable] 小图标,[Boolean] 是否替换)
|
||||
*/
|
||||
private fun compatStatusIcon(context: Context, expandedNf: StatusBarNotification?, iconDrawable: Drawable?) =
|
||||
expandedNf?.let { notifyInstance ->
|
||||
if (iconDrawable == null) return@let Pair(null, false)
|
||||
/** 判断是否不是灰度图标 */
|
||||
val isNotGrayscaleIcon = notifyInstance.isXmsf || isGrayscaleIcon(context, iconDrawable).not()
|
||||
|
||||
/** 目标彩色通知 APP 图标 */
|
||||
val customIcon = compatCustomIcon(isNotGrayscaleIcon.not(), notifyInstance.nfPkgName).first
|
||||
/** 打印日志 */
|
||||
printLogcat(tag = "StatusIcon", context, notifyInstance, isCustom = customIcon != null, isNotGrayscaleIcon.not())
|
||||
when {
|
||||
/** 处理自定义通知图标优化 */
|
||||
customIcon != null -> Pair(BitmapDrawable(context.resources, customIcon), true)
|
||||
/** 若不是灰度图标自动处理为圆角 */
|
||||
isNotGrayscaleIcon -> Pair(notifyInstance.compatPushingIcon(context, iconDrawable).rounded(context), true)
|
||||
/** 否则返回原始小图标 */
|
||||
else -> Pair(notifyInstance.notification.smallIcon.loadDrawable(context), false)
|
||||
}
|
||||
} ?: Pair(null, false)
|
||||
|
||||
/**
|
||||
* Hook 通知栏小图标
|
||||
*
|
||||
* 区分系统版本 - 由于每个系统版本的方法不一样这里单独拿出来进行 Hook
|
||||
* @param context 实例
|
||||
* @param expandedNf 通知实例
|
||||
* @param iconImageView 通知图标实例
|
||||
* @param isExpanded 通知是否展开 - 可做最小化通知处理 - 默认:是
|
||||
* @param isUseAndroid12Style 是否使用 Android 12 通知图标风格 - 默认跟随系统版本决定
|
||||
*/
|
||||
private fun compatNotifyIcon(
|
||||
context: Context,
|
||||
expandedNf: StatusBarNotification?,
|
||||
iconImageView: ImageView,
|
||||
isExpanded: Boolean = true,
|
||||
isUseAndroid12Style: Boolean = isUpperOfAndroidS,
|
||||
) = runInSafe(msg = "compatNotifyIcon") {
|
||||
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
|
||||
expandedNf?.let { notifyInstance ->
|
||||
|
||||
/** 新版风格反色 */
|
||||
val newStyle = if (context.isSystemInDarkMode) 0xFF2D2D2D.toInt() else Color.WHITE
|
||||
|
||||
/** 旧版风格反色 */
|
||||
val oldStyle = if (context.isNotSystemInDarkMode) 0xFF707070.toInt() else Color.WHITE
|
||||
|
||||
/** 通知图标原始颜色 */
|
||||
val iconColor = notifyInstance.notification.color
|
||||
|
||||
/** 是否有通知栏图标颜色 */
|
||||
val hasIconColor = iconColor != 0
|
||||
|
||||
/** 通知图标适配颜色 */
|
||||
val supportColor = iconColor.let {
|
||||
when {
|
||||
isUseAndroid12Style -> newStyle
|
||||
it == 0 || isExpanded.not() -> oldStyle
|
||||
else -> it
|
||||
}
|
||||
}
|
||||
|
||||
/** 获取通知小图标 */
|
||||
val iconDrawable = notifyInstance.notification.smallIcon.loadDrawable(context)
|
||||
|
||||
/** 判断图标风格 */
|
||||
val isGrayscaleIcon = notifyInstance.isXmsf.not() && isGrayscaleIcon(context, iconDrawable)
|
||||
|
||||
/** 自定义默认小图标 */
|
||||
var customIcon: Bitmap?
|
||||
|
||||
/** 自定义默认小图标颜色 */
|
||||
var customIconColor: Int
|
||||
compatCustomIcon(isGrayscaleIcon, notifyInstance.nfPkgName).also {
|
||||
customIcon = it.first
|
||||
customIconColor = if (isUseAndroid12Style || isExpanded)
|
||||
(it.second.takeIf { e -> e != 0 } ?: (if (isUseAndroid12Style) context.systemAccentColor else 0)) else 0
|
||||
}
|
||||
/** 打印日志 */
|
||||
printLogcat(tag = "NotifyIcon", context, notifyInstance, isCustom = customIcon != null, isGrayscaleIcon)
|
||||
/** 处理自定义通知图标优化 */
|
||||
if (customIcon != null) iconImageView.apply {
|
||||
/** 设置不要裁切到边界 */
|
||||
clipToOutline = false
|
||||
/** 设置自定义小图标 */
|
||||
setImageBitmap(customIcon)
|
||||
/** 上色 */
|
||||
setColorFilter(if (isUseAndroid12Style || customIconColor == 0) supportColor else customIconColor)
|
||||
/** Android 12 设置图标外圈颜色 */
|
||||
if (isUseAndroid12Style && customIconColor != 0)
|
||||
background = DrawableBuilder()
|
||||
.rounded()
|
||||
.solidColor(if (context.isSystemInDarkMode) customIconColor.brighter else customIconColor)
|
||||
.build()
|
||||
/** 设置原生的背景边距 */
|
||||
if (isUseAndroid12Style) setPadding(4.dp(context), 4.dp(context), 4.dp(context), 4.dp(context))
|
||||
} else {
|
||||
/** 重新设置图标 - 防止系统更改它 */
|
||||
iconImageView.setImageDrawable(iconDrawable)
|
||||
/** 判断如果是灰度图标就给他设置一个白色颜色遮罩 */
|
||||
if (isGrayscaleIcon) iconImageView.apply {
|
||||
/** 设置不要裁切到边界 */
|
||||
clipToOutline = false
|
||||
/** 设置图标着色 */
|
||||
setColorFilter(supportColor)
|
||||
/** Android 12 设置图标外圈颜色 */
|
||||
(if (hasIconColor) iconColor else context.systemAccentColor).also {
|
||||
if (isUseAndroid12Style)
|
||||
background = DrawableBuilder()
|
||||
.rounded()
|
||||
.solidColor(if (context.isSystemInDarkMode) it.brighter else it)
|
||||
.build()
|
||||
}
|
||||
/** 设置原生的背景边距 */
|
||||
if (isUseAndroid12Style) setPadding(4.dp(context), 4.dp(context), 4.dp(context), 4.dp(context))
|
||||
} else iconImageView.apply {
|
||||
/** 重新设置图标 */
|
||||
setImageDrawable(notifyInstance.compatPushingIcon(context, iconDrawable))
|
||||
/** 设置裁切到边界 */
|
||||
clipToOutline = true
|
||||
/** 设置一个圆角轮廓裁切 */
|
||||
outlineProvider = object : ViewOutlineProvider() {
|
||||
override fun getOutline(view: View, out: Outline) {
|
||||
out.setRoundRect(
|
||||
0, 0,
|
||||
view.width, view.height, 5.dpFloat(context)
|
||||
)
|
||||
}
|
||||
}
|
||||
if (isUseAndroid12Style) {
|
||||
/** 清除原生的背景边距 */
|
||||
setPadding(0, 0, 0, 0)
|
||||
/** 清除原生的主题色背景圆圈颜色 */
|
||||
background = null
|
||||
}
|
||||
/** 清除遮罩颜色 */
|
||||
colorFilter = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断状态栏小图标颜色以及反射的核心方法
|
||||
*
|
||||
* 区分系统版本 - 由于每个系统版本的方法不一样这里单独拿出来进行 Hook
|
||||
* @param context 实例
|
||||
* @param expandedNf 状态栏实例
|
||||
* @return [Boolean] 是否忽略通知图标颜色
|
||||
*/
|
||||
private fun hasIgnoreStatusBarIconColor(context: Context, expandedNf: StatusBarNotification?) = safeOfFalse {
|
||||
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
|
||||
expandedNf?.let { notifyInstance ->
|
||||
/** 获取通知小图标 */
|
||||
val iconDrawable = notifyInstance.notification.smallIcon.loadDrawable(context)
|
||||
|
||||
/** 判断是否不是灰度图标 */
|
||||
val isNotGrayscaleIcon = notifyInstance.isXmsf || isGrayscaleIcon(context, iconDrawable).not()
|
||||
|
||||
/** 获取目标修复彩色图标的 APP */
|
||||
val isTargetFixApp = compatCustomIcon(isNotGrayscaleIcon.not(), notifyInstance.nfPkgName).first != null
|
||||
/**
|
||||
* 只要不是灰度就返回彩色图标
|
||||
* 否则不对颜色进行反色处理防止一些系统图标出现异常
|
||||
*/
|
||||
(if (isTargetFixApp) false else isNotGrayscaleIcon).also {
|
||||
printLogcat(tag = "IconColor", context, expandedNf, isTargetFixApp, isNotGrayscaleIcon.not())
|
||||
}
|
||||
} ?: true.also { printLogcat(tag = "IconColor", context, expandedNf = null, isCustom = false, isGrayscale = false) }
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 [NotificationViewWrapperClass] 中获取 [ExpandableNotificationRowClass]
|
||||
* @return [Pair] - ([Boolean] 通知是否展开,[Any] 通知 Row 实例)
|
||||
*/
|
||||
private fun Any.getRowPair(): Pair<Boolean, Any?> {
|
||||
/** 通知是否展开 */
|
||||
var isExpanded = false
|
||||
|
||||
/**
|
||||
* 从父类中得到 mRow 变量 - [ExpandableNotificationRowClass]
|
||||
* 获取其中的得到通知方法
|
||||
*/
|
||||
val row = NotificationViewWrapperClass.clazz.field {
|
||||
name = "mRow"
|
||||
}.get(this).self?.also {
|
||||
isExpanded = ExpandableNotificationRowClass.clazz.method {
|
||||
name = "isExpanded"
|
||||
returnType = BooleanType
|
||||
}.get(it).boolean()
|
||||
}
|
||||
return Pair(isExpanded, row)
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 [ExpandableNotificationRowClass] 中获取 [StatusBarNotification]
|
||||
* @return [StatusBarNotification] or null
|
||||
*/
|
||||
private fun Any?.getSbn() =
|
||||
ExpandableNotificationRowClass.clazz
|
||||
.method { name = "getEntry" }
|
||||
.get(this).call()?.let {
|
||||
it.javaClass.method {
|
||||
name = "getSbn"
|
||||
}.get(it).invoke<StatusBarNotification>()
|
||||
} ?: ExpandableNotificationRowClass.clazz
|
||||
.method { name = "getStatusBarNotification" }
|
||||
.get(NotificationViewWrapperClass.clazz.field { name = "mRow" }.get(this).self)
|
||||
.invoke<StatusBarNotification>()
|
||||
|
||||
/** 缓存图标数据 */
|
||||
private fun cachingIconDatas() {
|
||||
iconDatas.clear()
|
||||
IconPackParams(param = this).iconDatas.apply {
|
||||
when {
|
||||
isNotEmpty() -> forEach { iconDatas.add(it) }
|
||||
isEmpty() && isEnableHookColorNotifyIcon(isHooking = false) -> loggerW(msg = "NotifyIconSupportData is empty!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新缓存数据
|
||||
* @param isRefreshCacheOnly 仅刷新缓存不刷新图标和通知改变 - 默认:否
|
||||
*/
|
||||
private fun recachingPrefs(isRefreshCacheOnly: Boolean = false) {
|
||||
isUsingCachingMethod = true
|
||||
prefs.clearCache()
|
||||
cachingIconDatas()
|
||||
if (isRefreshCacheOnly) return
|
||||
refreshStatusBarIcons()
|
||||
refreshNotificationIcons()
|
||||
}
|
||||
|
||||
override fun onHook() {
|
||||
/** 缓存图标数据 */
|
||||
cachingIconDatas()
|
||||
/** 注入 MIUI 自己增加的一个工具类 */
|
||||
NotificationUtilClass.hook {
|
||||
/** 强制回写系统的状态栏图标样式为原生 */
|
||||
injectMember {
|
||||
method {
|
||||
name = "shouldSubstituteSmallIcon"
|
||||
param(ExpandedNotificationClass)
|
||||
}
|
||||
replaceToFalse()
|
||||
}
|
||||
/** 强制回写系统的状态栏图标样式为原生 */
|
||||
injectMember {
|
||||
var isUseLegacy = false
|
||||
method {
|
||||
name = "getSmallIcon"
|
||||
param(ExpandedNotificationClass, IntType)
|
||||
}.remedys {
|
||||
method {
|
||||
name = "getSmallIcon"
|
||||
param(ExpandedNotificationClass)
|
||||
}
|
||||
method {
|
||||
name = "getSmallIcon"
|
||||
param(ContextClass, ExpandedNotificationClass)
|
||||
}.onFind { isUseLegacy = true }
|
||||
}
|
||||
afterHook {
|
||||
(globalContext ?: firstArgs())?.also { context ->
|
||||
val expandedNf = args(if (isUseLegacy) 1 else 0).cast<StatusBarNotification?>()
|
||||
/** Hook 状态栏小图标 */
|
||||
compatStatusIcon(
|
||||
context = context,
|
||||
expandedNf,
|
||||
(result as Icon).loadDrawable(context)
|
||||
).also { pair -> if (pair.second) result = Icon.createWithBitmap(pair.first?.toBitmap()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/** 注入状态栏通知图标实例 */
|
||||
StatusBarIconViewClass.hook {
|
||||
/** Hook 状态栏通知图标的颜色 */
|
||||
injectMember {
|
||||
method { name = "updateIconColor" }
|
||||
afterHook {
|
||||
instance<ImageView>().also {
|
||||
if (hasIgnoreStatusBarIconColor(it.context, field { name = "mNotification" }
|
||||
.get(instance).cast<StatusBarNotification>())) it.apply {
|
||||
alpha = 1f
|
||||
colorFilter = null
|
||||
} else it.apply {
|
||||
/**
|
||||
* 防止图标不是纯黑的问题
|
||||
* 图标在任何场景下跟随状态栏其它图标保持半透明
|
||||
* MIUI 12 进行单独判断
|
||||
*/
|
||||
field { name = "mCurrentSetColor" }.get(instance).int().also { color ->
|
||||
if (hasIgnoreStatusBarIconColor) {
|
||||
alpha = if (color.isWhite) 0.95f else 0.8f
|
||||
setColorFilter(if (color.isWhite) color else Color.BLACK)
|
||||
} else setColorFilter(color)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/** 记录实例 */
|
||||
injectMember {
|
||||
method {
|
||||
name = "setNotification"
|
||||
param(StatusBarNotificationClass)
|
||||
}.remedys {
|
||||
method {
|
||||
name = "setNotification"
|
||||
param(ExpandedNotificationClass)
|
||||
}
|
||||
}
|
||||
afterHook {
|
||||
if (firstArgs != null) instance<ImageView>().also {
|
||||
/** 注册壁纸颜色监听 */
|
||||
registerWallpaperColorChanged(it)
|
||||
/** 注册广播 */
|
||||
registerReceiver(it.context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/** 注入状态栏通知图标容器实例 */
|
||||
NotificationIconContainerClass.hook {
|
||||
injectMember {
|
||||
method { name = "calculateIconTranslations" }
|
||||
afterHook {
|
||||
/** 缓存实例 */
|
||||
notificationIconContainer = instance<ViewGroup>()
|
||||
/** 修复部分开发版状态栏图标只能显示一个的问题 */
|
||||
when (miuiIncrementalVersion.lowercase()) {
|
||||
"22.3.14", "22.3.15", "22.3.16", "v13.0.1.1.16.dev", "22.3.18" ->
|
||||
instance<ViewGroup>().layoutParams.width = 9999
|
||||
}
|
||||
}
|
||||
}
|
||||
injectMember {
|
||||
method { name = "updateState" }
|
||||
beforeHook {
|
||||
/** 解除状态栏通知图标个数限制 */
|
||||
if (isShowNotificationIcons && prefs.get(DataConst.ENABLE_HOOK_STATUS_ICON_COUNT))
|
||||
field { name = "MAX_STATIC_ICONS" }
|
||||
.get(instance).set(prefs.get(DataConst.HOOK_STATUS_ICON_COUNT)
|
||||
.let { if (it in 0..100) it else 5 })
|
||||
}
|
||||
}.by { NotificationIconContainerClass.clazz.hasField { name = "MAX_STATIC_ICONS" } }
|
||||
/** 旧版方法 - 新版不存在 */
|
||||
injectMember {
|
||||
method {
|
||||
name = "setMaxStaticIcons"
|
||||
param(IntType)
|
||||
}
|
||||
beforeHook { isShowNotificationIcons = (firstArgs<Int>() ?: 0) > 0 }
|
||||
}.ignoredNoSuchMemberFailure()
|
||||
/** 新版方法 - 旧版不存在 */
|
||||
injectMember {
|
||||
method {
|
||||
name = "miuiShowNotificationIcons"
|
||||
param(BooleanType)
|
||||
}
|
||||
beforeHook { isShowNotificationIcons = firstArgs<Boolean>() ?: false }
|
||||
}.ignoredNoSuchMemberFailure()
|
||||
}
|
||||
/** 注入原生通知包装纸实例 */
|
||||
NotificationHeaderViewWrapperClass.hook {
|
||||
/** 修复下拉通知图标自动设置回 APP 图标的方法 */
|
||||
injectMember {
|
||||
if (hasHandleHeaderViews)
|
||||
method { name = "handleHeaderViews" }
|
||||
else method { name = "resolveHeaderViews" }
|
||||
afterHook {
|
||||
/** 获取小图标 */
|
||||
val iconImageView =
|
||||
NotificationHeaderViewWrapperClass.clazz
|
||||
.field { name = "mIcon" }.get(instance).cast<ImageView>() ?: return@afterHook
|
||||
|
||||
/** 获取 [ExpandableNotificationRowClass] */
|
||||
val rowPair = instance.getRowPair()
|
||||
|
||||
/** 获取 [StatusBarNotification] */
|
||||
val expandedNf = rowPair.second.getSbn()
|
||||
|
||||
/** 通知是否展开 */
|
||||
var isExpanded = rowPair.first
|
||||
|
||||
/** 获取优先级 */
|
||||
val importance =
|
||||
(iconImageView.context.getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager?)
|
||||
?.getNotificationChannel(expandedNf?.notification?.channelId)?.importance ?: 0
|
||||
/** 非最小化优先级的通知全部设置为展开状态 */
|
||||
if (importance != 1) isExpanded = true
|
||||
/** 执行 Hook */
|
||||
compatNotifyIcon(iconImageView.context, expandedNf, iconImageView, isExpanded)
|
||||
}
|
||||
}
|
||||
/** 记录实例 */
|
||||
injectMember {
|
||||
constructor { param(ContextClass, ViewClass, ExpandableNotificationRowClass) }
|
||||
afterHook { notificationViewWrappers.add(instance) }
|
||||
}
|
||||
}
|
||||
/** 修改 MIUI 风格通知栏的通知图标 */
|
||||
MiuiNotificationViewWrapperClass.hook {
|
||||
/** 替换通知小图标 */
|
||||
injectMember {
|
||||
method { name = "handleAppIcon" }
|
||||
replaceUnit {
|
||||
field { name = "mAppIcon" }.get(instance).cast<ImageView>()?.apply {
|
||||
compatNotifyIcon(
|
||||
context = context,
|
||||
expandedNf = instance.getRowPair().second.getSbn(),
|
||||
iconImageView = this,
|
||||
isUseAndroid12Style = true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
/** 记录实例 */
|
||||
injectMember {
|
||||
constructor { param(ContextClass, ViewClass, ExpandableNotificationRowClass) }
|
||||
afterHook { miuiNotificationViewWrappers.add(instance) }
|
||||
}
|
||||
}.ignoredHookClassNotFoundFailure()
|
||||
/** 修改 MIUI 风格通知栏的通知图标 - 折叠通知 */
|
||||
MiuiNotificationChildrenContainerClass.hook {
|
||||
/** 替换通知小图标 */
|
||||
injectMember {
|
||||
method {
|
||||
name = "updateAppIcon"
|
||||
param(BooleanType)
|
||||
}
|
||||
afterHook {
|
||||
val expandedNf = NotificationChildrenContainerClass.clazz.field {
|
||||
name = "mContainingNotification"
|
||||
}.get(instance).self.getSbn()
|
||||
field { name = "mAppIcon" }.get(instance).cast<ImageView>()?.apply {
|
||||
compatNotifyIcon(context, expandedNf, iconImageView = this, isUseAndroid12Style = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
/** 记录实例 */
|
||||
injectMember {
|
||||
constructor { param(ContextClass, AttributeSetClass) }
|
||||
afterHook { miuiNotificationChildrenContainers.add(instance()) }
|
||||
}
|
||||
}.ignoredHookClassNotFoundFailure()
|
||||
/** 干掉下拉通知图标自动设置回 APP 图标的方法 */
|
||||
NotificationHeaderViewWrapperInjectorClass.hook {
|
||||
injectMember {
|
||||
method {
|
||||
name = "setAppIcon"
|
||||
param(ContextClass, ImageViewClass, ExpandedNotificationClass)
|
||||
}.remedys {
|
||||
method {
|
||||
name = "setAppIcon"
|
||||
param(ImageViewClass, ExpandedNotificationClass)
|
||||
}
|
||||
}
|
||||
intercept()
|
||||
}.ignoredNoSuchMemberFailure()
|
||||
injectMember {
|
||||
method {
|
||||
name = "resetIconBgAndPaddings"
|
||||
param(ImageViewClass, ExpandedNotificationClass)
|
||||
}
|
||||
intercept()
|
||||
}.ignoredNoSuchMemberFailure()
|
||||
}.ignoredHookClassNotFoundFailure()
|
||||
/** 发送适配新的 APP 图标通知 */
|
||||
PluginManagerImplClass.hook {
|
||||
injectMember {
|
||||
method {
|
||||
name = "onReceive"
|
||||
param(ContextClass, IntentClass)
|
||||
}
|
||||
afterHook {
|
||||
if (isEnableHookColorNotifyIcon()) (lastArgs as? Intent)?.also {
|
||||
if (it.action.equals(Intent.ACTION_PACKAGE_REPLACED).not() &&
|
||||
it.getBooleanExtra(Intent.EXTRA_REPLACING, false)
|
||||
) return@also
|
||||
when (it.action) {
|
||||
Intent.ACTION_PACKAGE_ADDED ->
|
||||
it.data?.schemeSpecificPart?.also { newPkgName ->
|
||||
if (iconDatas.takeIf { e -> e.isNotEmpty() }
|
||||
?.filter { e -> e.packageName == newPkgName }
|
||||
.isNullOrEmpty()
|
||||
) IconAdaptationTool.pushNewAppSupportNotify(firstArgs()!!, newPkgName)
|
||||
}
|
||||
Intent.ACTION_PACKAGE_REMOVED ->
|
||||
IconAdaptationTool.removeNewAppSupportNotify(
|
||||
context = firstArgs()!!,
|
||||
packageName = it.data?.schemeSpecificPart ?: ""
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/** 自动检查通知图标优化更新的注入监听 */
|
||||
MiuiClockClass.hook {
|
||||
injectMember {
|
||||
method { name = "updateTime" }
|
||||
afterHook {
|
||||
instance<View>().context.also {
|
||||
/** 注册广播 */
|
||||
registerReceiver(it)
|
||||
/** 注册定时监听 */
|
||||
if (isEnableHookColorNotifyIcon() && prefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX_AUTO))
|
||||
IconAdaptationTool.prepareAutoUpdateIconRule(
|
||||
context = it,
|
||||
timeSet = prefs.get(DataConst.NOTIFY_ICON_FIX_AUTO_TIME)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}.ignoredHookClassNotFoundFailure()
|
||||
}
|
||||
}
|
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/2/15.
|
||||
*/
|
||||
package com.fankes.miui.notify.hook.factory
|
||||
|
||||
import android.content.Context
|
||||
import com.fankes.miui.notify.bean.IconDataBean
|
||||
import com.highcapable.yukihookapi.hook.factory.modulePrefs
|
||||
import com.highcapable.yukihookapi.hook.param.PackageParam
|
||||
|
||||
/**
|
||||
* 获取此 APP 的通知图标是否被 Hook
|
||||
* @param bean 图标 bean
|
||||
*/
|
||||
fun PackageParam.isAppNotifyHookOf(bean: IconDataBean) = prefs.getBoolean(bean.toEnabledName(), bean.isEnabled)
|
||||
|
||||
/**
|
||||
* 获取此 APP 的通知图标是否被 Hook
|
||||
* @param bean 图标 bean
|
||||
*/
|
||||
fun Context.isAppNotifyHookOf(bean: IconDataBean) = modulePrefs.getBoolean(bean.toEnabledName(), bean.isEnabled)
|
||||
|
||||
/**
|
||||
* 设置 Hook 此 APP 的通知图标
|
||||
* @param bean 图标 bean
|
||||
* @param isHook 是否 Hook
|
||||
*/
|
||||
fun Context.putAppNotifyHookOf(bean: IconDataBean, isHook: Boolean) = modulePrefs.putBoolean(bean.toEnabledName(), isHook)
|
||||
|
||||
/**
|
||||
* 获取此 APP 的通知图标是否被全部 Hook
|
||||
* @param bean 图标 bean
|
||||
*/
|
||||
fun PackageParam.isAppNotifyHookAllOf(bean: IconDataBean) = prefs.getBoolean(bean.toEnabledAllName(), bean.isEnabledAll)
|
||||
|
||||
/**
|
||||
* 获取此 APP 的通知图标是否被全部 Hook
|
||||
* @param bean 图标 bean
|
||||
*/
|
||||
fun Context.isAppNotifyHookAllOf(bean: IconDataBean) = modulePrefs.getBoolean(bean.toEnabledAllName(), bean.isEnabledAll)
|
||||
|
||||
/**
|
||||
* 设置全部 Hook 此 APP 的通知图标
|
||||
* @param bean 图标 bean
|
||||
* @param isHook 是否 Hook
|
||||
*/
|
||||
fun Context.putAppNotifyHookAllOf(bean: IconDataBean, isHook: Boolean) = modulePrefs.putBoolean(bean.toEnabledAllName(), isHook)
|
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/3/26.
|
||||
*/
|
||||
package com.fankes.miui.notify.service
|
||||
|
||||
import android.service.quicksettings.TileService
|
||||
import com.fankes.miui.notify.ui.activity.ConfigureActivity
|
||||
import com.fankes.miui.notify.utils.factory.navigate
|
||||
|
||||
class QuickStartTileService : TileService() {
|
||||
|
||||
override fun onClick() {
|
||||
super.onClick()
|
||||
/** 启动通知图标优化列表窗口 */
|
||||
navigate<ConfigureActivity>()
|
||||
}
|
||||
}
|
@@ -1,125 +0,0 @@
|
||||
/**
|
||||
* 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,231 +0,0 @@
|
||||
/**
|
||||
* 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/24.
|
||||
*/
|
||||
@file:Suppress("SetTextI18n")
|
||||
|
||||
package com.fankes.miui.notify.ui
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
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.*
|
||||
|
||||
class MainActivity : BaseActivity() {
|
||||
|
||||
companion object {
|
||||
|
||||
/** 模块版本 */
|
||||
private const val moduleVersion = BuildConfig.VERSION_NAME
|
||||
}
|
||||
|
||||
private var isWarnDialogShowing = false // 警告对话框是否显示
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
/** 设置文本 */
|
||||
findViewById<TextView>(R.id.main_text_version).text = "当前版本:$moduleVersion"
|
||||
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 = "模块已激活"
|
||||
}
|
||||
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 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)
|
||||
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
|
||||
putBoolean(HookMedium.ENABLE_HIDE_ICON, b)
|
||||
packageManager.setComponentEnabledSetting(
|
||||
ComponentName(this@MainActivity, "com.fankes.miui.notify.Home"),
|
||||
if (b) PackageManager.COMPONENT_ENABLED_STATE_DISABLED else PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
|
||||
PackageManager.DONT_KILL_APP
|
||||
)
|
||||
}
|
||||
colorIconHookSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
if (!btn.isPressed) return@setOnCheckedChangeListener
|
||||
putBoolean(HookMedium.ENABLE_COLOR_ICON_HOOK, b)
|
||||
notifyIconConfigItem.isVisible = b
|
||||
}
|
||||
notifyIconHookSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
if (!btn.isPressed) return@setOnCheckedChangeListener
|
||||
putBoolean(HookMedium.ENABLE_NOTIFY_ICON_HOOK, b)
|
||||
}
|
||||
/** 重启按钮点击事件 */
|
||||
findViewById<View>(R.id.title_restart_icon).setOnClickListener {
|
||||
showDialog {
|
||||
title = "重启系统界面"
|
||||
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 {
|
||||
startActivity(Intent().apply {
|
||||
setPackage("com.coolapk.market")
|
||||
action = "android.intent.action.VIEW"
|
||||
data = Uri.parse("https://www.coolapk.com/u/876977")
|
||||
/** 防止顶栈一样重叠在自己的 APP 中 */
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
})
|
||||
} catch (e: Exception) {
|
||||
Toast.makeText(this, "你可能没有安装酷安", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
/** 项目地址点击事件 */
|
||||
findViewById<View>(R.id.link_with_project_address).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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
/** MIUI 12 的版本特殊 - 所以给出提示 */
|
||||
if (!isWarnDialogShowing && isHooked() && miuiVersion == "12" && isMiuiNotifyStyle)
|
||||
showDialog {
|
||||
isWarnDialogShowing = true
|
||||
title = "经典通知栏样式已启用"
|
||||
msg = "在 MIUI 12 中启用了经典通知栏样式后状态栏图标将不再做原生处理,模块停止工作," +
|
||||
"这取决于系统设置,你应当在 设置>通知管理>通知显示设置 中将样式设置为“原生样式”。"
|
||||
confirmButton(text = "我知道了") { isWarnDialogShowing = false }
|
||||
noCancelable()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断模块是否激活
|
||||
* @return [Boolean] 激活状态
|
||||
*/
|
||||
private fun isHooked() = HookMedium.isHooked()
|
||||
|
||||
/** 重启系统界面 */
|
||||
private fun restartSystemUI() =
|
||||
execShellCmd(cmd = "pgrep systemui").also { pid ->
|
||||
if (pid.isNotBlank())
|
||||
execShellCmd(cmd = "kill -9 $pid")
|
||||
else Toast.makeText(this, "ROOT 权限获取失败", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取保存的值
|
||||
* @param key 名称
|
||||
* @param default 默认值
|
||||
* @return [Boolean] 保存的值
|
||||
*/
|
||||
private fun getBoolean(key: String, default: Boolean = false) = HookMedium.getBoolean(key, default)
|
||||
|
||||
/**
|
||||
* 保存值
|
||||
* @param key 名称
|
||||
* @param bool 值
|
||||
*/
|
||||
private fun putBoolean(key: String, bool: Boolean) = HookMedium.putBoolean(key, bool)
|
||||
}
|
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/30.
|
||||
*/
|
||||
@file:Suppress("SetTextI18n", "InflateParams", "DEPRECATION")
|
||||
|
||||
package com.fankes.miui.notify.ui.activity
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.BaseAdapter
|
||||
import androidx.core.view.isVisible
|
||||
import com.fankes.miui.notify.R
|
||||
import com.fankes.miui.notify.bean.IconDataBean
|
||||
import com.fankes.miui.notify.databinding.ActivityConfigBinding
|
||||
import com.fankes.miui.notify.databinding.AdapterConfigBinding
|
||||
import com.fankes.miui.notify.databinding.DiaIconFilterBinding
|
||||
import com.fankes.miui.notify.hook.factory.isAppNotifyHookAllOf
|
||||
import com.fankes.miui.notify.hook.factory.isAppNotifyHookOf
|
||||
import com.fankes.miui.notify.hook.factory.putAppNotifyHookAllOf
|
||||
import com.fankes.miui.notify.hook.factory.putAppNotifyHookOf
|
||||
import com.fankes.miui.notify.params.IconPackParams
|
||||
import com.fankes.miui.notify.ui.activity.base.BaseActivity
|
||||
import com.fankes.miui.notify.utils.factory.*
|
||||
import com.fankes.miui.notify.utils.tool.IconRuleManagerTool
|
||||
import com.fankes.miui.notify.utils.tool.SystemUITool
|
||||
import com.highcapable.yukihookapi.hook.factory.isXposedModuleActive
|
||||
|
||||
class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
|
||||
|
||||
/** 当前筛选条件 */
|
||||
private var filterText = ""
|
||||
|
||||
/** 回调适配器改变 */
|
||||
private var onChanged: (() -> Unit)? = null
|
||||
|
||||
/** 回调滚动事件改变 */
|
||||
private var onScrollEvent: ((Boolean) -> Unit)? = null
|
||||
|
||||
/** 全部的通知图标优化数据 */
|
||||
private var iconAllDatas = ArrayList<IconDataBean>()
|
||||
|
||||
override fun onCreate() {
|
||||
/** 检查激活状态 */
|
||||
if (isXposedModuleActive.not()) {
|
||||
showDialog {
|
||||
title = "模块没有激活"
|
||||
msg = "模块没有激活,你无法使用这里的功能,请先激活模块。"
|
||||
confirmButton(text = "我知道了") { finish() }
|
||||
noCancelable()
|
||||
}
|
||||
return
|
||||
}
|
||||
/** 返回按钮点击事件 */
|
||||
binding.titleBackIcon.setOnClickListener { onBackPressed() }
|
||||
/** 刷新适配器结果相关 */
|
||||
refreshAdapterResult()
|
||||
/** 设置上下按钮点击事件 */
|
||||
binding.configTitleUp.setOnClickListener {
|
||||
snake(msg = "滚动到顶部")
|
||||
onScrollEvent?.invoke(false)
|
||||
}
|
||||
binding.configTitleDown.setOnClickListener {
|
||||
snake(msg = "滚动到底部")
|
||||
onScrollEvent?.invoke(true)
|
||||
}
|
||||
/** 设置过滤按钮点击事件 */
|
||||
binding.configTitleFilter.setOnClickListener {
|
||||
showDialog {
|
||||
title = "按条件过滤"
|
||||
val editText = bind<DiaIconFilterBinding>().diaIconFilterInputEdit.apply {
|
||||
requestFocus()
|
||||
invalidate()
|
||||
if (filterText.isNotBlank()) {
|
||||
setText(filterText)
|
||||
setSelection(filterText.length)
|
||||
}
|
||||
}
|
||||
confirmButton {
|
||||
if (editText.text.toString().isNotBlank()) {
|
||||
filterText = editText.text.toString().trim()
|
||||
refreshAdapterResult()
|
||||
} else {
|
||||
toast(msg = "条件不能为空")
|
||||
it.performClick()
|
||||
}
|
||||
}
|
||||
cancelButton()
|
||||
if (filterText.isNotBlank())
|
||||
neutralButton(text = "清除条件") {
|
||||
filterText = ""
|
||||
refreshAdapterResult()
|
||||
}
|
||||
}
|
||||
}
|
||||
/** 设置同步列表按钮点击事件 */
|
||||
binding.configTitleSync.setOnClickListener { onStartRefresh() }
|
||||
/** 设置列表元素和 Adapter */
|
||||
binding.configListView.apply {
|
||||
adapter = object : BaseAdapter() {
|
||||
|
||||
override fun getCount() = iconDatas.size
|
||||
|
||||
override fun getItem(position: Int) = iconDatas[position]
|
||||
|
||||
override fun getItemId(position: Int) = position.toLong()
|
||||
|
||||
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
|
||||
var cView = convertView
|
||||
val holder: AdapterConfigBinding
|
||||
if (convertView == null) {
|
||||
holder = AdapterConfigBinding.inflate(LayoutInflater.from(context))
|
||||
cView = holder.root
|
||||
cView.tag = holder
|
||||
} else holder = convertView.tag as AdapterConfigBinding
|
||||
getItem(position).also {
|
||||
holder.adpAppIcon.setImageBitmap(it.iconBitmap)
|
||||
(if (it.iconColor != 0) it.iconColor else resources.getColor(R.color.colorTextGray)).also { color ->
|
||||
holder.adpAppIcon.setColorFilter(color)
|
||||
holder.adpAppName.setTextColor(color)
|
||||
}
|
||||
holder.adpAppName.text = it.appName
|
||||
holder.adpAppPkgName.text = it.packageName
|
||||
holder.adpCbrName.text = "贡献者:" + it.contributorName
|
||||
isAppNotifyHookOf(it).also { e ->
|
||||
holder.adpAppOpenSwitch.isChecked = e
|
||||
holder.adpAppAllSwitch.isEnabled = e
|
||||
}
|
||||
holder.adpAppOpenSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
if (btn.isPressed.not()) return@setOnCheckedChangeListener
|
||||
putAppNotifyHookOf(it, b)
|
||||
holder.adpAppAllSwitch.isEnabled = b
|
||||
SystemUITool.refreshSystemUI(context = this@ConfigureActivity)
|
||||
}
|
||||
holder.adpAppAllSwitch.isChecked = isAppNotifyHookAllOf(it)
|
||||
holder.adpAppAllSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
if (btn.isPressed.not()) return@setOnCheckedChangeListener
|
||||
putAppNotifyHookAllOf(it, b)
|
||||
SystemUITool.refreshSystemUI(context = this@ConfigureActivity)
|
||||
}
|
||||
}
|
||||
return cView!!
|
||||
}
|
||||
}.apply {
|
||||
setOnItemLongClickListener { _, _, p, _ ->
|
||||
showDialog {
|
||||
title = "复制“${iconDatas[p].appName}”的规则"
|
||||
msg = "是否复制单条规则到剪贴板?"
|
||||
confirmButton { copyToClipboard(iconDatas[p].toString()) }
|
||||
cancelButton()
|
||||
}
|
||||
true
|
||||
}
|
||||
onChanged = { notifyDataSetChanged() }
|
||||
}
|
||||
onScrollEvent = { post { setSelection(if (it) iconDatas.lastIndex else 0) } }
|
||||
}
|
||||
/** 设置点击事件 */
|
||||
binding.configCbrButton.setOnClickListener {
|
||||
openBrowser(url = "https://github.com/fankes/AndroidNotifyIconAdapt/blob/main/CONTRIBUTING.md")
|
||||
}
|
||||
/** 装载数据 */
|
||||
mockLocalData()
|
||||
/** 更新数据 */
|
||||
when {
|
||||
intent?.getBooleanExtra("isNewAppSupport", false) == true ->
|
||||
showDialog {
|
||||
val appName = intent?.getStringExtra("appName") ?: ""
|
||||
val pkgName = intent?.getStringExtra("pkgName") ?: ""
|
||||
title = "新安装应用通知图标适配"
|
||||
msg = "你已安装 $appName($pkgName)\n\n" +
|
||||
"此应用未在通知优化名单中发现适配数据,若此应用发送的通知为彩色图标," +
|
||||
"可随时点击本页面下方的“贡献通知图标优化名单”按钮提交贡献或请求适配。\n\n" +
|
||||
"若你已知晓此应用会遵守原生通知图标规范,可忽略此提示。\n\n" +
|
||||
"你可以现在立即同步适配列表,以获取最新的适配数据。"
|
||||
confirmButton(text = "同步列表") { onStartRefresh() }
|
||||
cancelButton(text = "复制名称+包名") { copyToClipboard(content = "$appName($pkgName)") }
|
||||
neutralButton(text = "取消")
|
||||
noCancelable()
|
||||
}
|
||||
intent?.getBooleanExtra("isShowUpdDialog", true) == true -> onStartRefresh()
|
||||
}
|
||||
/** 清除数据 */
|
||||
intent?.apply {
|
||||
removeExtra("isNewAppSupport")
|
||||
removeExtra("isShowUpdDialog")
|
||||
}
|
||||
}
|
||||
|
||||
/** 开始手动同步 */
|
||||
private fun onStartRefresh() =
|
||||
IconRuleManagerTool.syncByHand(context = this) {
|
||||
filterText = ""
|
||||
mockLocalData()
|
||||
}
|
||||
|
||||
/** 装载或刷新本地数据 */
|
||||
private fun mockLocalData() {
|
||||
iconAllDatas = IconPackParams(context = this).iconDatas
|
||||
refreshAdapterResult()
|
||||
}
|
||||
|
||||
/** 刷新适配器结果相关 */
|
||||
private fun refreshAdapterResult() {
|
||||
onChanged?.invoke()
|
||||
binding.configTitleCountText.text =
|
||||
if (filterText.isBlank()) "已适配 ${iconDatas.size} 个 APP 的通知图标"
|
||||
else "“${filterText}” 匹配到 ${iconDatas.size} 个结果"
|
||||
binding.configListNoDataView.apply {
|
||||
text = if (iconAllDatas.isEmpty()) "噫,竟然什么都没有~\n请点击右上角同步按钮获取云端数据" else "噫,竟然什么都没找到~"
|
||||
isVisible = iconDatas.isEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前结果下的图标数组
|
||||
* @return [Array]
|
||||
*/
|
||||
private val iconDatas
|
||||
get() = if (filterText.isBlank()) iconAllDatas
|
||||
else iconAllDatas.filter {
|
||||
it.appName.lowercase().contains(filterText.lowercase()) || it.packageName.lowercase().contains(filterText.lowercase())
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
if (MainActivity.isActivityLive.not())
|
||||
showDialog {
|
||||
title = "提示"
|
||||
msg = "要返回模块主页吗?"
|
||||
confirmButton {
|
||||
super.onBackPressed()
|
||||
navigate<MainActivity>()
|
||||
}
|
||||
cancelButton { super.onBackPressed() }
|
||||
}
|
||||
else super.onBackPressed()
|
||||
}
|
||||
}
|
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/24.
|
||||
*/
|
||||
@file:Suppress("SetTextI18n")
|
||||
|
||||
package com.fankes.miui.notify.ui.activity
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.pm.PackageManager
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import com.fankes.miui.notify.R
|
||||
import com.fankes.miui.notify.const.Const
|
||||
import com.fankes.miui.notify.data.DataConst
|
||||
import com.fankes.miui.notify.databinding.ActivityMainBinding
|
||||
import com.fankes.miui.notify.databinding.DiaStatusIconCountBinding
|
||||
import com.fankes.miui.notify.params.IconPackParams
|
||||
import com.fankes.miui.notify.ui.activity.base.BaseActivity
|
||||
import com.fankes.miui.notify.utils.factory.*
|
||||
import com.fankes.miui.notify.utils.tool.GithubReleaseTool
|
||||
import com.fankes.miui.notify.utils.tool.SystemUITool
|
||||
import com.highcapable.yukihookapi.hook.factory.isXposedModuleActive
|
||||
import com.highcapable.yukihookapi.hook.factory.modulePrefs
|
||||
import com.highcapable.yukihookapi.hook.xposed.YukiHookModuleStatus
|
||||
|
||||
class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||
|
||||
companion object {
|
||||
|
||||
/** 窗口是否启动 */
|
||||
internal var isActivityLive = false
|
||||
|
||||
/** 模块版本 */
|
||||
private const val moduleVersion = Const.MODULE_VERSION_NAME
|
||||
|
||||
/** 预发布的版本标识 */
|
||||
private const val pendingFlag = ""
|
||||
}
|
||||
|
||||
/** 模块是否可用 */
|
||||
private var isModuleRegular = false
|
||||
|
||||
/** 模块是否有效 */
|
||||
private var isModuleValied = false
|
||||
|
||||
override fun onCreate() {
|
||||
/** 设置可用性 */
|
||||
isActivityLive = true
|
||||
/** 设置文本 */
|
||||
binding.mainTextVersion.text = "模块版本:$moduleVersion $pendingFlag"
|
||||
binding.mainTextMiuiVersion.text = "系统版本:$miuiFullVersion"
|
||||
/** 检查更新 */
|
||||
GithubReleaseTool.checkingForUpdate(context = this, moduleVersion) { version, function ->
|
||||
binding.mainTextReleaseVersion.apply {
|
||||
text = "点击更新 $version"
|
||||
isVisible = true
|
||||
setOnClickListener { function() }
|
||||
}
|
||||
}
|
||||
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 */
|
||||
isXposedModuleActive -> {
|
||||
if (IconPackParams(context = this).iconDatas.isEmpty() && modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX))
|
||||
showDialog {
|
||||
title = "配置通知图标优化名单"
|
||||
msg = "模块需要获取在线规则以更新“通知图标优化名单”,它现在是空的,这看起来是你第一次使用模块,请首先进行配置才可以使用相关功能。\n" +
|
||||
"你可以随时在本页面下方找到“配置通知图标优化名单”手动前往。"
|
||||
confirmButton(text = "前往") { navigate<ConfigureActivity>() }
|
||||
cancelButton()
|
||||
noCancelable()
|
||||
}
|
||||
if (isNotNoificationEnabled && modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX))
|
||||
showDialog {
|
||||
title = "模块的通知权限已关闭"
|
||||
msg = "请开启通知权限,以确保你能收到通知图标优化在线规则的更新。"
|
||||
confirmButton { openNotifySetting() }
|
||||
cancelButton()
|
||||
noCancelable()
|
||||
}
|
||||
}
|
||||
else ->
|
||||
showDialog {
|
||||
title = "模块没有激活"
|
||||
msg = "检测到模块没有激活,模块需要 Xposed 环境依赖," +
|
||||
"同时需要系统拥有 Root 权限," +
|
||||
"请自行查看本页面使用帮助与说明第二条。\n" +
|
||||
"由于需要修改系统应用达到效果,模块不支持太极阴、应用转生。"
|
||||
confirmButton(text = "我知道了")
|
||||
noCancelable()
|
||||
}
|
||||
}
|
||||
var statusBarIconCount = modulePrefs.get(DataConst.HOOK_STATUS_ICON_COUNT)
|
||||
var notifyIconAutoSyncTime = modulePrefs.get(DataConst.NOTIFY_ICON_FIX_AUTO_TIME)
|
||||
binding.colorIconHookItem.isVisible = modulePrefs.get(DataConst.ENABLE_MODULE)
|
||||
binding.statusIconCountItem.isVisible = modulePrefs.get(DataConst.ENABLE_MODULE)
|
||||
binding.notifyIconConfigItem.isVisible = modulePrefs.get(DataConst.ENABLE_MODULE)
|
||||
binding.notifyIconFixButton.isVisible = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX)
|
||||
binding.notifyIconFixNotifyItem.isVisible = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX)
|
||||
binding.notifyIconAutoSyncItem.isVisible = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX)
|
||||
binding.statusIconCountSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_HOOK_STATUS_ICON_COUNT)
|
||||
binding.statusIconCountChildItem.isVisible = modulePrefs.get(DataConst.ENABLE_HOOK_STATUS_ICON_COUNT)
|
||||
binding.notifyIconAutoSyncChildItem.isVisible = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX_AUTO)
|
||||
binding.moduleEnableSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_MODULE)
|
||||
binding.moduleEnableLogSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_MODULE_LOG)
|
||||
binding.hideIconInLauncherSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_HIDE_ICON)
|
||||
binding.colorIconCompatSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_COLOR_ICON_COMPAT)
|
||||
binding.notifyIconFixSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX)
|
||||
binding.notifyIconFixNotifySwitch.isChecked = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX_NOTIFY)
|
||||
binding.notifyIconAutoSyncSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX_AUTO)
|
||||
binding.statusIconCountText.text = statusBarIconCount.toString()
|
||||
binding.notifyIconAutoSyncText.text = notifyIconAutoSyncTime
|
||||
binding.moduleEnableSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
if (btn.isPressed.not()) return@setOnCheckedChangeListener
|
||||
modulePrefs.put(DataConst.ENABLE_MODULE, b)
|
||||
binding.moduleEnableLogSwitch.isVisible = b
|
||||
binding.colorIconHookItem.isVisible = b
|
||||
binding.statusIconCountItem.isVisible = b
|
||||
binding.notifyIconConfigItem.isVisible = b
|
||||
SystemUITool.showNeedRestartSnake(context = this)
|
||||
}
|
||||
binding.moduleEnableLogSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
if (btn.isPressed.not()) return@setOnCheckedChangeListener
|
||||
modulePrefs.put(DataConst.ENABLE_MODULE_LOG, b)
|
||||
SystemUITool.showNeedRestartSnake(context = this)
|
||||
}
|
||||
binding.hideIconInLauncherSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
if (btn.isPressed.not()) return@setOnCheckedChangeListener
|
||||
modulePrefs.put(DataConst.ENABLE_HIDE_ICON, b)
|
||||
packageManager.setComponentEnabledSetting(
|
||||
ComponentName(this@MainActivity, "com.fankes.miui.notify.Home"),
|
||||
if (b) PackageManager.COMPONENT_ENABLED_STATE_DISABLED else PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
|
||||
PackageManager.DONT_KILL_APP
|
||||
)
|
||||
}
|
||||
binding.statusIconCountSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
if (btn.isPressed.not()) return@setOnCheckedChangeListener
|
||||
modulePrefs.put(DataConst.ENABLE_HOOK_STATUS_ICON_COUNT, b)
|
||||
binding.statusIconCountChildItem.isVisible = b
|
||||
SystemUITool.showNeedRestartSnake(context = this)
|
||||
}
|
||||
binding.colorIconCompatSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
if (btn.isPressed.not()) return@setOnCheckedChangeListener
|
||||
modulePrefs.put(DataConst.ENABLE_COLOR_ICON_COMPAT, b)
|
||||
SystemUITool.refreshSystemUI(context = this)
|
||||
}
|
||||
binding.notifyIconFixSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
if (btn.isPressed.not()) return@setOnCheckedChangeListener
|
||||
modulePrefs.put(DataConst.ENABLE_NOTIFY_ICON_FIX, b)
|
||||
binding.notifyIconFixButton.isVisible = b
|
||||
binding.notifyIconFixNotifyItem.isVisible = b
|
||||
binding.notifyIconAutoSyncItem.isVisible = b
|
||||
SystemUITool.refreshSystemUI(context = this)
|
||||
}
|
||||
binding.notifyIconFixNotifySwitch.setOnCheckedChangeListener { btn, b ->
|
||||
if (btn.isPressed.not()) return@setOnCheckedChangeListener
|
||||
modulePrefs.put(DataConst.ENABLE_NOTIFY_ICON_FIX_NOTIFY, b)
|
||||
SystemUITool.refreshSystemUI(context = this, isRefreshCacheOnly = true)
|
||||
}
|
||||
binding.notifyIconAutoSyncSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
if (btn.isPressed.not()) return@setOnCheckedChangeListener
|
||||
modulePrefs.put(DataConst.ENABLE_NOTIFY_ICON_FIX_AUTO, b)
|
||||
binding.notifyIconAutoSyncChildItem.isVisible = b
|
||||
SystemUITool.refreshSystemUI(context = this, isRefreshCacheOnly = true)
|
||||
}
|
||||
/** 通知图标优化名单按钮点击事件 */
|
||||
binding.notifyIconFixButton.setOnClickListener { navigate<ConfigureActivity>() }
|
||||
/** 设置警告 */
|
||||
binding.warnSCountDisTip.isGone = miuiVersionCode > 12.5
|
||||
/** 修改状态栏通知图标个数按钮点击事件 */
|
||||
binding.statusIconCountButton.setOnClickListener {
|
||||
showDialog {
|
||||
title = "设置最多显示的图标个数"
|
||||
val editText = bind<DiaStatusIconCountBinding>().diaStatusIconCountInputEdit.apply {
|
||||
requestFocus()
|
||||
invalidate()
|
||||
setText(statusBarIconCount.toString())
|
||||
setSelection(statusBarIconCount.toString().length)
|
||||
}
|
||||
confirmButton {
|
||||
when {
|
||||
(runCatching { editText.text.toString().toInt() }.getOrNull() ?: -1)
|
||||
!in 0..100 -> snake(msg = "请输入有效数值")
|
||||
editText.text.toString().isNotBlank() -> runCatching {
|
||||
statusBarIconCount = editText.text.toString().trim().toInt()
|
||||
modulePrefs.put(DataConst.HOOK_STATUS_ICON_COUNT, statusBarIconCount)
|
||||
binding.statusIconCountText.text = statusBarIconCount.toString()
|
||||
SystemUITool.showNeedRestartSnake(context)
|
||||
}.onFailure { snake(msg = "数值格式无效") }
|
||||
else -> snake(msg = "请输入有效数值")
|
||||
}
|
||||
}
|
||||
cancelButton()
|
||||
}
|
||||
}
|
||||
/** 自动更新在线规则修改时间按钮点击事件 */
|
||||
binding.notifyIconAutoSyncButton.setOnClickListener {
|
||||
showTimePicker(notifyIconAutoSyncTime) {
|
||||
showDialog {
|
||||
title = "每天 $it 自动更新"
|
||||
msg = "设置保存后将在每天 $it 自动同步名单到最新云端数据,若数据已是最新则不会显示任何提示,否则会发送一条通知。\n\n" +
|
||||
"请确保:\n\n" +
|
||||
"1.模块没有被禁止前台以及后台联网权限\n" +
|
||||
"2.模块没有被禁止被其它 APP 关联唤醒\n" +
|
||||
"3.模块的系统通知权限已开启\n\n" +
|
||||
"模块无需保持在后台运行,到达同步时间后会自动启动,如果到达时间后模块正在运行则会自动取消本次计划任务。"
|
||||
confirmButton(text = "保存设置") {
|
||||
notifyIconAutoSyncTime = it
|
||||
binding.notifyIconAutoSyncText.text = it
|
||||
modulePrefs.put(DataConst.NOTIFY_ICON_FIX_AUTO_TIME, it)
|
||||
SystemUITool.refreshSystemUI(context, isRefreshCacheOnly = true)
|
||||
}
|
||||
cancelButton()
|
||||
noCancelable()
|
||||
}
|
||||
}
|
||||
}
|
||||
/** 重启按钮点击事件 */
|
||||
binding.titleRestartIcon.setOnClickListener { SystemUITool.restartSystemUI(context = this) }
|
||||
/** 项目地址按钮点击事件 */
|
||||
binding.titleGithubIcon.setOnClickListener { openBrowser(url = "https://github.com/fankes/MIUINativeNotifyIcon") }
|
||||
/** 恰饭! */
|
||||
binding.linkWithFollowMe.setOnClickListener {
|
||||
openBrowser(url = "https://www.coolapk.com/u/876977", packageName = "com.coolapk.market")
|
||||
}
|
||||
}
|
||||
|
||||
/** 刷新模块状态 */
|
||||
private fun refreshModuleStatus() {
|
||||
binding.mainLinStatus.setBackgroundResource(
|
||||
when {
|
||||
isXposedModuleActive && (isModuleRegular.not() || isModuleValied.not()) -> R.drawable.bg_yellow_round
|
||||
isXposedModuleActive -> R.drawable.bg_green_round
|
||||
else -> R.drawable.bg_dark_round
|
||||
}
|
||||
)
|
||||
binding.mainImgStatus.setImageResource(
|
||||
when {
|
||||
isXposedModuleActive -> R.mipmap.ic_success
|
||||
else -> R.mipmap.ic_warn
|
||||
}
|
||||
)
|
||||
binding.mainTextStatus.text =
|
||||
when {
|
||||
isXposedModuleActive && isModuleRegular.not() && modulePrefs.get(DataConst.ENABLE_MODULE).not() -> "模块已停用"
|
||||
isXposedModuleActive && isModuleRegular.not() -> "模块已激活,请重启系统界面"
|
||||
isXposedModuleActive && isModuleValied.not() -> "模块已更新,请重启系统界面"
|
||||
isXposedModuleActive -> "模块已激活"
|
||||
else -> "模块未激活"
|
||||
}
|
||||
binding.mainTextApiWay.isVisible = isXposedModuleActive
|
||||
binding.mainTextApiWay.text = "Activated by ${YukiHookModuleStatus.executorName} API ${YukiHookModuleStatus.executorVersion}"
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
/** 刷新模块状态 */
|
||||
refreshModuleStatus()
|
||||
/** 发送广播检查模块激活状态 */
|
||||
SystemUITool.checkingActivated(context = this) { isRegular, isValied ->
|
||||
isModuleRegular = isRegular
|
||||
isModuleValied = isValied
|
||||
refreshModuleStatus()
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/3/26.
|
||||
*/
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package com.fankes.miui.notify.ui.activity.auto
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import com.fankes.miui.notify.application.MNNApplication.Companion.appContext
|
||||
import com.fankes.miui.notify.ui.activity.base.BaseActivity
|
||||
import com.fankes.miui.notify.utils.factory.delayedRun
|
||||
import com.fankes.miui.notify.utils.tool.IconRuleManagerTool
|
||||
import com.fankes.miui.notify.utils.tool.SystemUITool
|
||||
|
||||
class NotifyIconRuleUpdateActivity : Activity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
/** 设置透明窗口 */
|
||||
window?.decorView?.systemUiVisibility =
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
window?.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
|
||||
window?.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
|
||||
/** 检测运行状态 */
|
||||
if (BaseActivity.isMainThreadRunning) {
|
||||
finish()
|
||||
return
|
||||
}
|
||||
/** 注册 */
|
||||
SystemUITool.register(context = this)
|
||||
/** 拉取云端数据 */
|
||||
IconRuleManagerTool.sync(appContext) {
|
||||
/** 刷新系统界面 */
|
||||
SystemUITool.refreshSystemUI()
|
||||
/** 结束当前窗口 */
|
||||
runOnUiThread { delayedRun(ms = 1000) { finish() } }
|
||||
}
|
||||
/** 切换到后台 */
|
||||
moveTaskToBack(true)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
/** 解除注册 */
|
||||
SystemUITool.unregister(context = this)
|
||||
}
|
||||
}
|
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/30.
|
||||
*/
|
||||
@file:Suppress("UNCHECKED_CAST")
|
||||
|
||||
package com.fankes.miui.notify.ui.activity.base
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.fankes.miui.notify.R
|
||||
import com.fankes.miui.notify.utils.factory.isNotSystemInDarkMode
|
||||
import com.fankes.miui.notify.utils.tool.SystemUITool
|
||||
import com.gyf.immersionbar.ktx.immersionBar
|
||||
import com.highcapable.yukihookapi.hook.factory.method
|
||||
import com.highcapable.yukihookapi.hook.type.android.LayoutInflaterClass
|
||||
import java.lang.reflect.ParameterizedType
|
||||
|
||||
abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
||||
|
||||
companion object {
|
||||
|
||||
/** 应用是否正在运行 */
|
||||
var isMainThreadRunning = false
|
||||
}
|
||||
|
||||
/** 获取绑定布局对象 */
|
||||
lateinit var binding: VB
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
isMainThreadRunning = true
|
||||
javaClass.genericSuperclass.also { type ->
|
||||
if (type is ParameterizedType) {
|
||||
binding = (type.actualTypeArguments[0] as Class<VB>).method {
|
||||
name = "inflate"
|
||||
param(LayoutInflaterClass)
|
||||
}.get().invoke<VB>(layoutInflater) ?: error("binding failed")
|
||||
setContentView(binding.root)
|
||||
} else error("binding but got wrong type")
|
||||
}
|
||||
/** 隐藏系统的标题栏 */
|
||||
supportActionBar?.hide()
|
||||
/** 初始化沉浸状态栏 */
|
||||
immersionBar {
|
||||
statusBarColor(R.color.colorThemeBackground)
|
||||
autoDarkModeEnable(true)
|
||||
statusBarDarkFont(isNotSystemInDarkMode)
|
||||
navigationBarColor(R.color.colorThemeBackground)
|
||||
navigationBarDarkIcon(isNotSystemInDarkMode)
|
||||
fitsSystemWindows(true)
|
||||
}
|
||||
/** 注册 */
|
||||
SystemUITool.register(context = this)
|
||||
/** 装载子类 */
|
||||
onCreate()
|
||||
}
|
||||
|
||||
/** 回调 [onCreate] 方法 */
|
||||
abstract fun onCreate()
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
/** 解除注册 */
|
||||
SystemUITool.unregister(context = this)
|
||||
}
|
||||
}
|
@@ -1,66 +0,0 @@
|
||||
/**
|
||||
* 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()
|
||||
}
|
||||
}
|
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/8.
|
||||
*/
|
||||
@file:Suppress("SameParameterValue")
|
||||
|
||||
package com.fankes.miui.notify.ui.view
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Color
|
||||
import android.text.TextUtils
|
||||
import android.util.AttributeSet
|
||||
import androidx.appcompat.widget.SwitchCompat
|
||||
import com.fankes.miui.notify.utils.drawable.drawabletoolbox.DrawableBuilder
|
||||
import com.fankes.miui.notify.utils.factory.dp
|
||||
import com.fankes.miui.notify.utils.factory.isSystemInDarkMode
|
||||
|
||||
class MaterialSwitch(context: Context, attrs: AttributeSet?) : SwitchCompat(context, attrs) {
|
||||
|
||||
private fun toColors(selected: Int, pressed: Int, normal: Int): ColorStateList {
|
||||
val colors = intArrayOf(selected, pressed, normal)
|
||||
val states = arrayOfNulls<IntArray>(3)
|
||||
states[0] = intArrayOf(android.R.attr.state_checked)
|
||||
states[1] = intArrayOf(android.R.attr.state_pressed)
|
||||
states[2] = intArrayOf()
|
||||
return ColorStateList(states, colors)
|
||||
}
|
||||
|
||||
private val thumbColor get() = if (context.isSystemInDarkMode) 0xFF7C7C7C else 0xFFCCCCCC
|
||||
|
||||
init {
|
||||
trackDrawable = DrawableBuilder()
|
||||
.rectangle()
|
||||
.rounded()
|
||||
.solidColor(0xFF656565.toInt())
|
||||
.height(20.dp(context))
|
||||
.cornerRadius(15.dp(context))
|
||||
.build()
|
||||
thumbDrawable = DrawableBuilder()
|
||||
.rectangle()
|
||||
.rounded()
|
||||
.solidColor(Color.WHITE)
|
||||
.size(20.dp(context), 20.dp(context))
|
||||
.cornerRadius(20.dp(context))
|
||||
.strokeWidth(8.dp(context))
|
||||
.strokeColor(Color.TRANSPARENT)
|
||||
.build()
|
||||
trackTintList = toColors(
|
||||
0xFF656565.toInt(),
|
||||
thumbColor.toInt(),
|
||||
thumbColor.toInt()
|
||||
)
|
||||
isSingleLine = true
|
||||
ellipsize = TextUtils.TruncateAt.END
|
||||
}
|
||||
}
|
@@ -1,101 +0,0 @@
|
||||
/**
|
||||
* 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/7.
|
||||
*/
|
||||
@file:Suppress("unused")
|
||||
|
||||
package com.fankes.miui.notify.utils
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
|
||||
|
||||
/**
|
||||
* 构造对话框
|
||||
* @param it 对话框方法体
|
||||
*/
|
||||
fun Context.showDialog(it: DialogBuilder.() -> Unit) = DialogBuilder(this).apply(it).show()
|
||||
|
||||
/**
|
||||
* 对话框构造器
|
||||
* @param context 实例
|
||||
*/
|
||||
class DialogBuilder(private val context: Context) {
|
||||
|
||||
private var instance: AlertDialog.Builder? = null // 实例对象
|
||||
|
||||
init {
|
||||
instance = AlertDialog.Builder(context, android.R.style.Theme_Material_Light_Dialog)
|
||||
}
|
||||
|
||||
/** 设置对话框不可关闭 */
|
||||
fun noCancelable() = instance?.setCancelable(false)
|
||||
|
||||
/** 设置对话框标题 */
|
||||
var title
|
||||
get() = ""
|
||||
set(value) {
|
||||
instance?.setTitle(value)
|
||||
}
|
||||
|
||||
/** 设置对话框消息内容 */
|
||||
var msg
|
||||
get() = ""
|
||||
set(value) {
|
||||
instance?.setMessage(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置对话框确定按钮
|
||||
* @param text 按钮文本内容
|
||||
* @param it 点击事件
|
||||
*/
|
||||
fun confirmButton(text: String = "确定", it: () -> Unit = {}) =
|
||||
instance?.setPositiveButton(text) { _, _ -> it() }
|
||||
|
||||
/**
|
||||
* 设置对话框取消按钮
|
||||
* @param text 按钮文本内容
|
||||
* @param it 点击事件
|
||||
*/
|
||||
fun cancelButton(text: String = "取消", it: () -> Unit = {}) =
|
||||
instance?.setNegativeButton(text) { _, _ -> it() }
|
||||
|
||||
/**
|
||||
* 设置对话框第三个按钮
|
||||
* @param text 按钮文本内容
|
||||
* @param it 点击事件
|
||||
*/
|
||||
fun neutralButton(text: String = "更多", it: () -> Unit = {}) =
|
||||
instance?.setNeutralButton(text) { _, _ -> it() }
|
||||
|
||||
/** 显示对话框 */
|
||||
internal fun show() = instance?.create()?.apply {
|
||||
window?.setBackgroundDrawable(GradientDrawable(
|
||||
GradientDrawable.Orientation.TOP_BOTTOM,
|
||||
intArrayOf(Color.WHITE, Color.WHITE)
|
||||
).apply {
|
||||
shape = GradientDrawable.RECTANGLE
|
||||
gradientType = GradientDrawable.LINEAR_GRADIENT
|
||||
cornerRadius = 15.dp(this@DialogBuilder.context)
|
||||
})
|
||||
}?.show()
|
||||
}
|
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* 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 zpp0196 on 2019/2/9.
|
||||
*/
|
||||
package com.fankes.miui.notify.utils;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.fankes.miui.notify.BuildConfig;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
@SuppressWarnings("ALL")
|
||||
public class FileUtils {
|
||||
|
||||
private static final String FILE_PREF_NAME = BuildConfig.APPLICATION_ID + "_preferences.xml";
|
||||
|
||||
public static boolean copyFile(File srcFile, File targetFile) {
|
||||
FileInputStream ins = null;
|
||||
FileOutputStream out = null;
|
||||
try {
|
||||
if (targetFile.exists()) {
|
||||
targetFile.delete();
|
||||
}
|
||||
File targetParent = targetFile.getParentFile();
|
||||
if (!targetParent.exists()) {
|
||||
targetParent.mkdirs();
|
||||
}
|
||||
targetFile.createNewFile();
|
||||
ins = new FileInputStream(srcFile);
|
||||
out = new FileOutputStream(targetFile);
|
||||
byte[] b = new byte[1024];
|
||||
int n;
|
||||
while ((n = ins.read(b)) != -1) {
|
||||
out.write(b, 0, n);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
} finally {
|
||||
try {
|
||||
if (ins != null) {
|
||||
ins.close();
|
||||
}
|
||||
if (out != null) {
|
||||
out.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static File getDataDir(Context context) {
|
||||
return new File(context.getApplicationInfo().dataDir);
|
||||
}
|
||||
|
||||
public static File getPrefDir(Context context) {
|
||||
return new File(getDataDir(context), "shared_prefs");
|
||||
}
|
||||
|
||||
public static File getDefaultPrefFile(Context context) {
|
||||
return new File(getPrefDir(context), FILE_PREF_NAME);
|
||||
}
|
||||
}
|
@@ -1,295 +0,0 @@
|
||||
/**
|
||||
* 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/7.
|
||||
*/
|
||||
@file:Suppress("DEPRECATION", "PrivateApi", "unused")
|
||||
|
||||
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.provider.Settings
|
||||
import android.service.notification.StatusBarNotification
|
||||
import android.util.Base64
|
||||
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
|
||||
|
||||
/**
|
||||
* 通知栏是否为 MIUI 样式
|
||||
* @return [Boolean] 是否符合条件
|
||||
*/
|
||||
val Context.isMiuiNotifyStyle
|
||||
get() = try {
|
||||
Settings.System.getInt(contentResolver, "status_bar_notification_style") == 0
|
||||
} catch (_: Throwable) {
|
||||
false
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统深色模式是否没开启
|
||||
* @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 系统
|
||||
* @return [Boolean] 是否符合条件
|
||||
*/
|
||||
val isMIUI by lazy {
|
||||
try {
|
||||
Class.forName("android.miui.R")
|
||||
true
|
||||
} catch (_: Exception) {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前设备是否不是 MIUI 定制 Android 系统
|
||||
* @return [Boolean] 是否符合条件
|
||||
*/
|
||||
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]
|
||||
*/
|
||||
val Context.packageInfo get() = packageManager?.getPackageInfo(packageName, 0) ?: PackageInfo()
|
||||
|
||||
/**
|
||||
* 判断应用是否安装
|
||||
* @return [Boolean]
|
||||
*/
|
||||
val String.isInstall
|
||||
get() =
|
||||
try {
|
||||
appContext.packageManager.getPackageInfo(
|
||||
this,
|
||||
PackageManager.GET_UNINSTALLED_PACKAGES
|
||||
)
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到版本信息
|
||||
* @return [String]
|
||||
*/
|
||||
val Context.versionName get() = packageInfo.versionName ?: ""
|
||||
|
||||
/**
|
||||
* 得到版本号
|
||||
* @return [Int]
|
||||
*/
|
||||
val Context.versionCode get() = packageInfo.versionCode
|
||||
|
||||
/**
|
||||
* dp 转换为 px
|
||||
* @return [Int]
|
||||
*/
|
||||
val Number.dp get() = (toFloat() * appContext.resources.displayMetrics.density).toInt()
|
||||
|
||||
/**
|
||||
* dp 转换为 px
|
||||
* @param context 使用的实例
|
||||
* @return [Float]
|
||||
*/
|
||||
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]
|
||||
*/
|
||||
val String.unbase64 get() = Base64.decode(this, Base64.DEFAULT) ?: ByteArray(0)
|
||||
|
||||
/**
|
||||
* 字节流解析为位图
|
||||
* @return [Bitmap]
|
||||
*/
|
||||
val ByteArray.bitmap: Bitmap get() = BitmapFactory.decodeByteArray(this, 0, size)
|
||||
|
||||
/**
|
||||
* 字符串解析为位图
|
||||
* @return [Bitmap]
|
||||
*/
|
||||
val String.bitmap: Bitmap get() = unbase64.bitmap
|
||||
|
||||
/**
|
||||
* 圆角图片
|
||||
* @param radius 圆角度
|
||||
* @return [Bitmap] 圆角后的位图 - 失败会返回处理之前的位图
|
||||
*/
|
||||
fun Bitmap.round(radius: Float): Bitmap =
|
||||
createBitmap(width, height, Bitmap.Config.ARGB_8888).also { out ->
|
||||
Canvas(out).also { canvas ->
|
||||
Paint().also { paint ->
|
||||
paint.isAntiAlias = true
|
||||
canvas.drawARGB(0, 0, 0, 0)
|
||||
paint.color = Color.WHITE
|
||||
canvas.drawRoundRect(RectF(Rect(0, 0, width, height)), radius, radius, paint)
|
||||
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
|
||||
canvas.drawBitmap(this, Rect(0, 0, width, height), Rect(0, 0, width, height), paint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统 Prop 值
|
||||
* @param key Key
|
||||
* @param default 默认值
|
||||
* @return [String]
|
||||
*/
|
||||
fun findPropString(key: String, default: String = "") =
|
||||
try {
|
||||
(Class.forName("android.os.SystemProperties").getDeclaredMethod(
|
||||
"get",
|
||||
String::class.java,
|
||||
String::class.java
|
||||
).apply { isAccessible = true }.invoke(null, key, default)) as? String? ?: default
|
||||
} catch (_: Exception) {
|
||||
default
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行命令 - su
|
||||
* @param cmd 命令
|
||||
* @return [String] 执行结果
|
||||
*/
|
||||
fun execShellCmd(cmd: String): String {
|
||||
var result = ""
|
||||
var dos: DataOutputStream? = null
|
||||
var dis: DataInputStream? = null
|
||||
try {
|
||||
val p = Runtime.getRuntime().exec("su")
|
||||
dos = DataOutputStream(p.outputStream)
|
||||
dis = DataInputStream(p.inputStream)
|
||||
dos.writeBytes("$cmd\n")
|
||||
dos.flush()
|
||||
dos.writeBytes("exit\n")
|
||||
dos.flush()
|
||||
var line: String
|
||||
while (dis.readLine().also { line = it } != null) result += line
|
||||
p.waitFor()
|
||||
} catch (_: Exception) {
|
||||
} finally {
|
||||
try {
|
||||
dos?.close()
|
||||
dis?.close()
|
||||
} catch (_: Exception) {
|
||||
}
|
||||
}
|
||||
return result.trim()
|
||||
}
|
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* 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 zpp0196 on 2018/4/11.
|
||||
*/
|
||||
package com.fankes.miui.notify.utils
|
||||
|
||||
import com.fankes.miui.notify.BuildConfig
|
||||
import de.robv.android.xposed.XSharedPreferences
|
||||
|
||||
object XPrefUtils {
|
||||
|
||||
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() {
|
||||
val preferences = XSharedPreferences(BuildConfig.APPLICATION_ID)
|
||||
preferences.makeWorldReadable()
|
||||
preferences.reload()
|
||||
return preferences
|
||||
}
|
||||
}
|
@@ -1,20 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This file is part of MIUINativeNotifyIcon.
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* 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,
|
||||
* This software 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.
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/8.
|
||||
*/
|
||||
|
@@ -1,24 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This file is part of MIUINativeNotifyIcon.
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* 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,
|
||||
* This software 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.
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/8.
|
||||
*/
|
||||
|
||||
package com.fankes.miui.notify.utils.drawable.drawabletoolbox
|
||||
|
||||
class Constants {
|
||||
|
@@ -1,20 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This file is part of MIUINativeNotifyIcon.
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* 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,
|
||||
* This software 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.
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/8.
|
||||
*/
|
||||
|
@@ -1,20 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This file is part of MIUINativeNotifyIcon.
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* 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,
|
||||
* This software 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.
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/8.
|
||||
*/
|
||||
|
@@ -1,20 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This file is part of MIUINativeNotifyIcon.
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* 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,
|
||||
* This software 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.
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/8.
|
||||
*/
|
||||
|
@@ -1,20 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This file is part of MIUINativeNotifyIcon.
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* 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,
|
||||
* This software 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.
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/8.
|
||||
*/
|
||||
|
@@ -1,20 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This file is part of MIUINativeNotifyIcon.
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* 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,
|
||||
* This software 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.
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/8.
|
||||
*/
|
||||
|
@@ -1,20 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This file is part of MIUINativeNotifyIcon.
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* 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,
|
||||
* This software 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.
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/8.
|
||||
*/
|
||||
|
@@ -1,20 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This file is part of MIUINativeNotifyIcon.
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* 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,
|
||||
* This software 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.
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/8.
|
||||
*/
|
||||
|
@@ -1,20 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This file is part of MIUINativeNotifyIcon.
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* 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,
|
||||
* This software 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.
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/8.
|
||||
*/
|
||||
|
@@ -1,20 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This file is part of MIUINativeNotifyIcon.
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* 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,
|
||||
* This software 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.
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/8.
|
||||
*/
|
||||
|
@@ -1,20 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This file is part of MIUINativeNotifyIcon.
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* 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,
|
||||
* This software 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.
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/8.
|
||||
*/
|
||||
|
@@ -1,20 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2022. Fankes Studio(qzmmcn@163.com)
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This file is part of MIUINativeNotifyIcon.
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* 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,
|
||||
* This software 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.
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Affero 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/>.
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/8.
|
||||
*/
|
||||
|
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/7.
|
||||
*/
|
||||
@file:Suppress("unused", "OPT_IN_USAGE", "EXPERIMENTAL_API_USAGE")
|
||||
|
||||
package com.fankes.miui.notify.utils.factory
|
||||
|
||||
import android.app.Dialog
|
||||
import android.app.TimePickerDialog
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.highcapable.yukihookapi.annotation.CauseProblemsApi
|
||||
import com.highcapable.yukihookapi.hook.factory.method
|
||||
import com.highcapable.yukihookapi.hook.type.android.LayoutInflaterClass
|
||||
|
||||
/**
|
||||
* 构造对话框
|
||||
* @param isUseBlackTheme 是否使用深色主题
|
||||
* @param it 对话框方法体
|
||||
*/
|
||||
fun Context.showDialog(isUseBlackTheme: Boolean = false, it: DialogBuilder.() -> Unit) =
|
||||
DialogBuilder(this, isUseBlackTheme).apply(it).show()
|
||||
|
||||
/**
|
||||
* 显示时间选择对话框
|
||||
* @param timeSet 当前时间 - 不写将使用当前时间格式:HH:mm
|
||||
* @param it 回调 - 小时与分钟 HH:mm
|
||||
*/
|
||||
fun Context.showTimePicker(timeSet: String = "", it: (String) -> Unit) =
|
||||
TimePickerDialog(this, { _, h, m -> it("${h.autoZero}:${m.autoZero}") }, timeSet.hour, timeSet.minute, true).show()
|
||||
|
||||
/**
|
||||
* 对话框构造器
|
||||
* @param context 实例
|
||||
* @param isUseBlackTheme 是否使用深色主题 - 对 AndroidX 风格无效
|
||||
*/
|
||||
class DialogBuilder(val context: Context, private val isUseBlackTheme: Boolean) {
|
||||
|
||||
private var instanceAndroidX: androidx.appcompat.app.AlertDialog.Builder? = null // 实例对象
|
||||
private var instanceAndroid: android.app.AlertDialog.Builder? = null // 实例对象
|
||||
|
||||
private var dialogInstance: Dialog? = null // 对话框实例
|
||||
|
||||
@CauseProblemsApi
|
||||
var customLayoutView: View? = null // 自定义布局
|
||||
|
||||
/**
|
||||
* 是否需要使用 AndroidX 风格对话框
|
||||
* @return [Boolean]
|
||||
*/
|
||||
private val isUsingAndroidX get() = runCatching { context is AppCompatActivity }.getOrNull() ?: false
|
||||
|
||||
init {
|
||||
if (isUsingAndroidX)
|
||||
runInSafe { instanceAndroidX = MaterialAlertDialogBuilder(context) }
|
||||
else runInSafe {
|
||||
instanceAndroid = android.app.AlertDialog.Builder(
|
||||
context,
|
||||
if (isUseBlackTheme) android.R.style.Theme_Material_Dialog else android.R.style.Theme_Material_Light_Dialog
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** 设置对话框不可关闭 */
|
||||
fun noCancelable() {
|
||||
if (isUsingAndroidX)
|
||||
runInSafe { instanceAndroidX?.setCancelable(false) }
|
||||
else runInSafe { instanceAndroid?.setCancelable(false) }
|
||||
}
|
||||
|
||||
/** 设置对话框标题 */
|
||||
var title
|
||||
get() = ""
|
||||
set(value) {
|
||||
if (isUsingAndroidX)
|
||||
runInSafe { instanceAndroidX?.setTitle(value) }
|
||||
else runInSafe { instanceAndroid?.setTitle(value) }
|
||||
}
|
||||
|
||||
/** 设置对话框消息内容 */
|
||||
var msg
|
||||
get() = ""
|
||||
set(value) {
|
||||
if (isUsingAndroidX)
|
||||
runInSafe { instanceAndroidX?.setMessage(value) }
|
||||
else runInSafe { instanceAndroid?.setMessage(value) }
|
||||
}
|
||||
|
||||
/** 设置进度条对话框消息内容 */
|
||||
var progressContent
|
||||
get() = ""
|
||||
set(value) {
|
||||
if (customLayoutView == null)
|
||||
customLayoutView = LinearLayout(context).apply {
|
||||
orientation = LinearLayout.HORIZONTAL
|
||||
gravity = Gravity.CENTER or Gravity.START
|
||||
addView(ProgressBar(context))
|
||||
addView(View(context).apply { layoutParams = ViewGroup.LayoutParams(20.dp(context), 5) })
|
||||
addView(TextView(context).apply {
|
||||
tag = "progressContent"
|
||||
text = value
|
||||
})
|
||||
setPadding(20.dp(context), 20.dp(context), 20.dp(context), 20.dp(context))
|
||||
}
|
||||
else customLayoutView?.findViewWithTag<TextView>("progressContent")?.text = value
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置对话框自定义布局
|
||||
* @return [ViewBinding]
|
||||
*/
|
||||
inline fun <reified T : ViewBinding> bind() =
|
||||
T::class.java.method {
|
||||
name = "inflate"
|
||||
param(LayoutInflaterClass)
|
||||
}.get().invoke<T>(LayoutInflater.from(context))?.apply {
|
||||
customLayoutView = root
|
||||
} ?: error("binding failed")
|
||||
|
||||
/**
|
||||
* 设置对话框确定按钮
|
||||
* @param text 按钮文本内容
|
||||
* @param it 点击事件
|
||||
*/
|
||||
fun confirmButton(text: String = "确定", it: () -> Unit = {}) {
|
||||
if (isUsingAndroidX)
|
||||
runInSafe { instanceAndroidX?.setPositiveButton(text) { _, _ -> it() } }
|
||||
else runInSafe { instanceAndroid?.setPositiveButton(text) { _, _ -> it() } }
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置对话框取消按钮
|
||||
* @param text 按钮文本内容
|
||||
* @param it 点击事件
|
||||
*/
|
||||
fun cancelButton(text: String = "取消", it: () -> Unit = {}) {
|
||||
if (isUsingAndroidX)
|
||||
runInSafe { instanceAndroidX?.setNegativeButton(text) { _, _ -> it() } }
|
||||
else runInSafe { instanceAndroid?.setNegativeButton(text) { _, _ -> it() } }
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置对话框第三个按钮
|
||||
* @param text 按钮文本内容
|
||||
* @param it 点击事件
|
||||
*/
|
||||
fun neutralButton(text: String = "更多", it: () -> Unit = {}) {
|
||||
if (isUsingAndroidX)
|
||||
runInSafe { instanceAndroidX?.setNeutralButton(text) { _, _ -> it() } }
|
||||
else runInSafe { instanceAndroid?.setNeutralButton(text) { _, _ -> it() } }
|
||||
}
|
||||
|
||||
/** 取消对话框 */
|
||||
fun cancel() = dialogInstance?.cancel()
|
||||
|
||||
/** 显示对话框 */
|
||||
internal fun show() =
|
||||
if (isUsingAndroidX) runInSafe {
|
||||
instanceAndroidX?.create()?.apply {
|
||||
customLayoutView?.let { setView(it) }
|
||||
dialogInstance = this
|
||||
}?.show()
|
||||
} else runInSafe {
|
||||
instanceAndroid?.create()?.apply {
|
||||
customLayoutView?.let { setView(it) }
|
||||
window?.setBackgroundDrawable(
|
||||
GradientDrawable(
|
||||
GradientDrawable.Orientation.TOP_BOTTOM,
|
||||
if (isUseBlackTheme) intArrayOf(0xFF2D2D2D.toInt(), 0xFF2D2D2D.toInt())
|
||||
else intArrayOf(Color.WHITE, Color.WHITE)
|
||||
).apply {
|
||||
shape = GradientDrawable.RECTANGLE
|
||||
gradientType = GradientDrawable.LINEAR_GRADIENT
|
||||
cornerRadius = 15.dpFloat(this@DialogBuilder.context)
|
||||
})
|
||||
dialogInstance = this
|
||||
}?.show()
|
||||
}
|
||||
}
|
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/3/13.
|
||||
*/
|
||||
@file:Suppress("unused")
|
||||
|
||||
package com.fankes.miui.notify.utils.factory
|
||||
|
||||
import com.highcapable.yukihookapi.hook.log.loggerE
|
||||
|
||||
/**
|
||||
* 忽略异常返回值
|
||||
* @param result 回调 - 如果异常为空
|
||||
* @return [T] 发生异常时返回设定值否则返回正常值
|
||||
*/
|
||||
inline fun <T> safeOfNull(result: () -> T): T? = safeOf(default = null, result)
|
||||
|
||||
/**
|
||||
* 忽略异常返回值
|
||||
* @param result 回调 - 如果异常为 false
|
||||
* @return [Boolean] 发生异常时返回设定值否则返回正常值
|
||||
*/
|
||||
inline fun safeOfFalse(result: () -> Boolean) = safeOf(default = false, result)
|
||||
|
||||
/**
|
||||
* 忽略异常返回值
|
||||
* @param result 回调 - 如果异常为 true
|
||||
* @return [Boolean] 发生异常时返回设定值否则返回正常值
|
||||
*/
|
||||
inline fun safeOfTrue(result: () -> Boolean) = safeOf(default = true, result)
|
||||
|
||||
/**
|
||||
* 忽略异常返回值
|
||||
* @param result 回调 - 如果异常为 false
|
||||
* @return [String] 发生异常时返回设定值否则返回正常值
|
||||
*/
|
||||
inline fun safeOfNothing(result: () -> String) = safeOf(default = "", result)
|
||||
|
||||
/**
|
||||
* 忽略异常返回值
|
||||
* @param result 回调 - 如果异常为 false
|
||||
* @return [Int] 发生异常时返回设定值否则返回正常值
|
||||
*/
|
||||
inline fun safeOfNan(result: () -> Int) = safeOf(default = 0, result)
|
||||
|
||||
/**
|
||||
* 忽略异常返回值
|
||||
* @param default 异常返回值
|
||||
* @param result 正常回调值
|
||||
* @return [T] 发生异常时返回设定值否则返回正常值
|
||||
*/
|
||||
inline fun <T> safeOf(default: T, result: () -> T) = try {
|
||||
result()
|
||||
} catch (_: Throwable) {
|
||||
default
|
||||
}
|
||||
|
||||
/**
|
||||
* 忽略异常运行
|
||||
* @param msg 出错输出的消息 - 默认为空
|
||||
* @param block 正常回调
|
||||
*/
|
||||
inline fun <T> T.runInSafe(msg: String = "", block: () -> Unit) {
|
||||
runCatching(block).onFailure { if (msg.isNotBlank()) loggerE(msg = msg, e = it) }
|
||||
}
|
@@ -0,0 +1,519 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/1/7.
|
||||
*/
|
||||
@file:Suppress("DEPRECATION", "PrivateApi", "unused", "ObsoleteSdkInt")
|
||||
|
||||
package com.fankes.miui.notify.utils.factory
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Notification
|
||||
import android.app.Service
|
||||
import android.app.WallpaperManager
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.*
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import android.provider.Settings
|
||||
import android.util.Base64
|
||||
import android.widget.Toast
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.content.getSystemService
|
||||
import com.fankes.miui.notify.application.MNNApplication.Companion.appContext
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.highcapable.yukihookapi.hook.factory.classOf
|
||||
import com.highcapable.yukihookapi.hook.factory.hasClass
|
||||
import com.highcapable.yukihookapi.hook.factory.method
|
||||
import com.highcapable.yukihookapi.hook.type.java.StringType
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* 系统深色模式是否开启
|
||||
* @return [Boolean] 是否开启
|
||||
*/
|
||||
val isSystemInDarkMode get() = appContext.isSystemInDarkMode
|
||||
|
||||
/**
|
||||
* 系统深色模式是否没开启
|
||||
* @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 系统
|
||||
* @return [Boolean] 是否符合条件
|
||||
*/
|
||||
val isMIUI by lazy { ("android.miui.R").hasClass }
|
||||
|
||||
/**
|
||||
* 当前设备是否不是 MIUI 定制 Android 系统
|
||||
* @return [Boolean] 是否符合条件
|
||||
*/
|
||||
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 [Float]
|
||||
*/
|
||||
val miuiVersionCode get() = safeOf(default = 0f) { miuiVersion.toFloat() }
|
||||
|
||||
/**
|
||||
* 获取 MIUI 次版本号
|
||||
* @return [String]
|
||||
*/
|
||||
val miuiIncrementalVersion get() = findPropString(key = "ro.system.build.version.incremental").trim()
|
||||
|
||||
/**
|
||||
* 获取 MIUI 完全版本
|
||||
* @return [String]
|
||||
*/
|
||||
val miuiFullVersion
|
||||
get() = if (isMIUI) miuiIncrementalVersion.let {
|
||||
if (it.lowercase().contains("a") ||
|
||||
it.lowercase().contains("b") ||
|
||||
it.lowercase().contains("c") ||
|
||||
it.lowercase().contains("d") ||
|
||||
it.lowercase().contains("e") ||
|
||||
it.lowercase().contains("f") ||
|
||||
it.lowercase().contains("g") ||
|
||||
it.lowercase().contains("h") ||
|
||||
it.lowercase().contains("i") ||
|
||||
it.lowercase().contains("j") ||
|
||||
it.lowercase().contains("k") ||
|
||||
it.lowercase().contains("l") ||
|
||||
it.lowercase().contains("m") ||
|
||||
it.lowercase().contains("n") ||
|
||||
it.lowercase().contains("o") ||
|
||||
it.lowercase().contains("p") ||
|
||||
it.lowercase().contains("q") ||
|
||||
it.lowercase().contains("r") ||
|
||||
it.lowercase().contains("s") ||
|
||||
it.lowercase().contains("t") ||
|
||||
it.lowercase().contains("u") ||
|
||||
it.lowercase().contains("v") ||
|
||||
it.lowercase().contains("w") ||
|
||||
it.lowercase().contains("x") ||
|
||||
it.lowercase().contains("y") ||
|
||||
it.lowercase().contains("z")
|
||||
) "$it 稳定版" else "V$miuiVersion $it 开发版"
|
||||
} else "不是 MIUI 系统"
|
||||
|
||||
/**
|
||||
* 得到安装包信息
|
||||
* @return [PackageInfo]
|
||||
*/
|
||||
val Context.packageInfo get() = packageManager?.getPackageInfo(packageName, 0) ?: PackageInfo()
|
||||
|
||||
/**
|
||||
* 判断应用是否安装
|
||||
* @return [Boolean]
|
||||
*/
|
||||
val String.isInstall
|
||||
get() = safeOfFalse {
|
||||
appContext.packageManager.getPackageInfo(
|
||||
this,
|
||||
PackageManager.GET_UNINSTALLED_PACKAGES
|
||||
)
|
||||
true
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到版本信息
|
||||
* @return [String]
|
||||
*/
|
||||
val Context.versionName get() = packageInfo.versionName ?: ""
|
||||
|
||||
/**
|
||||
* 得到版本号
|
||||
* @return [Int]
|
||||
*/
|
||||
val Context.versionCode get() = packageInfo.versionCode
|
||||
|
||||
/**
|
||||
* 得到 APP 名称
|
||||
* @param name APP 包名
|
||||
* @return [String]
|
||||
*/
|
||||
fun Context.findAppName(name: String) =
|
||||
safeOfNothing { packageManager?.getPackageInfo(name, 0)?.applicationInfo?.loadLabel(packageManager).toString() }
|
||||
|
||||
/**
|
||||
* 得到 APP 图标
|
||||
* @param name APP 包名
|
||||
* @return [Drawable] or null
|
||||
*/
|
||||
fun Context.findAppIcon(name: String) =
|
||||
safeOfNull { packageManager?.getPackageInfo(name, 0)?.applicationInfo?.loadIcon(packageManager) }
|
||||
|
||||
/**
|
||||
* 对数值自动补零
|
||||
* @return [String]
|
||||
*/
|
||||
val Int.autoZero: String get() = if (this < 10) "0$this" else toString()
|
||||
|
||||
/**
|
||||
* 从字符串获取小时
|
||||
* @return [Int]
|
||||
*/
|
||||
val String.hour
|
||||
get() = safeOfNan {
|
||||
Calendar.getInstance().also {
|
||||
it.time = SimpleDateFormat("HH:mm", Locale.CHINA).parse(this) as Date
|
||||
}.get(Calendar.HOUR_OF_DAY)
|
||||
}
|
||||
|
||||
/**
|
||||
* 从字符串获取分钟
|
||||
* @return [Int]
|
||||
*/
|
||||
val String.minute
|
||||
get() = safeOfNan {
|
||||
Calendar.getInstance().also {
|
||||
it.time = SimpleDateFormat("HH:mm", Locale.CHINA).parse(this) as Date
|
||||
}.get(Calendar.MINUTE)
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否关闭了通知权限
|
||||
* @return [Boolean]
|
||||
*/
|
||||
val isNotNoificationEnabled get() = !NotificationManagerCompat.from(appContext).areNotificationsEnabled()
|
||||
|
||||
/**
|
||||
* 网络连接是否正常
|
||||
* @return [Boolean] 网络是否连接
|
||||
*/
|
||||
val isNetWorkSuccess
|
||||
get() = safeOfFalse { appContext.getSystemService<ConnectivityManager>()?.activeNetworkInfo != null }
|
||||
|
||||
/**
|
||||
* dp 转换为 pxInt
|
||||
* @param context 使用的实例
|
||||
* @return [Int]
|
||||
*/
|
||||
fun Number.dp(context: Context) = dpFloat(context).toInt()
|
||||
|
||||
/**
|
||||
* dp 转换为 pxFloat
|
||||
* @param context 使用的实例
|
||||
* @return [Float]
|
||||
*/
|
||||
fun Number.dpFloat(context: Context) = toFloat() * context.resources.displayMetrics.density
|
||||
|
||||
/**
|
||||
* 获取系统主题色
|
||||
* @return [Int] Android < 12 返回 [wallpaperColor]
|
||||
*/
|
||||
val Context.systemAccentColor
|
||||
get() = safeOf(wallpaperColor) { if (isUpperOfAndroidS) resources.getColor(android.R.color.system_accent1_600) else wallpaperColor }
|
||||
|
||||
/**
|
||||
* 获取系统壁纸颜色
|
||||
* @return [Int] 无法获取时返回透明色
|
||||
*/
|
||||
val Context.wallpaperColor
|
||||
get() = safeOfNan {
|
||||
WallpaperManager.getInstance(this).getWallpaperColors(WallpaperManager.FLAG_SYSTEM)?.primaryColor?.toArgb() ?: 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取较浅的颜色
|
||||
* @return [Int]
|
||||
*/
|
||||
val Int.brighter: Int
|
||||
get() {
|
||||
val hsv = FloatArray(3)
|
||||
Color.colorToHSV(this, hsv)
|
||||
hsv[1] = hsv[1] - 0.3f
|
||||
hsv[2] = hsv[2] + 0.3f
|
||||
return Color.HSVToColor(hsv)
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为白色
|
||||
* @return [Boolean]
|
||||
*/
|
||||
val Int.isWhite
|
||||
get() = safeOfTrue {
|
||||
val r = this and 0xff0000 shr 16
|
||||
val g = this and 0x00ff00 shr 8
|
||||
val b = this and 0x0000ff
|
||||
(0.2126 * r + 0.7152 * g + 0.0722 * b) >= 128
|
||||
}
|
||||
|
||||
/**
|
||||
* Base64 加密
|
||||
* @return [String]
|
||||
*/
|
||||
val Bitmap.base64
|
||||
get() = safeOfNothing {
|
||||
val baos = ByteArrayOutputStream()
|
||||
compress(Bitmap.CompressFormat.PNG, 100, baos)
|
||||
Base64.encodeToString(baos.toByteArray(), Base64.DEFAULT)
|
||||
}
|
||||
|
||||
/**
|
||||
* Base64 加密
|
||||
* @return [String]
|
||||
*/
|
||||
val String.base64: String get() = Base64.encodeToString(toByteArray(), Base64.DEFAULT)
|
||||
|
||||
/**
|
||||
* Base64 解密为字节流
|
||||
* @return [ByteArray]
|
||||
*/
|
||||
val String.unbase64 get() = Base64.decode(this, Base64.DEFAULT) ?: ByteArray(0)
|
||||
|
||||
/**
|
||||
* 字节流解析为位图
|
||||
* @return [Bitmap]
|
||||
*/
|
||||
val ByteArray.bitmap: Bitmap get() = BitmapFactory.decodeByteArray(this, 0, size)
|
||||
|
||||
/**
|
||||
* 字符串解析为位图
|
||||
* @return [Bitmap]
|
||||
*/
|
||||
val String.bitmap: Bitmap get() = unbase64.bitmap
|
||||
|
||||
/**
|
||||
* 圆角图片
|
||||
* @param radius 圆角度
|
||||
* @return [Bitmap] 圆角后的位图 - 失败会返回处理之前的位图
|
||||
*/
|
||||
fun Bitmap.round(radius: Float): Bitmap = safeOf(default = this) {
|
||||
Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888).also { out ->
|
||||
Canvas(out).also { canvas ->
|
||||
Paint().also { paint ->
|
||||
paint.isAntiAlias = true
|
||||
canvas.drawARGB(0, 0, 0, 0)
|
||||
paint.color = Color.WHITE
|
||||
canvas.drawRoundRect(RectF(Rect(0, 0, width, height)), radius, radius, paint)
|
||||
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
|
||||
canvas.drawBitmap(this, Rect(0, 0, width, height), Rect(0, 0, width, height), paint)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统 Prop 值
|
||||
* @param key Key
|
||||
* @param default 默认值
|
||||
* @return [String]
|
||||
*/
|
||||
fun findPropString(key: String, default: String = "") = safeOf(default) {
|
||||
(classOf(name = "android.os.SystemProperties").method {
|
||||
name = "get"
|
||||
param(StringType, StringType)
|
||||
}.get().invoke(key, default)) ?: default
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行命令 - su
|
||||
* @param cmd 命令
|
||||
* @return [String] 执行结果
|
||||
*/
|
||||
fun execShellSu(cmd: String) = safeOfNothing {
|
||||
Shell.su(cmd).exec().out.let {
|
||||
if (it.isNotEmpty()) it[0].trim() else ""
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 弹出 [Toast]
|
||||
* @param msg 提示内容
|
||||
*/
|
||||
fun toast(msg: String) = Toast.makeText(appContext, msg, Toast.LENGTH_SHORT).show()
|
||||
|
||||
/**
|
||||
* 跳转到指定页面
|
||||
*
|
||||
* [T] 为指定的 [Activity]
|
||||
*/
|
||||
inline fun <reified T : Activity> Context.navigate() = runInSafe { startActivity(Intent(this, T::class.java)) }
|
||||
|
||||
/**
|
||||
* 跳转到指定页面
|
||||
*
|
||||
* [T] 为指定的 [Activity]
|
||||
*/
|
||||
inline fun <reified T : Activity> Service.navigate() =
|
||||
runInSafe { startActivity(Intent(this, T::class.java).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK }) }
|
||||
|
||||
/**
|
||||
* 弹出 [Snackbar]
|
||||
* @param msg 提示内容
|
||||
* @param actionText 按钮文本 - 不写默认取消按钮
|
||||
* @param it 按钮事件回调
|
||||
*/
|
||||
fun Context.snake(msg: String, actionText: String = "", it: () -> Unit = {}) =
|
||||
Snackbar.make((this as Activity).findViewById(android.R.id.content), msg, Snackbar.LENGTH_LONG)
|
||||
.apply {
|
||||
if (actionText.isBlank()) return@apply
|
||||
setActionTextColor(if (isSystemInDarkMode) Color.BLACK else Color.WHITE)
|
||||
setAction(actionText) { it() }
|
||||
}.show()
|
||||
|
||||
/**
|
||||
* 启动系统浏览器
|
||||
* @param url 网址
|
||||
* @param packageName 指定包名 - 可不填
|
||||
*/
|
||||
fun Context.openBrowser(url: String, packageName: String = "") = runCatching {
|
||||
startActivity(Intent().apply {
|
||||
if (packageName.isNotBlank()) setPackage(packageName)
|
||||
action = Intent.ACTION_VIEW
|
||||
data = Uri.parse(url)
|
||||
/** 防止顶栈一样重叠在自己的 APP 中 */
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
})
|
||||
}.onFailure {
|
||||
if (packageName.isNotBlank())
|
||||
snake(msg = "启动 $packageName 失败")
|
||||
else snake(msg = "启动系统浏览器失败")
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转 APP 自身设置界面
|
||||
* @param packageName 包名
|
||||
*/
|
||||
fun Context.openSelfSetting(packageName: String = appContext.packageName) = runCatching {
|
||||
if (packageName.isInstall)
|
||||
startActivity(Intent().apply {
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
|
||||
data = Uri.fromParts("package", packageName, null)
|
||||
})
|
||||
else toast(msg = "你没有安装此应用")
|
||||
}.onFailure { toast(msg = "启动 $packageName 应用信息失败") }
|
||||
|
||||
/** 跳转通知设置界面 */
|
||||
fun Context.openNotifySetting() = runCatching {
|
||||
Intent().also { intent ->
|
||||
intent.action = Settings.ACTION_APP_NOTIFICATION_SETTINGS
|
||||
intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName)
|
||||
intent.putExtra(Notification.EXTRA_CHANNEL_ID, applicationInfo.uid)
|
||||
startActivity(intent)
|
||||
}
|
||||
}.onFailure { snake(msg = "跳转通知设置失败") }
|
||||
|
||||
/**
|
||||
* 复制到剪贴板
|
||||
* @param content 要复制的文本
|
||||
*/
|
||||
fun Context.copyToClipboard(content: String) = runInSafe {
|
||||
(getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager).apply {
|
||||
setPrimaryClip(ClipData.newPlainText(null, content))
|
||||
(primaryClip?.getItemAt(0)?.text ?: "").also {
|
||||
if (it != content) snake(msg = "复制失败") else snake(msg = "已复制")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 时间戳 -> 时间
|
||||
* @param format 格式化方法 - 默认:yyyy-MM-dd HH:mm:ss
|
||||
* @return [String] 目标字符串时间
|
||||
*/
|
||||
fun Long.stampToDate(format: String = "yyyy-MM-dd HH:mm:ss") =
|
||||
safeOfNothing { SimpleDateFormat(format, Locale.CHINA).format(Date(this)) ?: "" }
|
||||
|
||||
/**
|
||||
* 延迟执行
|
||||
* @param ms 毫秒 - 默认:150
|
||||
* @param it 方法体
|
||||
*/
|
||||
fun Any?.delayedRun(ms: Long = 150, it: () -> Unit) = runInSafe { Handler().postDelayed({ it() }, ms) }
|
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/2/19.
|
||||
*/
|
||||
package com.fankes.miui.notify.utils.tool
|
||||
|
||||
import android.graphics.*
|
||||
import android.graphics.drawable.AnimationDrawable
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.VectorDrawable
|
||||
import android.util.ArrayMap
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import com.fankes.miui.notify.utils.factory.safeOfFalse
|
||||
import kotlin.math.abs
|
||||
|
||||
/**
|
||||
* 这是一个从 AOSP 源码中分离出来的功能
|
||||
*
|
||||
* 主要作用于兼容部分 MIUI 魔改颜色判断代码造成判断位图灰度功能失效
|
||||
*/
|
||||
object BitmapCompatTool {
|
||||
|
||||
/** 缓存已判断的结果防止卡顿 */
|
||||
private var cachedBitmapGrayscales = ArrayMap<Int, Boolean>()
|
||||
|
||||
private var tempBuffer = intArrayOf(0)
|
||||
private var tempCompactBitmap: Bitmap? = null
|
||||
private var tempCompactBitmapCanvas: Canvas? = null
|
||||
private var tempCompactBitmapPaint: Paint? = null
|
||||
private val tempMatrix = Matrix()
|
||||
|
||||
/**
|
||||
* 判断 [Drawable] 是否为灰度位图
|
||||
* @param drawable 要判断的 [Drawable]
|
||||
* @return [Boolean] 是否灰度
|
||||
*/
|
||||
fun isGrayscaleDrawable(drawable: Drawable) = safeOfFalse {
|
||||
when (drawable) {
|
||||
is BitmapDrawable -> isGrayscaleBitmap(drawable.bitmap)
|
||||
is AnimationDrawable -> !(drawable.numberOfFrames <= 0 || !isGrayscaleBitmap(drawable.getFrame(0).toBitmap()))
|
||||
is VectorDrawable -> true
|
||||
else -> isGrayscaleBitmap(drawable.toBitmap())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断 [Bitmap] 是否为灰度位图
|
||||
* @param bitmap 要判断的位图
|
||||
* @return [Boolean] 是否灰度
|
||||
*/
|
||||
private fun isGrayscaleBitmap(bitmap: Bitmap) =
|
||||
cachedBitmapGrayscales[bitmap.generationId] ?: let {
|
||||
var height = bitmap.height
|
||||
var width = bitmap.width
|
||||
if (height > 64 || width > 64) {
|
||||
if (tempCompactBitmap == null) {
|
||||
tempCompactBitmap = Bitmap.createBitmap(64, 64, Bitmap.Config.ARGB_8888)
|
||||
.also { tempCompactBitmapCanvas = Canvas(it) }
|
||||
tempCompactBitmapPaint = Paint(Paint.FILTER_BITMAP_FLAG).apply { isFilterBitmap = true }
|
||||
}
|
||||
tempMatrix.reset()
|
||||
tempMatrix.setScale(64f / width, 64f / height, 0f, 0f)
|
||||
tempCompactBitmapCanvas?.drawColor(0, PorterDuff.Mode.SRC)
|
||||
tempCompactBitmapCanvas?.drawBitmap(bitmap, tempMatrix, tempCompactBitmapPaint)
|
||||
height = 64
|
||||
width = 64
|
||||
}
|
||||
val size = height * width
|
||||
ensureBufferSize(size)
|
||||
tempCompactBitmap?.getPixels(tempBuffer, 0, width, 0, 0, width, height)
|
||||
for (i in 0 until size)
|
||||
if (isGrayscaleColor(tempBuffer[i]).not()) {
|
||||
cachedBitmapGrayscales[bitmap.generationId] = false
|
||||
return@let false
|
||||
}
|
||||
cachedBitmapGrayscales[bitmap.generationId] = true
|
||||
true
|
||||
}
|
||||
|
||||
/**
|
||||
* 提纯 [Bitmap] 颜色判断灰度
|
||||
* @param color 颜色
|
||||
* @return [Boolean] 是否灰度
|
||||
*/
|
||||
private fun isGrayscaleColor(color: Int): Boolean {
|
||||
if (color shr 24 and 255 < 50) return true
|
||||
val r = color shr 16 and 255
|
||||
val g = color shr 8 and 255
|
||||
val b = color and 255
|
||||
return !(abs(r - g) >= 20 || abs(r - b) >= 20 || abs(g - b) >= 20)
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算字节数组
|
||||
* @param size 大小
|
||||
*/
|
||||
private fun ensureBufferSize(size: Int) {
|
||||
if (tempBuffer.size < size) tempBuffer = IntArray(size)
|
||||
}
|
||||
}
|
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/3/20.
|
||||
*/
|
||||
package com.fankes.miui.notify.utils.tool
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import com.fankes.miui.notify.utils.factory.*
|
||||
import okhttp3.*
|
||||
import org.json.JSONObject
|
||||
import java.io.IOException
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* 获取 Github Release 最新版本工具类
|
||||
*/
|
||||
object GithubReleaseTool {
|
||||
|
||||
/** 仓库作者 */
|
||||
private const val REPO_AUTHOR = "fankes"
|
||||
|
||||
/** 仓库名称 */
|
||||
private const val REPO_NAME = "MIUINativeNotifyIcon"
|
||||
|
||||
/**
|
||||
* 获取最新版本信息
|
||||
* @param context 实例
|
||||
* @param version 当前版本
|
||||
* @param it 成功后回调 - ([String] 最新版本,[Function] 更新对话框方法体)
|
||||
*/
|
||||
fun checkingForUpdate(context: Context, version: String, it: (String, () -> Unit) -> Unit) = checkingInternetConnect(context) {
|
||||
OkHttpClient().newBuilder().build().newCall(
|
||||
Request.Builder()
|
||||
.url("https://api.github.com/repos/$REPO_AUTHOR/$REPO_NAME/releases/latest")
|
||||
.get()
|
||||
.build()
|
||||
).enqueue(object : Callback {
|
||||
override fun onFailure(call: Call, e: IOException) {}
|
||||
|
||||
override fun onResponse(call: Call, response: Response) = runInSafe {
|
||||
JSONObject(response.body?.string() ?: "").apply {
|
||||
GithubReleaseBean(
|
||||
name = getString("name"),
|
||||
htmlUrl = getString("html_url"),
|
||||
content = getString("body"),
|
||||
date = getString("published_at").replace(oldValue = "T", newValue = " ").replace(oldValue = "Z", newValue = "")
|
||||
).apply {
|
||||
fun showUpdate() = context.showDialog {
|
||||
title = "最新版本 $name"
|
||||
msg = "发布于 $date\n\n" +
|
||||
"更新日志\n\n" + content
|
||||
confirmButton(text = "更新") { context.openBrowser(htmlUrl) }
|
||||
cancelButton()
|
||||
}
|
||||
if (name != version) (context as? Activity?)?.runOnUiThread {
|
||||
showUpdate()
|
||||
it(name) { showUpdate() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查网络连接情况
|
||||
* @param context 实例
|
||||
* @param it 已连接回调
|
||||
*/
|
||||
private fun checkingInternetConnect(context: Context, it: () -> Unit) = runInSafe {
|
||||
if (isNetWorkSuccess)
|
||||
OkHttpClient().newBuilder().build().newCall(
|
||||
Request.Builder()
|
||||
.url("https://www.baidu.com")
|
||||
.get()
|
||||
.build()
|
||||
).enqueue(object : Callback {
|
||||
override fun onFailure(call: Call, e: IOException) {
|
||||
(context as? Activity?)?.runOnUiThread {
|
||||
context.showDialog {
|
||||
title = "网络不可用"
|
||||
msg = "模块的联网权限可能已被禁用,请开启联网权限以定期检查更新。"
|
||||
confirmButton(text = "去开启") { context.openSelfSetting() }
|
||||
cancelButton()
|
||||
noCancelable()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResponse(call: Call, response: Response) = runInSafe {
|
||||
(context as? Activity?)?.runOnUiThread { runInSafe { it() } }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Github Release bean
|
||||
* @param name 版本名称
|
||||
* @param htmlUrl 网页地址
|
||||
* @param content 更新日志
|
||||
* @param date 发布时间
|
||||
*/
|
||||
private data class GithubReleaseBean(
|
||||
var name: String,
|
||||
var htmlUrl: String,
|
||||
var content: String,
|
||||
var date: String
|
||||
) : Serializable
|
||||
}
|
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/3/21.
|
||||
*/
|
||||
package com.fankes.miui.notify.utils.tool
|
||||
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.drawable.Icon
|
||||
import android.os.Build
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import com.fankes.miui.notify.const.Const
|
||||
import com.fankes.miui.notify.hook.HookEntry
|
||||
import com.fankes.miui.notify.utils.factory.*
|
||||
|
||||
/**
|
||||
* 通知图标适配推送通知类
|
||||
*
|
||||
* 这个类需要在 [HookEntry] 中调用
|
||||
*/
|
||||
object IconAdaptationTool {
|
||||
|
||||
/** 推送通知的渠道名称 */
|
||||
private const val NOTIFY_CHANNEL = "notifyRuleSupportId"
|
||||
|
||||
/** 已过期的日期 */
|
||||
private val outDateLimits = HashSet<String>()
|
||||
|
||||
/**
|
||||
* 使用的小图标
|
||||
* @return [Bitmap]
|
||||
*/
|
||||
private val smallIcon by lazy {
|
||||
("iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAACXBIWXMAAAsTAAALEwEAmpwYAAAG\n" +
|
||||
"x2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkP\n" +
|
||||
"SJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG\n" +
|
||||
"9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNi4wLWMwMDYgNzkuZGF\n" +
|
||||
"iYWNiYiwgMjAyMS8wNC8xNC0wMDozOTo0NCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6\n" +
|
||||
"cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gP\n" +
|
||||
"HJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYW\n" +
|
||||
"RvYmUuY29tL3hhcC8xLjAvIiB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1\n" +
|
||||
"lbnRzLzEuMS8iIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90\n" +
|
||||
"b3Nob3AvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuM\n" +
|
||||
"C9tbS8iIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cG\n" +
|
||||
"UvUmVzb3VyY2VFdmVudCMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIDI\n" +
|
||||
"yLjQgKE1hY2ludG9zaCkiIHhtcDpDcmVhdGVEYXRlPSIyMDIyLTAzLTIzVDAyOjU1OjM2\n" +
|
||||
"KzA4OjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAyMi0wMy0yM1QwMzowMDoyMSswODowMCIge\n" +
|
||||
"G1wOk1ldGFkYXRhRGF0ZT0iMjAyMi0wMy0yM1QwMzowMDoyMSswODowMCIgZGM6Zm9ybW\n" +
|
||||
"F0PSJpbWFnZS9wbmciIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiIHBob3Rvc2hvcDpJQ0N\n" +
|
||||
"Qcm9maWxlPSJzUkdCIElFQzYxOTY2LTIuMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlp\n" +
|
||||
"ZDpiZGY1YWY2NS1lYjYxLTRiOGUtOTk1NS01OTE5OThkN2ExNDAiIHhtcE1NOkRvY3VtZ\n" +
|
||||
"W50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDo2MDFlYjQ1OC01ZTdlLWFjNDYtODA0Mi\n" +
|
||||
"1iNWJmYTFhYWQwNGMiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpjYTU\n" +
|
||||
"4YTA1ZS04OTU1LTQyNzItODg2NC0xNmI5MWI0YzcxMmUiPiA8eG1wTU06SGlzdG9yeT4g\n" +
|
||||
"PHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJjcmVhdGVkIiBzdEV2dDppbnN0Y\n" +
|
||||
"W5jZUlEPSJ4bXAuaWlkOmNhNThhMDVlLTg5NTUtNDI3Mi04ODY0LTE2YjkxYjRjNzEyZS\n" +
|
||||
"Igc3RFdnQ6d2hlbj0iMjAyMi0wMy0yM1QwMjo1NTozNiswODowMCIgc3RFdnQ6c29mdHd\n" +
|
||||
"hcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIDIyLjQgKE1hY2ludG9zaCkiLz4gPHJkZjps\n" +
|
||||
"aSBzdEV2dDphY3Rpb249InNhdmVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjg5Y\n" +
|
||||
"mIxNTI1LWVjYmMtNGY2NC1iZTRlLWU1N2EyNjQ1NDE1YyIgc3RFdnQ6d2hlbj0iMjAyMi\n" +
|
||||
"0wMy0yM1QwMjo1NzoxMCswODowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGh\n" +
|
||||
"vdG9zaG9wIDIyLjQgKE1hY2ludG9zaCkiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPHJkZjps\n" +
|
||||
"aSBzdEV2dDphY3Rpb249InNhdmVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOmJkZ\n" +
|
||||
"jVhZjY1LWViNjEtNGI4ZS05OTU1LTU5MTk5OGQ3YTE0MCIgc3RFdnQ6d2hlbj0iMjAyMi\n" +
|
||||
"0wMy0yM1QwMzowMDoyMSswODowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGh\n" +
|
||||
"vdG9zaG9wIDIyLjQgKE1hY2ludG9zaCkiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPC9yZGY6\n" +
|
||||
"U2VxPiA8L3htcE1NOkhpc3Rvcnk+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+I\n" +
|
||||
"DwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+QdGsggAAA35JREFUaIHtmE2IVW\n" +
|
||||
"Ucxn9z0Ukm7cMSo1AxUwjNIclLRVSL0CAoyD5oYwS1iogWGW0rwQpcJNjCRdKmTR+SBhF\n" +
|
||||
"BWWZlZllmOgsT/EqHKRuqMVv8XJy5zPGd95x75hyh03Ae+C/O//2/z3Oee97P26MyGdD6\n" +
|
||||
"r1/gQqExUjc0RuqGxkjd0BipGxojdcOkMTKlS/tCYBXQBvqBWcA/wI/AD8AW4NML9C79w\n" +
|
||||
"APAYmAOcCUwCBwCvgTeB37J7K3Goq1utRgG1NUZPEXibnVnQa231CUxnhjxmoKkId5WWx\n" +
|
||||
"M08XpJrSe7GXmlJHEH36l9oUgketRPKmqtS3P2OHaxWgO8HBl9vwPbgM+AU8B0YAnJ3Fk\n" +
|
||||
"Uqd8HLAfO5MyHz4HbIvkh4ENgJ/Dn6DxZCdxFfGF6GngtPUeuz3D9qnpZzi/7mDoS6fe9\n" +
|
||||
"Oi1SP0XdnqH1vDo9Q2eeujmj33WmhtbuSMFTOQbSsUg9Gem/3/HDbEuk7ox6c0GtZyP9d\n" +
|
||||
"3WMLIg0vlGQuBPz1cEIzx51aqouxN/qsglqvRnhWYj6UpAcVnsnSN75/MciIntTfC+m8r\n" +
|
||||
"+qi0vo9Kp/BBrrUD8KkutLkHdijvpbxMy3jn2Z1eoL6uUVdDYE/NtRjwfJ+yoIoF6rnoi\n" +
|
||||
"Y2VORNx33B9wHWsDMYEk7m7NsFsEhYBlwMsjfCOwFplbkBzgdPPe2gOEg2e38VQQnSMwM\n" +
|
||||
"BvmlwBfAtIr8FwXPIy1gf5BsVxS5ieTQd5zEzFDQvhzYBfRU0OgPnk/j+GPJYMlx26d+P\n" +
|
||||
"MpxNjXX5hlfmneYbJBltAYCrk2YnCZDnHeOKRAXqz8FHMOp9mtMltsQu0uYeTzC085yqL\n" +
|
||||
"qqIPFMdV+k/46gbr7xpflrz98086Kt/hv0P6JjR5RbIwKqz5h/NF/p+OVb9bA6O1I/N6P\n" +
|
||||
"+Z/WWLiYezXjHO9JGMBlOMRxW16r3mhwn7jS5D2Rdho6ps3JeKGuYaXKnedhkL5qhLlWf\n" +
|
||||
"UL/KqN/Y4Q1FNmd0KIqj6tU5JtJmjnThGu7S/k6aMyayvpSF5FfL+xJhXKF+U1JrU8iXJ\n" +
|
||||
"bLC7M8Z4pTJXJrIypOO59ShgloH1YdiPOkbYgy3A48ANwBXAZcCIyQ79gDwAfAe8FeFzQ\n" +
|
||||
"3gEuBB4B5gATAb6BvlPUpy63wX2JpF0M3I/waT5g+6xkjd0BipGxojdUNjpG5ojNQNjZG\n" +
|
||||
"64Rx5J7QeMy++3AAAAABJRU5ErkJggg==").bitmap
|
||||
}
|
||||
|
||||
/**
|
||||
* 推送新 APP 安装适配通知
|
||||
* @param context 实例
|
||||
* @param packageName 安装的 APP 包名
|
||||
*/
|
||||
fun pushNewAppSupportNotify(context: Context, packageName: String) {
|
||||
context.getSystemService(NotificationManager::class.java)?.apply {
|
||||
createNotificationChannel(
|
||||
NotificationChannel(
|
||||
NOTIFY_CHANNEL, "通知图标优化适配",
|
||||
NotificationManager.IMPORTANCE_DEFAULT
|
||||
).apply { enableLights(false) }
|
||||
)
|
||||
notify(packageName.hashCode(), Notification.Builder(context, NOTIFY_CHANNEL).apply {
|
||||
setShowWhen(true)
|
||||
setContentTitle("您已安装 ${context.findAppName(packageName)}")
|
||||
setContentText("尚未适配此应用,点按打开在线规则。")
|
||||
setColor(0xFF2993F0.toInt())
|
||||
setAutoCancel(true)
|
||||
setSmallIcon(Icon.createWithBitmap(smallIcon))
|
||||
setLargeIcon(context.findAppIcon(packageName)?.toBitmap())
|
||||
setContentIntent(
|
||||
PendingIntent.getActivity(
|
||||
context, packageName.hashCode(),
|
||||
Intent().apply {
|
||||
component = ComponentName(
|
||||
Const.MODULE_PACKAGE_NAME,
|
||||
"${Const.MODULE_PACKAGE_NAME}.ui.activity.ConfigureActivity"
|
||||
)
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
}.apply {
|
||||
putExtra("isNewAppSupport", true)
|
||||
putExtra("appName", context.findAppName(packageName))
|
||||
putExtra("pkgName", packageName)
|
||||
}, if (Build.VERSION.SDK_INT < 31) PendingIntent.FLAG_UPDATE_CURRENT else PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
)
|
||||
}.build())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测 APP 卸载后移除相关通知
|
||||
* @param context 实例
|
||||
* @param packageName 卸载的 APP 包名
|
||||
*/
|
||||
fun removeNewAppSupportNotify(context: Context, packageName: String) = runInSafe {
|
||||
context.getSystemService(NotificationManager::class.java)?.cancel(packageName.hashCode())
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动更新通知图标优化在线规则
|
||||
*
|
||||
* 一天执行一次
|
||||
* @param context 实例
|
||||
* @param timeSet 设定的时间
|
||||
*/
|
||||
fun prepareAutoUpdateIconRule(context: Context, timeSet: String) = runInSafe {
|
||||
System.currentTimeMillis().also {
|
||||
if (it.stampToDate(format = "HH:mm") == timeSet && (outDateLimits.isEmpty() || outDateLimits.none { each ->
|
||||
each == it.stampToDate(format = "yyyy-MM-dd")
|
||||
})) {
|
||||
outDateLimits.add(it.stampToDate(format = "yyyy-MM-dd"))
|
||||
context.startActivity(
|
||||
Intent().apply {
|
||||
component = ComponentName(
|
||||
Const.MODULE_PACKAGE_NAME,
|
||||
"${Const.MODULE_PACKAGE_NAME}.ui.activity.auto.NotifyIconRuleUpdateActivity"
|
||||
)
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,457 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/2/25.
|
||||
*/
|
||||
@file:Suppress("TrustAllX509TrustManager", "CustomX509TrustManager", "IMPLICIT_CAST_TO_ANY")
|
||||
|
||||
package com.fankes.miui.notify.utils.tool
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.provider.Settings
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import com.fankes.miui.notify.R
|
||||
import com.fankes.miui.notify.data.DataConst
|
||||
import com.fankes.miui.notify.databinding.DiaSourceFromBinding
|
||||
import com.fankes.miui.notify.databinding.DiaSourceFromStringBinding
|
||||
import com.fankes.miui.notify.hook.HookConst.TYPE_SOURCE_SYNC_WAY_1
|
||||
import com.fankes.miui.notify.hook.HookConst.TYPE_SOURCE_SYNC_WAY_2
|
||||
import com.fankes.miui.notify.hook.HookConst.TYPE_SOURCE_SYNC_WAY_3
|
||||
import com.fankes.miui.notify.params.IconPackParams
|
||||
import com.fankes.miui.notify.ui.activity.ConfigureActivity
|
||||
import com.fankes.miui.notify.utils.factory.safeOfNull
|
||||
import com.fankes.miui.notify.utils.factory.showDialog
|
||||
import com.fankes.miui.notify.utils.factory.snake
|
||||
import com.highcapable.yukihookapi.hook.factory.modulePrefs
|
||||
import com.highcapable.yukihookapi.hook.log.loggerD
|
||||
import okhttp3.*
|
||||
import java.io.IOException
|
||||
import java.security.SecureRandom
|
||||
import java.security.cert.X509Certificate
|
||||
import javax.net.ssl.*
|
||||
|
||||
/**
|
||||
* 通知图标在线规则管理类
|
||||
*/
|
||||
object IconRuleManagerTool {
|
||||
|
||||
/** 推送通知的渠道名称 */
|
||||
private const val NOTIFY_CHANNEL = "notifyRuleUpdateId"
|
||||
|
||||
/** 当前规则的系统名称 */
|
||||
private const val OS_TAG = "MIUI"
|
||||
|
||||
/** 当前规则的通知图标颜色 */
|
||||
private const val OS_COLOR = 0xFFE06818
|
||||
|
||||
/**
|
||||
* 从在线地址手动同步规则
|
||||
* @param context 实例
|
||||
* @param it 成功后回调
|
||||
*/
|
||||
fun syncByHand(context: Context, it: () -> Unit) =
|
||||
context.showDialog {
|
||||
title = "同步列表"
|
||||
var sourceType = context.modulePrefs.get(DataConst.SOURCE_SYNC_WAY)
|
||||
var customUrl = context.modulePrefs.get(DataConst.SOURCE_SYNC_WAY_CUSTOM_URL)
|
||||
bind<DiaSourceFromBinding>().apply {
|
||||
diaSfText.apply {
|
||||
if (customUrl.isNotBlank()) {
|
||||
setText(customUrl)
|
||||
setSelection(customUrl.length)
|
||||
}
|
||||
doOnTextChanged { text, _, _, _ -> customUrl = text.toString() }
|
||||
}
|
||||
diaSfTextLin.isVisible = sourceType == TYPE_SOURCE_SYNC_WAY_3
|
||||
diaSfRd1.isChecked = sourceType == TYPE_SOURCE_SYNC_WAY_1
|
||||
diaSfRd2.isChecked = sourceType == TYPE_SOURCE_SYNC_WAY_2
|
||||
diaSfRd3.isChecked = sourceType == TYPE_SOURCE_SYNC_WAY_3
|
||||
diaSfRd1.setOnClickListener {
|
||||
diaSfRd2.isChecked = false
|
||||
diaSfRd3.isChecked = false
|
||||
diaSfTextLin.isVisible = false
|
||||
sourceType = TYPE_SOURCE_SYNC_WAY_1
|
||||
}
|
||||
diaSfRd2.setOnClickListener {
|
||||
diaSfRd1.isChecked = false
|
||||
diaSfRd3.isChecked = false
|
||||
diaSfTextLin.isVisible = false
|
||||
sourceType = TYPE_SOURCE_SYNC_WAY_2
|
||||
}
|
||||
diaSfRd3.setOnClickListener {
|
||||
diaSfRd1.isChecked = false
|
||||
diaSfRd2.isChecked = false
|
||||
diaSfTextLin.isVisible = true
|
||||
sourceType = TYPE_SOURCE_SYNC_WAY_3
|
||||
}
|
||||
}
|
||||
confirmButton {
|
||||
context.modulePrefs.put(DataConst.SOURCE_SYNC_WAY, sourceType)
|
||||
context.modulePrefs.put(DataConst.SOURCE_SYNC_WAY_CUSTOM_URL, customUrl)
|
||||
sync(context, sourceType, customUrl, it)
|
||||
}
|
||||
cancelButton()
|
||||
neutralButton(text = "自定义规则") {
|
||||
context.showDialog {
|
||||
title = "自定义规则(调试)"
|
||||
val editText = bind<DiaSourceFromStringBinding>().diaSfsInputEdit.apply {
|
||||
requestFocus()
|
||||
invalidate()
|
||||
}
|
||||
IconPackParams(context).also { params ->
|
||||
confirmButton(text = "合并") {
|
||||
editText.text.toString().also { jsonString ->
|
||||
when {
|
||||
jsonString.isNotBlank() && params.isNotVaildJson(jsonString) -> context.snake(msg = "不是有效的 JSON 数据")
|
||||
jsonString.isNotBlank() -> {
|
||||
params.save(
|
||||
params.splicingJsonArray(
|
||||
dataJson1 = params.storageDataJson ?: "[]",
|
||||
dataJson2 = jsonString.takeIf { params.isJsonArray(it) } ?: "[$jsonString]"
|
||||
)
|
||||
)
|
||||
notifyRefresh(context)
|
||||
it()
|
||||
}
|
||||
else -> context.snake(msg = "请输入有效内容")
|
||||
}
|
||||
}
|
||||
}
|
||||
cancelButton(text = "覆盖") {
|
||||
editText.text.toString().also { jsonString ->
|
||||
when {
|
||||
jsonString.isNotBlank() && params.isNotVaildJson(jsonString) -> context.snake(msg = "不是有效的 JSON 数据")
|
||||
jsonString.isNotBlank() -> {
|
||||
params.save(dataJson = jsonString.takeIf { params.isJsonArray(it) } ?: "[$jsonString]")
|
||||
notifyRefresh(context)
|
||||
it()
|
||||
}
|
||||
else -> context.snake(msg = "请输入有效内容")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
neutralButton(text = "取消")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从在线地址同步规则
|
||||
* @param context 实例
|
||||
* @param sourceType 同步地址类型 - 默认自动获取已存储的键值
|
||||
* @param customUrl 自定义同步地址 - 默认自动获取已存储的键值
|
||||
* @param it 成功后回调
|
||||
*/
|
||||
fun sync(
|
||||
context: Context,
|
||||
sourceType: Int = context.modulePrefs.get(DataConst.SOURCE_SYNC_WAY),
|
||||
customUrl: String = context.modulePrefs.get(DataConst.SOURCE_SYNC_WAY_CUSTOM_URL),
|
||||
it: () -> Unit
|
||||
) {
|
||||
when (sourceType) {
|
||||
TYPE_SOURCE_SYNC_WAY_1 ->
|
||||
onRefreshing(context, url = "https://raw.fastgit.org/fankes/AndroidNotifyIconAdapt/main", it)
|
||||
TYPE_SOURCE_SYNC_WAY_2 ->
|
||||
onRefreshing(context, url = "https://raw.githubusercontent.com/fankes/AndroidNotifyIconAdapt/main", it)
|
||||
TYPE_SOURCE_SYNC_WAY_3 ->
|
||||
if (customUrl.isNotBlank())
|
||||
if (customUrl.startsWith("http://") || customUrl.startsWith("https://"))
|
||||
onRefreshingCustom(context, customUrl, it)
|
||||
else context.snakeOrNotify(title = "同步失败", msg = "同步地址不是一个合法的 URL")
|
||||
else context.snakeOrNotify(title = "同步失败", msg = "同步地址不能为空")
|
||||
else -> context.snakeOrNotify(title = "同步异常", msg = "同步类型错误")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始更新数据
|
||||
* @param context 实例
|
||||
* @param url
|
||||
* @param it 成功后回调
|
||||
*/
|
||||
private fun onRefreshing(context: Context, url: String, it: () -> Unit) = checkingInternetConnect(context) {
|
||||
fun doParse(callback: (Boolean) -> Unit = {}) {
|
||||
wait(context, url = "$url/OS/$OS_TAG/NotifyIconsSupportConfig.json") { isDone1, ctOS ->
|
||||
callback(true)
|
||||
wait(context, url = "$url/APP/NotifyIconsSupportConfig.json") { isDone2, ctAPP ->
|
||||
callback(false)
|
||||
IconPackParams(context).also { params ->
|
||||
when {
|
||||
isDone1 && isDone2 -> params.splicingJsonArray(ctOS, ctAPP).also {
|
||||
when {
|
||||
params.isHackString(it) ->
|
||||
context.snakeOrNotify(title = "同步错误", msg = "请求需要验证,请尝试魔法上网或关闭魔法")
|
||||
params.isNotVaildJson(it) ->
|
||||
context.snakeOrNotify(title = "同步错误", msg = "目标地址不是有效的 JSON 数据")
|
||||
params.isCompareDifferent(it) -> {
|
||||
params.save(it)
|
||||
pushNotify(context, title = "同步完成", msg = "已更新通知图标优化名单,点击查看")
|
||||
notifyRefresh(context)
|
||||
it()
|
||||
}
|
||||
else -> (if (context is AppCompatActivity) context.snake(msg = "列表数据已是最新"))
|
||||
}
|
||||
}
|
||||
context is AppCompatActivity ->
|
||||
context.showDialog {
|
||||
title = "连接失败"
|
||||
msg = "连接失败,错误如下:\n${if (isDone1.not()) ctOS else ctAPP}"
|
||||
confirmButton(text = "再试一次") { syncByHand(context, it) }
|
||||
cancelButton()
|
||||
}
|
||||
else -> pushNotify(context, title = "同步地址不可用", msg = if (isDone1.not()) ctOS else ctAPP)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (context is AppCompatActivity)
|
||||
context.showDialog {
|
||||
title = "同步中"
|
||||
progressContent = "正在同步 OS 数据"
|
||||
noCancelable()
|
||||
doParse { if (it) progressContent = "正在同步 APP 数据" else cancel() }
|
||||
}
|
||||
else doParse()
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始更新数据
|
||||
* @param context 实例
|
||||
* @param url
|
||||
* @param it 成功后回调
|
||||
*/
|
||||
private fun onRefreshingCustom(context: Context, url: String, it: () -> Unit) = checkingInternetConnect(context) {
|
||||
fun doParse(callback: () -> Unit = {}) {
|
||||
wait(context, url) { isDone, content ->
|
||||
callback()
|
||||
IconPackParams(context).also { params ->
|
||||
when {
|
||||
isDone -> when {
|
||||
params.isHackString(content) ->
|
||||
context.snakeOrNotify(title = "同步错误", msg = "请求需要验证,请尝试魔法上网或关闭魔法")
|
||||
params.isNotVaildJson(content) ->
|
||||
context.snakeOrNotify(title = "同步错误", msg = "目标地址不是有效的 JSON 数据")
|
||||
params.isCompareDifferent(content) -> {
|
||||
params.save(content)
|
||||
pushNotify(context, title = "同步完成", msg = "已更新通知图标优化名单,点击查看")
|
||||
notifyRefresh(context)
|
||||
it()
|
||||
}
|
||||
else -> (if (context is AppCompatActivity) context.snake(msg = "列表数据已是最新"))
|
||||
}
|
||||
context is AppCompatActivity ->
|
||||
context.showDialog {
|
||||
title = "连接失败"
|
||||
msg = "连接失败,错误如下:\n$content"
|
||||
confirmButton(text = "我知道了")
|
||||
}
|
||||
else -> pushNotify(context, title = "同步地址不可用", msg = content)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (context is AppCompatActivity)
|
||||
context.showDialog {
|
||||
title = "同步中"
|
||||
progressContent = "正在通过自定义地址同步数据"
|
||||
noCancelable()
|
||||
doParse { cancel() }
|
||||
}
|
||||
else doParse()
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查网络连接情况
|
||||
* @param context 实例
|
||||
* @param it 已连接回调
|
||||
*/
|
||||
private fun checkingInternetConnect(context: Context, it: () -> Unit) =
|
||||
if (context is AppCompatActivity) context.showDialog {
|
||||
title = "准备中"
|
||||
progressContent = "正在检查网络连接情况"
|
||||
noCancelable()
|
||||
baseCheckingInternetConnect(context) { isDone ->
|
||||
cancel()
|
||||
if (isDone) it() else
|
||||
context.showDialog {
|
||||
title = "网络不可用"
|
||||
msg = "无法连接到互联网,请检查你当前的设备是否可以上网,且没有在手机管家中禁用本模块的联网权限。"
|
||||
confirmButton(text = "检查设置") {
|
||||
runCatching {
|
||||
context.startActivity(Intent().apply {
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
|
||||
data = Uri.fromParts("package", context.packageName, null)
|
||||
})
|
||||
}.onFailure { context.snake(msg = "启动应用信息页面失败") }
|
||||
}
|
||||
cancelButton()
|
||||
}
|
||||
}
|
||||
} else baseCheckingInternetConnect(context) { isDone ->
|
||||
if (isDone) it() else pushNotify(context, title = "网络不可用", msg = "无法连接到互联网,无法更新通知图标规则")
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查网络连接情况
|
||||
* @param context 实例
|
||||
* @param it 已连接回调
|
||||
*/
|
||||
private fun baseCheckingInternetConnect(context: Context, it: (Boolean) -> Unit) =
|
||||
wait(context, url = "https://www.baidu.com") { isDone, _ -> it(isDone) }
|
||||
|
||||
/**
|
||||
* 发送 GET 请求内容并等待
|
||||
* @param context 实例
|
||||
* @param url 请求地址
|
||||
* @param it 回调 - ([Boolean] 是否成功,[String] 成功的内容或失败消息)
|
||||
*/
|
||||
private fun wait(context: Context, url: String, it: (Boolean, String) -> Unit) = runCatching {
|
||||
OkHttpClient().newBuilder().apply {
|
||||
SSLSocketClient.sSLSocketFactory?.let { sslSocketFactory(it, SSLSocketClient.trustManager) }
|
||||
hostnameVerifier(SSLSocketClient.hostnameVerifier)
|
||||
}.build().newCall(
|
||||
Request.Builder()
|
||||
.url(url)
|
||||
.get()
|
||||
.build()
|
||||
).enqueue(object : Callback {
|
||||
override fun onFailure(call: Call, e: IOException) {
|
||||
(context as? Activity?)?.runOnUiThread { it(false, e.toString()) } ?: it(false, e.toString())
|
||||
}
|
||||
|
||||
override fun onResponse(call: Call, response: Response) {
|
||||
val bodyString = response.body?.string() ?: ""
|
||||
(context as? Activity?)?.runOnUiThread { it(true, bodyString) } ?: it(true, bodyString)
|
||||
}
|
||||
})
|
||||
}.onFailure { it(false, "URL 无效") }
|
||||
|
||||
/**
|
||||
* 推送通知图标更新通知
|
||||
* @param context 实例
|
||||
*/
|
||||
private fun notifyRefresh(context: Context) {
|
||||
if (context !is AppCompatActivity) return
|
||||
SystemUITool.refreshSystemUI(context) { context.snake(msg = "通知图标优化名单已完成同步") }
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据实例类型决定推送通知还是弹出提示
|
||||
* @param title 标题 - 仅对通知生效
|
||||
* @param msg 消息内容
|
||||
*/
|
||||
private fun Context.snakeOrNotify(title: String, msg: String) {
|
||||
if (this !is AppCompatActivity)
|
||||
pushNotify(context = this, title, msg)
|
||||
else snake(msg)
|
||||
}
|
||||
|
||||
/**
|
||||
* 推送通知
|
||||
* @param context 实例 - 类型为 [AppCompatActivity] 时将不会推送通知
|
||||
* @param title 通知标题
|
||||
* @param msg 通知消息
|
||||
*/
|
||||
private fun pushNotify(context: Context, title: String, msg: String) {
|
||||
if (context !is AppCompatActivity)
|
||||
context.getSystemService<NotificationManager>()?.apply {
|
||||
createNotificationChannel(
|
||||
NotificationChannel(
|
||||
NOTIFY_CHANNEL, "通知图标优化规则",
|
||||
NotificationManager.IMPORTANCE_DEFAULT
|
||||
)
|
||||
)
|
||||
notify(0, NotificationCompat.Builder(context, NOTIFY_CHANNEL).apply {
|
||||
setContentTitle(title)
|
||||
setContentText(msg)
|
||||
color = OS_COLOR.toInt()
|
||||
setAutoCancel(true)
|
||||
setSmallIcon(R.drawable.ic_nf_icon_update)
|
||||
setSound(null)
|
||||
setDefaults(NotificationCompat.DEFAULT_ALL)
|
||||
setContentIntent(
|
||||
PendingIntent.getActivity(
|
||||
context, msg.hashCode(),
|
||||
Intent(context, ConfigureActivity::class.java).apply { putExtra("isShowUpdDialog", false) },
|
||||
if (Build.VERSION.SDK_INT < 31) PendingIntent.FLAG_UPDATE_CURRENT else PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
)
|
||||
}.build())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动信任 SSL 证书
|
||||
*
|
||||
* 放行全部加密 SSL 请求
|
||||
*/
|
||||
private object SSLSocketClient {
|
||||
|
||||
/**
|
||||
* 格式化实例
|
||||
* @return [SSLSocketFactory] or null
|
||||
*/
|
||||
val sSLSocketFactory
|
||||
get() = safeOfNull {
|
||||
SSLContext.getInstance("TLS").let {
|
||||
it.init(null, arrayOf<TrustManager>(trustManager), SecureRandom())
|
||||
it.socketFactory
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用的实例
|
||||
* @return [HostnameVerifier]
|
||||
*/
|
||||
val hostnameVerifier get() = HostnameVerifier { _, _ -> true }
|
||||
|
||||
/**
|
||||
* 信任管理者
|
||||
* @return [X509TrustManager]
|
||||
*/
|
||||
val trustManager
|
||||
get() = object : X509TrustManager {
|
||||
|
||||
override fun checkClientTrusted(chain: Array<X509Certificate?>?, authType: String?) {
|
||||
loggerD(msg = "TrustX509 --> $authType")
|
||||
}
|
||||
|
||||
override fun checkServerTrusted(chain: Array<X509Certificate?>?, authType: String?) {
|
||||
loggerD(msg = "TrustX509 --> $authType")
|
||||
}
|
||||
|
||||
override fun getAcceptedIssuers() = arrayOf<X509Certificate>()
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||
*
|
||||
* This software is non-free but opensource software: you can redistribute it
|
||||
* and/or modify it under the terms of the GNU Affero General Public License
|
||||
* as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
* <p>
|
||||
*
|
||||
* This software 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
|
||||
* Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* and eula along with this software. If not, see
|
||||
* <https://www.gnu.org/licenses/>
|
||||
*
|
||||
* This file is Created by fankes on 2022/2/8.
|
||||
*/
|
||||
package com.fankes.miui.notify.utils.tool
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import com.fankes.miui.notify.application.MNNApplication.Companion.appContext
|
||||
import com.fankes.miui.notify.const.Const
|
||||
import com.fankes.miui.notify.utils.factory.*
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.highcapable.yukihookapi.hook.factory.isXposedModuleActive
|
||||
|
||||
/**
|
||||
* 系统界面工具
|
||||
*/
|
||||
object SystemUITool {
|
||||
|
||||
/** 宿主广播回调 */
|
||||
private var moduleHandlerCallback: ((Boolean, Boolean) -> Unit)? = null
|
||||
|
||||
/** 通知广播回调 */
|
||||
private var remindHandlerCallback: ((Boolean, Boolean) -> Unit)? = null
|
||||
|
||||
/**
|
||||
* 注册广播
|
||||
* @param context 实例
|
||||
*/
|
||||
fun register(context: Context) {
|
||||
/** 注册广播检查模块激活状态 */
|
||||
context.registerReceiver(moduleHandlerReceiver, IntentFilter().apply { addAction(Const.ACTION_MODULE_HANDLER_RECEIVER) })
|
||||
/** 注册广播通知系统界面改变 */
|
||||
context.registerReceiver(remindHandlerReceiver, IntentFilter().apply { addAction(Const.ACTION_REMIND_HANDLER_RECEIVER) })
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消注册广播
|
||||
* @param context 实例
|
||||
*/
|
||||
fun unregister(context: Context) {
|
||||
context.unregisterReceiver(moduleHandlerReceiver)
|
||||
context.unregisterReceiver(remindHandlerReceiver)
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查模块是否激活
|
||||
* @param context 实例
|
||||
* @param it 成功后回调 - ([Boolean] 是否激活,[Boolean] 是否有效)
|
||||
*/
|
||||
fun checkingActivated(context: Context, it: (Boolean, Boolean) -> Unit) {
|
||||
moduleHandlerCallback = it
|
||||
context.sendBroadcast(Intent().apply {
|
||||
action = Const.ACTION_MODULE_CHECKING_RECEIVER
|
||||
putExtra(Const.MODULE_VERSION_VERIFY_TAG, Const.MODULE_VERSION_VERIFY)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 重启系统界面
|
||||
* @param context 实例
|
||||
*/
|
||||
fun restartSystemUI(context: Context) =
|
||||
context.showDialog {
|
||||
title = "重启系统界面"
|
||||
msg = "你确定要立即重启系统界面吗?\n\n" +
|
||||
"部分 MIUI 内测和开发版中使用了状态栏主题可能会发生主题失效的情况,这种情况请再重启一次即可。\n\n" +
|
||||
"重启过程会黑屏并等待进入锁屏重新解锁。"
|
||||
confirmButton {
|
||||
execShellSu(cmd = "pgrep systemui").also { pid ->
|
||||
if (pid.isNotBlank())
|
||||
execShellSu(cmd = "kill -9 $pid")
|
||||
else toast(msg = "ROOT 权限获取失败")
|
||||
}
|
||||
}
|
||||
cancelButton()
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新系统界面状态栏与通知图标
|
||||
* @param context 实例
|
||||
* @param isRefreshCacheOnly 仅刷新缓存不刷新图标和通知改变 - 默认:否
|
||||
* @param it 成功后回调
|
||||
*/
|
||||
fun refreshSystemUI(context: Context? = null, isRefreshCacheOnly: Boolean = false, it: () -> Unit = {}) = runInSafe {
|
||||
fun sendMessage() {
|
||||
(context ?: appContext).sendBroadcast(Intent().apply {
|
||||
action = Const.ACTION_REMIND_CHECKING_RECEIVER
|
||||
putExtra("isRefreshCacheOnly", isRefreshCacheOnly)
|
||||
putExtra(Const.MODULE_VERSION_VERIFY_TAG, Const.MODULE_VERSION_VERIFY)
|
||||
})
|
||||
}
|
||||
if (isXposedModuleActive)
|
||||
context?.showDialog {
|
||||
title = "请稍后"
|
||||
progressContent = "正在等待系统界面刷新"
|
||||
/** 是否等待成功 */
|
||||
var isWaited = false
|
||||
/** 设置等待延迟 */
|
||||
delayedRun(ms = 5000) {
|
||||
if (isWaited) return@delayedRun
|
||||
remindHandlerCallback = null
|
||||
cancel()
|
||||
context.snake(msg = "预计响应超时,建议重启系统界面", actionText = "立即重启") { restartSystemUI(context) }
|
||||
}
|
||||
remindHandlerCallback = { isGrasp, isValied ->
|
||||
remindHandlerCallback = null
|
||||
cancel()
|
||||
isWaited = true
|
||||
when {
|
||||
isGrasp && !isValied ->
|
||||
context.snake(msg = "请重启系统界面以生效模块更新", actionText = "立即重启") { restartSystemUI(context) }
|
||||
else -> it()
|
||||
}
|
||||
}
|
||||
sendMessage()
|
||||
noCancelable()
|
||||
} ?: sendMessage()
|
||||
else context?.snake(msg = "模块没有激活,更改不会生效")
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示需要重启系统界面的 [Snackbar]
|
||||
* @param context 实例
|
||||
*/
|
||||
fun showNeedRestartSnake(context: Context) =
|
||||
if (isXposedModuleActive)
|
||||
context.snake(msg = "设置需要重启系统界面才能生效", actionText = "立即重启") { restartSystemUI(context) }
|
||||
else context.snake(msg = "模块没有激活,更改不会生效")
|
||||
|
||||
/** 宿主广播接收器 */
|
||||
private val moduleHandlerReceiver by lazy {
|
||||
object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
val isRegular = intent?.getBooleanExtra("isRegular", false) ?: false
|
||||
val isValied = intent?.getBooleanExtra("isValied", false) ?: false
|
||||
moduleHandlerCallback?.invoke(isRegular, isValied)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 通知广播接收器 */
|
||||
private val remindHandlerReceiver by lazy {
|
||||
object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
val isGrasp = intent?.getBooleanExtra("isGrasp", false) ?: false
|
||||
val isValied = intent?.getBooleanExtra("isValied", false) ?: false
|
||||
remindHandlerCallback?.invoke(isGrasp, isValied)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* 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/8.
|
||||
*/
|
||||
|
||||
@file:Suppress("SameParameterValue")
|
||||
|
||||
package com.fankes.miui.notify.view
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Color
|
||||
import android.util.AttributeSet
|
||||
import androidx.appcompat.widget.SwitchCompat
|
||||
import com.fankes.miui.notify.utils.dp
|
||||
import com.fankes.miui.notify.utils.drawable.drawabletoolbox.DrawableBuilder
|
||||
|
||||
class MaterialSwitch(context: Context, attrs: AttributeSet?) : SwitchCompat(context, attrs) {
|
||||
|
||||
private fun toColors(selected: Int, pressed: Int, normal: Int): ColorStateList {
|
||||
val colors = intArrayOf(selected, pressed, normal)
|
||||
val states = arrayOfNulls<IntArray>(3)
|
||||
states[0] = intArrayOf(android.R.attr.state_checked)
|
||||
states[1] = intArrayOf(android.R.attr.state_pressed)
|
||||
states[2] = intArrayOf()
|
||||
return ColorStateList(states, colors)
|
||||
}
|
||||
|
||||
init {
|
||||
trackDrawable = DrawableBuilder()
|
||||
.rectangle()
|
||||
.rounded()
|
||||
.solidColor(0xFF656565.toInt())
|
||||
.height(20.dp)
|
||||
.cornerRadius(15.dp)
|
||||
.build()
|
||||
thumbDrawable = DrawableBuilder()
|
||||
.rectangle()
|
||||
.rounded()
|
||||
.solidColor(Color.WHITE)
|
||||
.size(20.dp, 20.dp)
|
||||
.cornerRadius(20.dp)
|
||||
.strokeWidth(2.dp)
|
||||
.strokeColor(Color.TRANSPARENT)
|
||||
.build()
|
||||
trackTintList = toColors(
|
||||
0xFF656565.toInt(),
|
||||
0xFFCCCCCC.toInt(),
|
||||
0xFFCCCCCC.toInt()
|
||||
)
|
||||
}
|
||||
}
|
6
app/src/main/res/drawable/bg_orange_round.xml
Executable file
@@ -0,0 +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="#FF7043" />
|
||||
<corners android:radius="15dp" />
|
||||
</shape>
|
6
app/src/main/res/drawable/bg_yellow_round.xml
Executable file
@@ -0,0 +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="#FF9800" />
|
||||
<corners android:radius="15dp" />
|
||||
</shape>
|
11
app/src/main/res/drawable/ic_nf_icon_update.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="@color/white"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96zM14,13v4h-4v-4H7l5,-5 5,5h-3z" />
|
||||
</vector>
|
10
app/src/main/res/drawable/ic_notify_icon.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="150dp"
|
||||
android:height="150dp"
|
||||
android:viewportWidth="1024"
|
||||
android:viewportHeight="1024">
|
||||
|
||||
<path
|
||||
android:fillColor="@color/white"
|
||||
android:pathData="M192,736 L192,416C192,261.2 302,132.1 448,102.4L448,64C448,28.6 476.6,0 512,0 547.4,0 576,28.6 576,64L576,102.4C722,132.1 832,261.2 832,416L832,736 864.1,736C899.4,736 928,764.4 928,800 928,835.4 899.4,864 864.1,864L159.9,864C124.6,864 96,835.6 96,800 96,764.6 124.6,736 159.9,736L192,736ZM608,928C608,981 565,1024 512,1024 459,1024 416,981 416,928L608,928Z" />
|
||||
</vector>
|
11
app/src/main/res/drawable/ic_system_clock.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="@color/white"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM15.29,16.71L11,12.41V7h2v4.59l3.71,3.71L15.29,16.71z" />
|
||||
</vector>
|
@@ -5,7 +5,7 @@
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/colorThemeBackground"
|
||||
android:orientation="vertical"
|
||||
tools:context=".ui.MainActivity"
|
||||
tools:context=".ui.activity.MainActivity"
|
||||
tools:ignore="HardcodedText,UseCompoundDrawables,ContentDescription">
|
||||
|
||||
<LinearLayout
|
||||
@@ -24,13 +24,15 @@
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginEnd="25dp"
|
||||
android:src="@mipmap/back"
|
||||
android:tint="@color/colorTextGray" />
|
||||
android:layout_marginEnd="20dp"
|
||||
android:src="@mipmap/ic_back"
|
||||
android:tint="@color/colorTextGray"
|
||||
android:tooltipText="返回" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="2.5dp"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center|start"
|
||||
android:orientation="vertical">
|
||||
@@ -50,10 +52,46 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:text="..."
|
||||
android:text="适配列表正在等待装载"
|
||||
android:textColor="@color/colorTextDark"
|
||||
android:textSize="12sp" />
|
||||
android:textSize="11.5sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.constraintlayout.utils.widget.ImageFilterView
|
||||
android:id="@+id/config_title_up"
|
||||
android:layout_width="22dp"
|
||||
android:layout_height="22dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:src="@mipmap/ic_page_top"
|
||||
android:tint="@color/colorTextGray"
|
||||
android:tooltipText="滚动到顶部" />
|
||||
|
||||
<androidx.constraintlayout.utils.widget.ImageFilterView
|
||||
android:id="@+id/config_title_down"
|
||||
android:layout_width="22dp"
|
||||
android:layout_height="22dp"
|
||||
android:layout_marginEnd="15dp"
|
||||
android:src="@mipmap/ic_page_bottom"
|
||||
android:tint="@color/colorTextGray"
|
||||
android:tooltipText="滚动到底部" />
|
||||
|
||||
<androidx.constraintlayout.utils.widget.ImageFilterView
|
||||
android:id="@+id/config_title_filter"
|
||||
android:layout_width="22dp"
|
||||
android:layout_height="22dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:src="@mipmap/ic_filter"
|
||||
android:tint="@color/colorTextGray"
|
||||
android:tooltipText="按条件过滤" />
|
||||
|
||||
<androidx.constraintlayout.utils.widget.ImageFilterView
|
||||
android:id="@+id/config_title_sync"
|
||||
android:layout_width="23dp"
|
||||
android:layout_height="23dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:src="@mipmap/ic_sync"
|
||||
android:tint="@color/colorTextGray"
|
||||
android:tooltipText="同步列表" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
@@ -62,7 +100,7 @@
|
||||
android:layout_marginLeft="15dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginRight="15dp"
|
||||
android:background="@drawable/permotion_round"
|
||||
android:background="@drawable/bg_permotion_round"
|
||||
android:elevation="0dp"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
@@ -73,7 +111,7 @@
|
||||
android:layout_height="15dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:alpha="0.85"
|
||||
android:src="@mipmap/about"
|
||||
android:src="@mipmap/ic_about"
|
||||
android:tint="@color/colorTextDark" />
|
||||
|
||||
<TextView
|
||||
@@ -81,24 +119,41 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0.6"
|
||||
android:lineSpacingExtra="5dp"
|
||||
android:text="启用替换后 APP 的彩色通知图标将被替换为预设的小图标。\n启用全部替换将忽略 APP 非彩色图标,强制将全部通知图标替换为列表中预设的小图标。"
|
||||
android:text="启用替换后 APP 的彩色通知图标将被替换为预设的小图标。\n启用全部替换将忽略 APP 单色图标,强制将全部通知图标替换为列表中预设的小图标。"
|
||||
android:textColor="@color/colorTextGray"
|
||||
android:textSize="11sp"
|
||||
tools:ignore="SmallSp" />
|
||||
</LinearLayout>
|
||||
|
||||
<ListView
|
||||
android:id="@+id/config_list_view"
|
||||
<FrameLayout
|
||||
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" />
|
||||
android:layout_weight="1">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/config_list_no_data_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:lineSpacingExtra="6dp"
|
||||
android:text="没有数据"
|
||||
android:textColor="@color/colorTextDark"
|
||||
android:textSize="17sp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<ListView
|
||||
android:id="@+id/config_list_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:divider="@color/trans"
|
||||
android:dividerHeight="15dp"
|
||||
android:fadingEdgeLength="10dp"
|
||||
android:listSelector="@color/trans"
|
||||
android:padding="15dp"
|
||||
android:requiresFadingEdge="vertical"
|
||||
android:scrollbars="none" />
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/config_cbr_button"
|
||||
@@ -107,7 +162,7 @@
|
||||
android:layout_marginLeft="15dp"
|
||||
android:layout_marginRight="15dp"
|
||||
android:layout_marginBottom="15dp"
|
||||
android:background="@drawable/button_round"
|
||||
android:background="@drawable/bg_button_round"
|
||||
android:gravity="center"
|
||||
android:padding="10dp"
|
||||
android:singleLine="true"
|
||||
|
@@ -6,8 +6,8 @@
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/colorThemeBackground"
|
||||
android:orientation="vertical"
|
||||
tools:context=".ui.MainActivity"
|
||||
tools:ignore="HardcodedText,UseCompoundDrawables,ContentDescription">
|
||||
tools:context=".ui.activity.MainActivity"
|
||||
tools:ignore="HardcodedText,UseCompoundDrawables,ContentDescription,TooManyViews">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
@@ -32,11 +32,24 @@
|
||||
<androidx.constraintlayout.utils.widget.ImageFilterView
|
||||
android:id="@+id/title_restart_icon"
|
||||
style="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp"
|
||||
android:layout_marginEnd="15dp"
|
||||
android:alpha="0.85"
|
||||
android:src="@mipmap/ic_restart"
|
||||
android:tint="@color/colorTextGray"
|
||||
android:tooltipText="重启系统界面" />
|
||||
|
||||
<androidx.constraintlayout.utils.widget.ImageFilterView
|
||||
android:id="@+id/title_github_icon"
|
||||
style="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:layout_width="27dp"
|
||||
android:layout_height="27dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:src="@mipmap/restart"
|
||||
android:tint="@color/colorTextGray" />
|
||||
android:alpha="0.85"
|
||||
android:src="@mipmap/ic_github"
|
||||
android:tint="@color/colorTextGray"
|
||||
android:tooltipText="项目地址" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
@@ -47,7 +60,7 @@
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginRight="15dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:background="@drawable/dark_round"
|
||||
android:background="@drawable/bg_dark_round"
|
||||
android:elevation="0dp"
|
||||
android:gravity="center">
|
||||
|
||||
@@ -57,7 +70,7 @@
|
||||
android:layout_height="25dp"
|
||||
android:layout_marginStart="25dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:src="@mipmap/warn"
|
||||
android:src="@mipmap/ic_warn"
|
||||
android:tint="@color/white" />
|
||||
|
||||
<LinearLayout
|
||||
@@ -74,28 +87,71 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:text="模块未激活"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:text="模块状态未知"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="18sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/main_text_version"
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:alpha="0.8"
|
||||
android:text="当前版本:%1"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="13sp" />
|
||||
android:gravity="center|start"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/main_text_version"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0.8"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:text="模块版本:%1"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="13sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/main_text_release_version"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="5dp"
|
||||
android:background="@drawable/bg_orange_round"
|
||||
android:ellipsize="end"
|
||||
android:paddingLeft="5dp"
|
||||
android:paddingTop="2dp"
|
||||
android:paddingRight="5dp"
|
||||
android:paddingBottom="2dp"
|
||||
android:singleLine="true"
|
||||
android:text="点击更新 %1"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="11sp"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/main_text_miui_version"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0.8"
|
||||
android:text="MIUI 版本:%1"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:text="系统版本:%1"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="13sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/main_text_api_way"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="5dp"
|
||||
android:alpha="0.6"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:text="%1"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="11sp"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
@@ -119,7 +175,7 @@
|
||||
android:layout_marginLeft="15dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginRight="15dp"
|
||||
android:background="@drawable/permotion_round"
|
||||
android:background="@drawable/bg_permotion_round"
|
||||
android:elevation="0dp"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
@@ -130,7 +186,7 @@
|
||||
android:layout_height="15dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:alpha="0.85"
|
||||
android:src="@mipmap/about"
|
||||
android:src="@mipmap/ic_about"
|
||||
android:tint="@color/colorTextDark" />
|
||||
|
||||
<TextView
|
||||
@@ -151,14 +207,36 @@
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginRight="15dp"
|
||||
android:animateLayoutChanges="true"
|
||||
android:background="@drawable/permotion_round"
|
||||
android:background="@drawable/bg_permotion_round"
|
||||
android:elevation="0dp"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="15dp"
|
||||
android:paddingTop="15dp"
|
||||
android:paddingRight="15dp">
|
||||
|
||||
<com.fankes.miui.notify.view.MaterialSwitch
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center|start">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:src="@mipmap/ic_basic" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0.85"
|
||||
android:singleLine="true"
|
||||
android:text="基础设置"
|
||||
android:textColor="@color/colorTextGray"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.fankes.miui.notify.ui.view.MaterialSwitch
|
||||
android:id="@+id/module_enable_switch"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
@@ -167,7 +245,7 @@
|
||||
android:textColor="@color/colorTextGray"
|
||||
android:textSize="15sp" />
|
||||
|
||||
<com.fankes.miui.notify.view.MaterialSwitch
|
||||
<com.fankes.miui.notify.ui.view.MaterialSwitch
|
||||
android:id="@+id/module_enable_log_switch"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="35dp"
|
||||
@@ -182,29 +260,53 @@
|
||||
android:layout_marginBottom="10dp"
|
||||
android:alpha="0.6"
|
||||
android:lineSpacingExtra="6dp"
|
||||
android:text="模块关闭后功能都将彻底停止工作,以下选项都将不再生效。"
|
||||
android:text="模块关闭后一切功能都将彻底停止工作。"
|
||||
android:textColor="@color/colorTextDark"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/status_icon_count_item"
|
||||
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:animateLayoutChanges="true"
|
||||
android:background="@drawable/bg_permotion_round"
|
||||
android:elevation="0dp"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="15dp"
|
||||
android:paddingTop="15dp"
|
||||
android:paddingRight="15dp">
|
||||
|
||||
<com.fankes.miui.notify.view.MaterialSwitch
|
||||
android:id="@+id/color_icon_fix_switch"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="忽略彩色通知图标"
|
||||
android:gravity="center|start">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:src="@mipmap/ic_control" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0.85"
|
||||
android:singleLine="true"
|
||||
android:text="功能调整"
|
||||
android:textColor="@color/colorTextGray"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.fankes.miui.notify.ui.view.MaterialSwitch
|
||||
android:id="@+id/status_icon_count_switch"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="解除状态栏通知图标个数限制"
|
||||
android:textColor="@color/colorTextGray"
|
||||
android:textSize="15sp" />
|
||||
|
||||
@@ -214,26 +316,183 @@
|
||||
android:layout_marginBottom="10dp"
|
||||
android:alpha="0.6"
|
||||
android:lineSpacingExtra="6dp"
|
||||
android:text="此选项默认开启,开启后将自动对 APP 通知图标进行判断,保持高版本 API 的 APP 不规范的彩色图标不被着色为白、黑色块并对图标进行圆角优化,关闭后将按照 Android API 规范对 APP 通知进行图标着色,可能会出现着色为黑白、色块情况。"
|
||||
android:text="此选项默认开启,MIUI 默认最多只能显示 3 个图标,其余图标将变成省略号,你可以在下方自定义最多显示的图标个数,修改为 0 则只会显示省略号代表图标个数,为防止发生异常,最大限制 100 个,超出的图标可能会被信号或网速指示器遮挡。"
|
||||
android:textColor="@color/colorTextDark"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/warn_s_count_dis_tip"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:alpha="0.6"
|
||||
android:lineSpacingExtra="6dp"
|
||||
android:text="⚠️ 仅支持 MIUI 12.5 后期开发版以及最新版本"
|
||||
android:textColor="@color/colorTextDark"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/status_icon_count_child_item"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:gravity="center">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
android:src="@drawable/ic_notify_icon"
|
||||
app:tint="@color/colorTextGray" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center"
|
||||
android:singleLine="true"
|
||||
android:text="最多显示"
|
||||
android:textColor="@color/colorTextGray"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/status_icon_count_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center"
|
||||
android:maxWidth="100dp"
|
||||
android:paddingLeft="5dp"
|
||||
android:paddingRight="5dp"
|
||||
android:singleLine="true"
|
||||
android:text="5"
|
||||
android:textColor="@color/colorTextGray"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center"
|
||||
android:singleLine="true"
|
||||
android:text="个"
|
||||
android:textColor="@color/colorTextGray"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/status_icon_count_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_button_round"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center"
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingRight="10dp"
|
||||
android:paddingBottom="5dp"
|
||||
android:singleLine="true"
|
||||
android:text="修改个数"
|
||||
android:textColor="@color/colorTextGray"
|
||||
android:textSize="14sp" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/color_icon_hook_item"
|
||||
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/bg_permotion_round"
|
||||
android:elevation="0dp"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="15dp"
|
||||
android:paddingTop="15dp"
|
||||
android:paddingRight="15dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center|start">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:src="@mipmap/ic_modify" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0.85"
|
||||
android:singleLine="true"
|
||||
android:text="图标调整"
|
||||
android:textColor="@color/colorTextGray"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.fankes.miui.notify.ui.view.MaterialSwitch
|
||||
android:id="@+id/color_icon_compat_switch"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="启用兼容模式"
|
||||
android:textColor="@color/colorTextGray"
|
||||
android:textSize="15sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:alpha="0.6"
|
||||
android:lineSpacingExtra="6dp"
|
||||
android:text="如果发现通知图标颜色判定不正常可启用兼容模式,一般情况下不建议启用兼容模式,发生问题请关闭兼容模式。"
|
||||
android:textColor="@color/colorTextDark"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/config_item_notify"
|
||||
android:id="@+id/notify_icon_config_item"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginLeft="15dp"
|
||||
android:layout_marginTop="15dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:background="@drawable/permotion_round"
|
||||
android:layout_marginRight="15dp"
|
||||
android:animateLayoutChanges="true"
|
||||
android:background="@drawable/bg_permotion_round"
|
||||
android:elevation="0dp"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="15dp"
|
||||
android:paddingRight="15dp">
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingTop="15dp"
|
||||
android:paddingRight="10dp">
|
||||
|
||||
<com.fankes.miui.notify.view.MaterialSwitch
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="5dp"
|
||||
android:layout_marginRight="5dp"
|
||||
android:gravity="center|start">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:src="@mipmap/ic_notify" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0.85"
|
||||
android:singleLine="true"
|
||||
android:text="图标优化"
|
||||
android:textColor="@color/colorTextGray"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.fankes.miui.notify.ui.view.MaterialSwitch
|
||||
android:id="@+id/notify_icon_fix_switch"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -244,11 +503,13 @@
|
||||
android:textSize="15sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/config_notify_app_button"
|
||||
android:id="@+id/notify_icon_fix_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="3dp"
|
||||
android:layout_marginRight="3dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:background="@drawable/button_round"
|
||||
android:background="@drawable/bg_button_round"
|
||||
android:gravity="center"
|
||||
android:padding="10dp"
|
||||
android:singleLine="true"
|
||||
@@ -264,9 +525,134 @@
|
||||
android:layout_marginBottom="10dp"
|
||||
android:alpha="0.6"
|
||||
android:lineSpacingExtra="6dp"
|
||||
android:text="此选项默认开启,开启后将对优化名单内 APP 通知小图标进行色彩修复,使得它们的图标看起来更加美观。"
|
||||
android:text="首次安装请打开名单列表从云端更新数据,后期适配的内容也请手动打开名单列表重新拉取数据以检查更新,数据更新后无需重启系统界面,实时生效。"
|
||||
android:textColor="@color/colorTextDark"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<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="此选项默认开启,开启后将对优化名单内的 APP 通知小图标使用单色调进行修复,特别是通过系统级别推送的通知,它们始终是 APP 默认图标(彩色的 APP 图标),修复后使得它们的图标看起来更加符合 Android 原生的统一规范。"
|
||||
android:textColor="@color/colorTextDark"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/notify_icon_fix_notify_item"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="5dp"
|
||||
android:layout_marginRight="5dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.fankes.miui.notify.ui.view.MaterialSwitch
|
||||
android:id="@+id/notify_icon_fix_notify_switch"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="30dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:text="提醒未适配通知图标的新安装应用"
|
||||
android:textColor="@color/colorTextGray"
|
||||
android:textSize="15sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:alpha="0.6"
|
||||
android:lineSpacingExtra="6dp"
|
||||
android:text="此选项默认开启,在通知图标优化名单有数据时将自动检查新安装的应用是否存在适配数据,若没有将会发送通知提醒,如果你了解日后新安装的应用通知图标是遵守原生单色图标规范的,可以关闭此提醒。"
|
||||
android:textColor="@color/colorTextDark"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/notify_icon_auto_sync_item"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="5dp"
|
||||
android:layout_marginRight="5dp"
|
||||
android:animateLayoutChanges="true"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.fankes.miui.notify.ui.view.MaterialSwitch
|
||||
android:id="@+id/notify_icon_auto_sync_switch"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="30dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:text="启用通知图标优化名单自动更新"
|
||||
android:textColor="@color/colorTextGray"
|
||||
android:textSize="15sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:alpha="0.6"
|
||||
android:lineSpacingExtra="6dp"
|
||||
android:text="此选项默认开启,为确保名单内的数据为云端最新版本,你可以设置每天自动更新在线规则的时间,自动更新的地址为你最后一次成功设置的在线规则同步地址。\n请确保模块能够后台联网并不被阻止其它 APP 唤醒,否则自动同步可能会失败。\n模块无需保持在后台运行,到达同步时间后会自动启动,如果到达时间后模块正在运行则会自动取消本次计划任务。"
|
||||
android:textColor="@color/colorTextDark"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/notify_icon_auto_sync_child_item"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:gravity="center">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="17dp"
|
||||
android:layout_height="17dp"
|
||||
android:src="@drawable/ic_system_clock"
|
||||
app:tint="@color/colorTextGray" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center"
|
||||
android:singleLine="true"
|
||||
android:text="每天"
|
||||
android:textColor="@color/colorTextGray"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/notify_icon_auto_sync_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center"
|
||||
android:maxWidth="100dp"
|
||||
android:paddingLeft="5dp"
|
||||
android:paddingRight="5dp"
|
||||
android:singleLine="true"
|
||||
android:text="07:00"
|
||||
android:textColor="@color/colorTextGray"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/notify_icon_auto_sync_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_button_round"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center"
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingRight="10dp"
|
||||
android:paddingBottom="5dp"
|
||||
android:singleLine="true"
|
||||
android:text="修改时间"
|
||||
android:textColor="@color/colorTextGray"
|
||||
android:textSize="14sp" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
@@ -275,14 +661,36 @@
|
||||
android:layout_marginLeft="15dp"
|
||||
android:layout_marginTop="15dp"
|
||||
android:layout_marginRight="15dp"
|
||||
android:background="@drawable/permotion_round"
|
||||
android:background="@drawable/bg_permotion_round"
|
||||
android:elevation="0dp"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="15dp"
|
||||
android:paddingTop="15dp"
|
||||
android:paddingRight="15dp">
|
||||
|
||||
<com.fankes.miui.notify.view.MaterialSwitch
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center|start">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:src="@mipmap/ic_home" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0.85"
|
||||
android:singleLine="true"
|
||||
android:text="显示设置"
|
||||
android:textColor="@color/colorTextGray"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.fankes.miui.notify.ui.view.MaterialSwitch
|
||||
android:id="@+id/hide_icon_in_launcher_switch"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -296,9 +704,19 @@
|
||||
android:layout_marginBottom="10dp"
|
||||
android:alpha="0.6"
|
||||
android:lineSpacingExtra="6dp"
|
||||
android:text="隐藏模块图标后界面可能会被关闭,将不会再在桌面显示,你可以在 EdXposed、LsPosed 中找到模块设置并打开。"
|
||||
android:text="隐藏模块图标后界面可能会被关闭,将不会再在桌面显示,你可以在 EdXposed、LSPosed 中找到模块设置并打开。"
|
||||
android:textColor="@color/colorTextDark"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:alpha="0.6"
|
||||
android:lineSpacingExtra="6dp"
|
||||
android:text="注意:请务必在 LSPosed 中关闭“强制显示桌面图标”功能"
|
||||
android:textColor="#FF5722"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
@@ -307,32 +725,31 @@
|
||||
android:layout_marginLeft="15dp"
|
||||
android:layout_marginTop="15dp"
|
||||
android:layout_marginRight="15dp"
|
||||
android:background="@drawable/permotion_round"
|
||||
android:background="@drawable/bg_permotion_round"
|
||||
android:elevation="0dp"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:padding="15dp">
|
||||
android:padding="15dp"
|
||||
android:paddingTop="15dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_marginBottom="15dp"
|
||||
android:gravity="center|start">
|
||||
|
||||
<androidx.constraintlayout.utils.widget.ImageFilterView
|
||||
<ImageView
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:alpha="0.85"
|
||||
android:src="@mipmap/about"
|
||||
android:tint="@color/colorTextGray" />
|
||||
android:layout_marginEnd="10dp"
|
||||
android:src="@mipmap/ic_help" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0.85"
|
||||
android:singleLine="true"
|
||||
android:text="使用帮助与说明"
|
||||
android:text="使用帮助&说明"
|
||||
android:textColor="@color/colorTextGray"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
@@ -342,8 +759,8 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:alpha="0.8"
|
||||
android:lineSpacingExtra="6dp"
|
||||
android:text="Q.这个模块是如何诞生的?\nA.这个模块诞生来源于 MIUI 的乱改和不规范,本来 MIUI 9 之后,官方给出了原生通知图标样式,后面由于用户反应通知栏经常出现黑白块,这当然不是系统的错,而是国内 APP 极其不规范的通知图标设计,于是 MIUI 选择直接忽略这个问题把全部图标都改成了 APP 的彩色图标,使得之前拥有自有样式的原生图标也被破坏,通知中“setSmallIcon”不再有效,这个模块就是为了修复被 MIUI 开发组忽略的图标问题,并完美地给 MIUI 修复了黑白块图标的问题。"
|
||||
android:lineSpacingExtra="10dp"
|
||||
android:text="Q.这个模块是如何诞生的?\nA.这个模块诞生来源于 MIUI 的乱改和不规范,本来 MIUI 9 之后,官方给出了原生通知图标样式,后面由于用户反应通知栏经常出现黑白块。\n这当然不是系统的错,而是国内 APP 和 MIPUSH 的通知极其不规范的通知图标设计。\n但是呢,接到反馈后 MIUI 开发组选择直接忽略这个问题,在 2021-5-18 的开发版开始,把全部通知图标都改成了 APP 的彩色图标,使得之前拥有自有样式的原生图标也被破坏。\n对于 Android 开发者来说,官方文档中的 “setSmallIcon” 不再适用于魔改后的 MIUI,这将会严重破坏非常多的状态图标。\n当然,国内的手机生态除了 MIPUSH 的营销通知就是社交软件的通知,可能大部分人都不会在意这件事情。\n但是,这个模块就是为了修复被 MIUI 开发组忽略的图标问题才诞生的,并完美地给 MIUI 修复了黑白块图标的问题。"
|
||||
android:textColor="@color/colorTextDark"
|
||||
android:textSize="12sp" />
|
||||
|
||||
@@ -352,8 +769,8 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:alpha="0.8"
|
||||
android:lineSpacingExtra="6dp"
|
||||
android:text="Q.如何使用?\nA.模块仅支持 EdXposed、LsPosed,由于涉及到修改系统应用,不支持太极(阴)框架,在 LsPosed 的作用域中,只需勾选“系统界面”即可,应用设置后需要重启系统界面。"
|
||||
android:lineSpacingExtra="10dp"
|
||||
android:text="Q.如何使用?\nA.模块仅支持 LSPosed,EdXposed 也可以使用但随时停止支持,由于模块涉及到修改系统应用,不支持其它 Hook 框架,在 LSPosed 的作用域中,只需勾选“系统界面”(旧版本为“系统 UI”)即可,应用设置后需要重启系统界面。"
|
||||
android:textColor="@color/colorTextDark"
|
||||
android:textSize="12sp" />
|
||||
|
||||
@@ -362,8 +779,8 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:alpha="0.8"
|
||||
android:lineSpacingExtra="6dp"
|
||||
android:text="Q.哪些是已知问题?\nA.以下是问题描述列表:\n(1) MIUI 自己的系统应用的通知图标仍然可能出现黑白块的情况,可使用通知图标优化暂时修复其图标问题,后期只能等官方修复(基本上没什么可能性)。\n(2) 动态小图标可能会在高版本系统中闪烁,这是 MIUI 的问题,后期仍在想解决办法。\n(3) 使用 Zygisk 方式运行的 Lsposed 可能会发生通知优化图标 Hook 不生效的问题(出现黑白块),仅在最新版本的 MIUI 13 开发内测版中遇到,若出现问题请使用 Ramdisk 版本的 Lsposed。"
|
||||
android:lineSpacingExtra="10dp"
|
||||
android:text="Q.哪些是已知问题?\nA.以下是问题描述列表:\n(1) 动态小图标可能会在高版本系统中闪烁,这是 MIUI 自身就存在的问题,后期只能等官方修复。\n(2) 请始终保持最新版本的 LSPosed,旧版本可能会出现 Hook 不生效的问题,若最新版本依然不生效请在作用域中长按“系统界面”(“系统 UI”)选择重新优化。\n(3) 建议最低从 MIUI 12.5 “2021-5-18” 开发版以后开始使用,之前的版本可能或多或少存在 MIUI 自身 BUG 不生效、黑白块问题,将不再进行适配。"
|
||||
android:textColor="@color/colorTextDark"
|
||||
android:textSize="12sp" />
|
||||
|
||||
@@ -371,59 +788,12 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0.8"
|
||||
android:lineSpacingExtra="6dp"
|
||||
android:lineSpacingExtra="10dp"
|
||||
android:text="Q.如何反馈问题?\nA.酷安关注 @星夜不荟"
|
||||
android:textColor="@color/colorTextDark"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/link_with_project_address"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="15dp"
|
||||
android:layout_marginTop="15dp"
|
||||
android:layout_marginRight="15dp"
|
||||
android:background="@drawable/permotion_round"
|
||||
android:elevation="0dp"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:padding="15dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:gravity="center|start">
|
||||
|
||||
<androidx.constraintlayout.utils.widget.ImageFilterView
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:alpha="0.85"
|
||||
android:src="@mipmap/about"
|
||||
android:tint="@color/colorTextGray" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0.85"
|
||||
android:singleLine="true"
|
||||
android:text="项目地址"
|
||||
android:textColor="@color/colorTextGray"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0.8"
|
||||
android:lineSpacingExtra="6dp"
|
||||
android:text="本软件是免费开源项目,遵循 GPL 协议,你可以点击这里前往 Github 查看源码以及获取模块更新。\n严禁以任何形式贩卖、商用本软件,否则开发者有权追究其法律责任。"
|
||||
android:textColor="@color/colorTextDark"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -431,7 +801,7 @@
|
||||
android:layout_marginTop="15dp"
|
||||
android:layout_marginRight="15dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:background="@drawable/permotion_round"
|
||||
android:background="@drawable/bg_permotion_round"
|
||||
android:elevation="0dp"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
@@ -460,7 +830,7 @@
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@mipmap/qr_pay" />
|
||||
android:src="@mipmap/bg_qr_pay" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<TextView
|
||||
@@ -473,6 +843,35 @@
|
||||
android:textColor="@color/colorTextGray"
|
||||
android:textSize="16sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="15dp"
|
||||
android:layout_marginRight="15dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:background="@drawable/bg_permotion_round"
|
||||
android:gravity="center|start"
|
||||
android:orientation="horizontal"
|
||||
android:padding="10dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="35dp"
|
||||
android:layout_height="35dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:src="@mipmap/ic_yukihookapi" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:autoLink="web"
|
||||
android:ellipsize="end"
|
||||
android:lineSpacingExtra="6dp"
|
||||
android:maxLines="2"
|
||||
android:text="此模块使用 YukiHookAPI 构建。\n了解更多 https://github.com/fankes/YukiHookAPI"
|
||||
android:textColor="@color/colorTextGray"
|
||||
android:textSize="11sp" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</LinearLayout>
|
@@ -3,8 +3,9 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/permotion_round"
|
||||
android:background="@drawable/bg_permotion_round"
|
||||
android:baselineAligned="false"
|
||||
android:descendantFocusability="blocksDescendants"
|
||||
android:gravity="center|start"
|
||||
android:orientation="horizontal"
|
||||
android:padding="15dp"
|
||||
@@ -28,7 +29,7 @@
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:src="@mipmap/about"
|
||||
android:src="@mipmap/ic_about"
|
||||
android:tint="@color/colorTextGray" />
|
||||
|
||||
<TextView
|
||||
@@ -67,7 +68,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.fankes.miui.notify.view.MaterialSwitch
|
||||
<com.fankes.miui.notify.ui.view.MaterialSwitch
|
||||
android:id="@+id/adp_app_open_switch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="30dp"
|
||||
@@ -76,7 +77,7 @@
|
||||
android:textColor="@color/colorTextGray"
|
||||
android:textSize="13sp" />
|
||||
|
||||
<com.fankes.miui.notify.view.MaterialSwitch
|
||||
<com.fankes.miui.notify.ui.view.MaterialSwitch
|
||||
android:id="@+id/adp_app_all_switch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="30dp"
|
||||
|
24
app/src/main/res/layout/dia_icon_filter.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<?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:orientation="vertical"
|
||||
android:paddingLeft="15dp"
|
||||
android:paddingTop="15dp"
|
||||
android:paddingRight="15dp"
|
||||
tools:ignore="HardcodedText">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/dia_icon_filter_input_edit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:hint="可输入 APP 名称、包名"
|
||||
android:singleLine="true" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
</LinearLayout>
|
54
app/src/main/res/layout/dia_source_from.xml
Normal file
@@ -0,0 +1,54 @@
|
||||
<?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:orientation="vertical"
|
||||
android:paddingLeft="15dp"
|
||||
android:paddingTop="15dp"
|
||||
android:paddingRight="15dp"
|
||||
tools:ignore="HardcodedText">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="8.5dp"
|
||||
android:layout_marginRight="8.5dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:lineSpacingExtra="6dp"
|
||||
android:text="在线规则将不定期更新,建议定期同步列表以适配更多 APP,若无法同步请自行寻找解决方法或魔法上网。"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||
android:id="@+id/dia_sf_rd1"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="从 FastGit 获取" />
|
||||
|
||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||
android:id="@+id/dia_sf_rd2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="从 Github Raw 获取" />
|
||||
|
||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||
android:id="@+id/dia_sf_rd3"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="从自定义地址获取" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/dia_sf_text_lin"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/dia_sf_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:hint="请输入在线地址 URL"
|
||||
android:singleLine="true" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
</LinearLayout>
|
36
app/src/main/res/layout/dia_source_from_string.xml
Normal file
@@ -0,0 +1,36 @@
|
||||
<?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:orientation="vertical"
|
||||
android:paddingLeft="15dp"
|
||||
android:paddingTop="15dp"
|
||||
android:paddingRight="15dp"
|
||||
tools:ignore="HardcodedText">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="5dp"
|
||||
android:layout_marginRight="5dp"
|
||||
android:layout_marginBottom="17.5dp"
|
||||
android:lineSpacingExtra="6dp"
|
||||
android:text="此功能仅用于调试单条规则或多条规则,同步最新在线规则后这里的内容将会被覆盖清空。"
|
||||
android:textColor="@color/colorTextDark"
|
||||
android:textSize="13sp" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/dia_sfs_input_edit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="150dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center|start|top"
|
||||
android:hint="请粘贴 JSON 规则到此处"
|
||||
android:textSize="14sp" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
</LinearLayout>
|
26
app/src/main/res/layout/dia_status_icon_count.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<?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:orientation="vertical"
|
||||
android:paddingLeft="15dp"
|
||||
android:paddingTop="15dp"
|
||||
android:paddingRight="15dp"
|
||||
tools:ignore="HardcodedText">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/dia_status_icon_count_input_edit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:digits="0123456789"
|
||||
android:ellipsize="end"
|
||||
android:hint="请输入 0-100 之间的整数"
|
||||
android:inputType="number"
|
||||
android:singleLine="true" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
</LinearLayout>
|
Before Width: | Height: | Size: 201 KiB After Width: | Height: | Size: 201 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_basic.png
Normal file
After Width: | Height: | Size: 6.4 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_control.png
Normal file
After Width: | Height: | Size: 5.7 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_filter.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_github.png
Normal file
After Width: | Height: | Size: 5.8 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_help.png
Normal file
After Width: | Height: | Size: 5.6 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_home.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 6.9 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_modify.png
Normal file
After Width: | Height: | Size: 6.0 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_notify.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_page_bottom.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_page_top.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_restart.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_sync.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_yukihookapi.png
Normal file
After Width: | Height: | Size: 8.3 KiB |
Before Width: | Height: | Size: 5.1 KiB |
@@ -1,4 +1,4 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<resources>
|
||||
<!-- Base application theme. -->
|
||||
<style name="Theme.MIUINativeNotifyIcon" parent="Theme.Material3.DayNight">
|
||||
<!-- Primary brand color. -->
|
||||
@@ -10,7 +10,7 @@
|
||||
<item name="colorSecondaryVariant">@color/teal_200</item>
|
||||
<item name="colorOnSecondary">@color/black</item>
|
||||
<!-- Status bar color. -->
|
||||
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
|
||||
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
|
||||
<!-- Customize your theme here. -->
|
||||
</style>
|
||||
</resources>
|
6
app/src/main/res/values/array.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string-array name="module_scope">
|
||||
<item>com.android.systemui</item>
|
||||
</string-array>
|
||||
</resources>
|
@@ -1,3 +1,4 @@
|
||||
<resources>
|
||||
<string name="app_name">MIUI 原生通知图标</string>
|
||||
<string name="tile_name">通知图标</string>
|
||||
</resources>
|
@@ -1,4 +1,4 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<resources>
|
||||
<!-- Base application theme. -->
|
||||
<style name="Theme.MIUINativeNotifyIcon" parent="Theme.Material3.DayNight">
|
||||
<!-- Primary brand color. -->
|
||||
@@ -10,7 +10,7 @@
|
||||
<item name="colorSecondaryVariant">@color/teal_700</item>
|
||||
<item name="colorOnSecondary">@color/black</item>
|
||||
<!-- Status bar color. -->
|
||||
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
|
||||
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
|
||||
<!-- Customize your theme here. -->
|
||||
</style>
|
||||
</resources>
|