337 Commits
1.15 ... 2.7

Author SHA1 Message Date
d14b2cb551 Update version to 2.7 2022-05-31 03:54:21 +08:00
a864d4aa32 Added notify icon custom corner function 2022-05-31 03:49:10 +08:00
12029cf550 Update misc 2022-05-31 03:49:03 +08:00
ac4544e992 Added lower Android version warn 2022-05-31 02:27:35 +08:00
7f0597f034 Update YukiHookAPI 2022-05-31 02:10:49 +08:00
a7c02467de Fix mi push icon wrong when open force app icon in notify panel 2022-05-30 23:32:40 +08:00
107569607d Update version to 2.6 2022-05-30 03:47:52 +08:00
5d099d2ec6 Changed contributing way 2022-05-30 03:46:20 +08:00
45da218cc8 Added notify icon in notify panel used app icon function 2022-05-30 03:22:41 +08:00
9a8cc9378c Added warn dialog when enable replace all notify icon 2022-05-30 02:34:18 +08:00
d7620f62b1 Merge code 2022-05-30 02:13:49 +08:00
cf9f81be23 Merge to new way support receiver callback 2022-05-30 01:57:55 +08:00
2e1929f36e Merge systemBar support with native 2022-05-30 00:50:11 +08:00
cb6cbf0398 Added YukiPromoteTool 2022-05-30 00:35:03 +08:00
dbdd0fc514 Update YukiHookAPI 2022-05-29 04:17:27 +08:00
21f4ff9ad3 Update YukiHookAPI 2022-05-27 03:35:14 +08:00
1bc79056a9 Update YukiHookAPI 2022-05-25 04:38:00 +08:00
41cb741dff Changed FunctionFactory.kt 2022-05-12 01:09:16 +08:00
6578027a34 Changed Xposed Scope 2022-05-11 21:52:13 +08:00
01cb647f0c Update YukiHookAPI 2022-05-10 01:52:39 +08:00
171cd6a6d1 Make to pending 2022-05-09 01:01:33 +08:00
02f8852ab0 Fix Activity destroy non-null unregister bug 2022-05-09 00:56:26 +08:00
826805c552 Make SystemUIHooker singleton 2022-05-08 15:04:21 +08:00
627697d586 Update YukiHookAPI 2022-05-06 15:08:21 +08:00
f5615ff89f Update YukiHookAPI 2022-05-04 14:02:55 +08:00
dd45e57b00 Update YukiHookAPI 2022-05-04 10:15:02 +08:00
d73239de73 Update YukiHookAPI 2022-05-04 09:31:54 +08:00
deb0ca794f Update Kotlin version 2022-05-04 07:01:44 +08:00
84b3648626 Update YukiHookAPI 2022-05-04 06:55:49 +08:00
ae8fb6514c Update README.md 2022-05-04 06:45:14 +08:00
197f427adb Update YukiHookAPI 2022-05-01 11:59:30 +08:00
58a23b4537 Update README.md/PRIVACY.md 2022-04-26 00:28:05 +08:00
72bbdb69a8 Update PRIVACY.md 2022-04-26 00:20:42 +08:00
679ae26462 Merge code 2022-04-25 02:46:53 +08:00
eefa7ee9e7 Update YukiHookAPI 2022-04-18 03:13:50 +08:00
217d5d9bc3 Merge code 2022-04-15 15:28:59 +08:00
4d1e383ef5 Update YukiHookAPI 2022-04-15 05:18:34 +08:00
25399cd88b Update version to 2.5 2022-04-14 03:11:17 +08:00
18691d8b8d 更换通知刷新方案,彻底解决系统界面卡死问题 2022-04-14 02:55:43 +08:00
7c61b09054 Update YukiHookAPI 2022-04-13 04:59:35 +08:00
7a7e179a2b Merge code 2022-04-11 23:07:37 +08:00
dbd7dbf172 Update YukiHookAPI 2022-04-10 03:13:04 +08:00
502e5dc04b Update YukiHookAPI 2022-04-09 02:32:13 +08:00
ff0c57319a Update README.md 2022-04-09 01:50:24 +08:00
647a39c327 Update README.md 2022-04-05 22:45:32 +08:00
04e8d43356 加入新安装应用的通知图标优化适配通知忽略 DEBUG 版本的 APP 2022-04-05 21:56:37 +08:00
f85d2db36e Update YukiHookAPI 2022-04-04 22:55:09 +08:00
2e5284ebe9 Update version to 2.35 2022-04-04 13:55:10 +08:00
abffc4d853 Update version to 2.35 2022-04-04 13:54:42 +08:00
5d81b8ff87 尝试修复 MIUI 12 的问题 2022-04-04 13:48:54 +08:00
d91d2736e6 修复图标缓存过大造成系统界面停止运行的问题 2022-04-04 13:38:38 +08:00
72169989f2 Merge code 2022-04-04 12:04:12 +08:00
c85da002f5 Update YukiHookAPI 2022-04-04 03:13:19 +08:00
c09a1b5760 Update README.md 2022-03-30 20:56:52 +08:00
c30e56c5aa Update YukiHookAPI 2022-03-30 14:13:48 +08:00
822e988c16 Update version to 2.3 2022-03-29 23:50:37 +08:00
fc728a75a4 Update version to 2.3 2022-03-29 23:50:09 +08:00
256e2ebfce 优化 Android 12 风格通知图标深色模式的颜色 2022-03-29 23:47:21 +08:00
be4b952f62 修复折叠情况下的经典通知图标无变化问题,添加安卓 12 以下系统经典通知情况下图标颜色实时跟随壁纸功能 2022-03-29 23:14:57 +08:00
c7263c6d94 Fix a receiver bug 2022-03-29 21:46:20 +08:00
4733578912 Update YukiHookAPI 2022-03-29 21:05:49 +08:00
87879301f0 Update YukiHookAPI 2022-03-29 21:04:03 +08:00
c9be72e5f7 Update version to 2.2 2022-03-28 14:16:58 +08:00
0b6f55c49a Update version to 2.2 2022-03-28 14:06:56 +08:00
226d9395b6 Update version to 2.2 2022-03-28 14:01:45 +08:00
9877bf902f Merge code 2022-03-28 13:43:43 +08:00
0e43a7ce8c Merge code 2022-03-28 13:25:54 +08:00
d256c8024d Merge code 2022-03-28 11:56:07 +08:00
686671d2b8 Merge code 2022-03-28 03:34:04 +08:00
b2031f95a4 新增经典通知栏下也使用原生通知图标,不再限制经典样式取消激活模块,不支持 MIUI 12 2022-03-28 03:31:12 +08:00
d943aa6184 Merge code 2022-03-28 01:20:38 +08:00
21aa563a5f Merge code 2022-03-28 01:14:11 +08:00
009982c26f Merge code 2022-03-28 01:05:53 +08:00
47461809dc 增加允许建立非 HTTPS 的连接 2022-03-28 01:00:20 +08:00
e7dae611ba Update YukiHookAPI 2022-03-28 00:57:17 +08:00
da1f390d39 增加通知栏快捷磁贴打开在线规则列表功能 2022-03-26 12:26:00 +08:00
48ec0f9a72 Merge code 2022-03-26 02:33:38 +08:00
9393a87c63 Merge code 2022-03-25 23:47:20 +08:00
2fde4ae833 Merge code 2022-03-25 21:30:04 +08:00
bee5b21097 Merge code 2022-03-25 14:51:59 +08:00
bdda054d3a Merge code 2022-03-25 14:42:47 +08:00
66d578f172 Merge code 2022-03-25 14:41:55 +08:00
c8e3e67ce0 Merge code 2022-03-25 14:35:42 +08:00
378edf92eb Merge code 2022-03-25 14:31:35 +08:00
7d4db23346 Merge code 2022-03-25 14:21:20 +08:00
8f40f4b30c Merge code 2022-03-25 12:06:14 +08:00
442e57fd0a Merge code 2022-03-25 11:40:44 +08:00
6e3c627ad2 Merge code 2022-03-25 03:04:17 +08:00
299e93b25c Merge code 2022-03-25 02:01:52 +08:00
b8894e3bc0 Update YukiHookAPI 2022-03-25 01:52:42 +08:00
85a49122d0 Update YukiHookAPI 2022-03-25 00:59:58 +08:00
dba85cca89 Merge code 2022-03-24 15:08:32 +08:00
6b10523fb0 Merge code 2022-03-24 13:46:56 +08:00
048d7e4284 增加模块激活状态判断以及模块更新提醒 2022-03-24 13:37:08 +08:00
bc2dd8a973 增加模块激活状态判断以及模块更新提醒 2022-03-24 04:03:56 +08:00
646f30d05a Merge code 2022-03-24 02:00:29 +08:00
361b07a909 Merge code 2022-03-24 01:51:46 +08:00
8e3b575d38 Merge code 2022-03-24 01:14:04 +08:00
dff2c4d0c8 Merge code 2022-03-24 01:13:21 +08:00
6700ad96ad Merge code 2022-03-24 01:08:33 +08:00
cb6fdefee0 Merge code 2022-03-24 00:25:59 +08:00
3631d5e8c3 Merge code 2022-03-23 21:44:11 +08:00
e5af34d6db Merge code 2022-03-23 15:19:49 +08:00
abd7546dfe Merge code 2022-03-23 14:48:07 +08:00
12ce701334 修复动态设置图标时系统主题色透明问题 2022-03-23 14:04:24 +08:00
16e3780c97 Merge code 2022-03-23 03:22:12 +08:00
ca27c17c46 增加状态栏通知图标动态更新,取消对新的开发版修复通知图标只有一个的问题 2022-03-23 02:49:19 +08:00
cf80becf4e Merge code 2022-03-22 21:14:38 +08:00
a3689b4aaa Merge code 2022-03-22 21:13:42 +08:00
cd628e9329 Merge code 2022-03-22 03:00:50 +08:00
a36b1a8ba2 Merge code 2022-03-22 00:12:03 +08:00
5db1671a97 更新模块 UI 2022-03-21 23:18:52 +08:00
af3dace9d9 更新模块 UI 2022-03-21 15:24:42 +08:00
7616bf9370 Merge code 2022-03-21 14:03:22 +08:00
b124355601 Merge code 2022-03-21 13:52:49 +08:00
09a8f5644f 添加新应用安装后自动提醒适配通知图标功能 2022-03-21 03:33:28 +08:00
387bdd197b Update README.md 2022-03-20 22:31:32 +08:00
3c8d358c63 Update README.md 2022-03-20 22:16:13 +08:00
8c9dcc1706 Update README.md 2022-03-20 22:14:33 +08:00
b9a9979ef8 Update README.md 2022-03-20 22:13:20 +08:00
8809573353 Update README.md 2022-03-20 22:12:39 +08:00
0b7cb8f567 Update README.md 2022-03-20 22:11:22 +08:00
1b49271fd2 Update README.md 2022-03-20 21:51:51 +08:00
9492ae6022 Merge code 2022-03-20 21:05:35 +08:00
e509f0e6db Merge code 2022-03-20 14:11:08 +08:00
b610eca3b2 Merge code 2022-03-20 11:02:50 +08:00
3aff10fed5 Update YukiHookAPI 2022-03-20 03:33:55 +08:00
f29a0a9c64 Merge code 2022-03-20 00:36:20 +08:00
44dfb5abfe Merge code 2022-03-20 00:26:35 +08:00
e80b95004a Merge code 2022-03-20 00:21:38 +08:00
9b90004bff 尝试修复 MIPUSH 图标在 MIUI 12 上反色失败的问题 2022-03-19 23:40:14 +08:00
84bbaa5d8d Merge code 2022-03-19 23:28:51 +08:00
2d98fd0e1a Merge R8 Rules 2022-03-19 20:35:36 +08:00
0f2da2077e 布局更换为 ViewBinding 并适配 MD3 风格对话框 2022-03-19 14:35:39 +08:00
b8a843906a Update YukiHookAPI 2022-03-18 23:57:38 +08:00
2a76d8e3f0 Update YukiHookAPI 2022-03-18 14:46:26 +08:00
f0f3a37402 Merge code 2022-03-18 14:45:46 +08:00
3e50ca6db7 Update YukiHookAPI 2022-03-18 14:01:18 +08:00
c27f124b25 Update version to 2.16,fix more bugs. 2022-03-18 05:51:42 +08:00
Fankesyooni
09be1ea2c2 Update README.md 2022-03-18 05:51:22 +08:00
f5f90d712a Update version to 2.16,fix more bugs. 2022-03-18 05:50:02 +08:00
7a1f139adc Update version to 2.16,fix more bugs. 2022-03-18 05:49:44 +08:00
3ed382165b Update YukiHookAPI 2022-03-18 05:47:35 +08:00
5173051e66 修复一个通知图标颜色判断问题 2022-03-18 02:33:46 +08:00
c30ee53796 增加提醒在线规则更新功能 2022-03-18 00:29:21 +08:00
ae2fcda709 Update README.md 2022-03-17 23:57:23 +08:00
1a077259d1 更正全部图标为半透明效果 2022-03-17 23:48:40 +08:00
6e95239d94 更正全部图标为半透明效果 2022-03-17 23:19:50 +08:00
c1b08c93d0 更正黑色下的图标为半透明效果 2022-03-17 23:02:31 +08:00
90dda0aa52 Update version to 2.15,fix more bugs. 2022-03-17 11:33:53 +08:00
4699eb137e 再次修复通知图标个数对旧版本 MIUI 不生效的问题 2022-03-17 11:32:44 +08:00
ef47eef989 Update version to 2.1,fix more bugs. 2022-03-17 10:13:09 +08:00
7a5df6457f 修复状态栏通知个数显示导致隐藏图标无效的 BUG 2022-03-17 10:11:26 +08:00
3d977998c1 Update version to 2.0,fix more bugs. 2022-03-17 05:15:11 +08:00
014e073af6 Merge code 2022-03-17 05:14:29 +08:00
0be6b9c910 Merge code 2022-03-17 05:14:10 +08:00
3816aab335 更新帮助文案 2022-03-17 05:08:08 +08:00
3b77a1cd82 更新帮助文案 2022-03-17 05:07:17 +08:00
5c5fae4ef6 修改项目地址为图标 2022-03-17 05:03:52 +08:00
ea665fdc30 增加解除状态栏通知图标个数限制功能以及优化界面风格 2022-03-17 04:56:36 +08:00
740a250a59 修复状态栏图标不是纯黑的问题 2022-03-17 03:35:18 +08:00
f433da040c Merge code 2022-03-13 00:43:05 +08:00
00bf1acdb8 Update version to 1.95,fix more bugs. 2022-03-06 03:06:46 +08:00
099886b0b2 支持导入数组和非数组格式的 JSON 自定义规则,并加入支持合并非全部覆盖的功能 2022-03-06 02:59:32 +08:00
4109a25b5d Update YukiHookAPI 2022-03-06 02:18:53 +08:00
db93f8d48e 尝试修复部分 MIUI 状态栏图标反色不生效的问题 2022-03-06 02:12:58 +08:00
e6cff940a7 Update version to 1.9,fix more bugs. 2022-03-05 00:25:50 +08:00
3f7ea97812 ... 2022-03-05 00:20:25 +08:00
8f8810e92a 修改 MIUI 版本显示方式 2022-03-05 00:19:59 +08:00
e65624c044 修改 MIUI 版本显示方式 2022-03-05 00:19:37 +08:00
eabac2bd2d Update version 2022-03-05 00:11:30 +08:00
bde952c72c 更新新的在线规则地址并加入自定义功能 2022-03-04 23:22:29 +08:00
Fankesyooni
3e362591b6 Merge pull request #41 from pzcn/master
use CDN
2022-03-04 15:20:11 +08:00
pzcn
ea29c089f6 use CDN 2022-03-04 14:57:06 +08:00
cff1eb1958 Update README.md 2022-03-03 03:43:57 +08:00
83c98b2ad3 Update version to 1.87,fix more bugs. 2022-03-02 03:14:33 +08:00
0d7f323232 Update version to 1.87,fix more bugs. 2022-03-02 03:08:57 +08:00
0d63b0a14d Update version to 1.87,fix more bugs. 2022-03-02 03:08:28 +08:00
6684d7f376 更新 YukiHookAPI 2022-03-02 03:07:38 +08:00
89321af1ce 优化代码,加入保姆级别网络问题解答 2022-03-02 01:00:55 +08:00
d7a9f1e413 Update version to 1.86,fix more bugs. 2022-03-01 02:52:08 +08:00
edf199d9a6 Update version to 1.86,fix more bugs. 2022-03-01 02:51:09 +08:00
8d6a05e02c 修复 MIUI 在 Android 11 上最小化优先级图标的着色问题 2022-03-01 02:50:30 +08:00
c7d9b2661b 修复一个可能崩溃的问题 2022-02-27 23:29:43 +08:00
d0a32e08d9 Merge code 2022-02-27 22:48:01 +08:00
b0f9e44f8a Update version to 1.85,fix more bugs. 2022-02-27 00:51:24 +08:00
1e749d2f64 Update version to 1.85,fix more bugs. 2022-02-27 00:50:41 +08:00
c886bbd6cf Update version to 1.85,fix more bugs. 2022-02-27 00:49:32 +08:00
ec45839029 合并代码到新项目 2022-02-27 00:45:28 +08:00
6fd2294529 Merge remote-tracking branch 'origin/master' 2022-02-27 00:05:00 +08:00
Fankesyooni
5913da8183 Merge pull request #37 from naicfeng/patch-1
适配 航班管家 图标 #36
2022-02-27 00:04:38 +08:00
浅秋枫影
fcf2889668 fix iconBitmap 2022-02-27 00:01:03 +08:00
浅秋枫影
6d784f1283 适配 航班管家 图标 #36
适配 航班管家 图标 #36
2022-02-26 23:56:45 +08:00
cd8ceec765 完全修改 Hook 方案,加入新的日志打印方式 2022-02-26 22:57:11 +08:00
5325ac37d6 Update version to 1.8,fix more bugs. 2022-02-25 03:10:47 +08:00
07fa6965ad Update version to 1.8,fix more bugs. 2022-02-25 03:08:16 +08:00
4c88a5fbc6 Update version to 1.8,fix more bugs. 2022-02-25 03:07:32 +08:00
da61a52c13 将通知优化图标迁移至云端 2022-02-25 03:05:21 +08:00
3314f9fb57 bulit in online config test 2022-02-24 23:47:23 +08:00
ebb1bec36f 适配“主题壁纸”通知优化图标 2022-02-24 23:36:48 +08:00
Fankesyooni
d5d2e2107c Merge pull request #35 from sddpljx/master
修复 小米钱包 包名
2022-02-24 22:35:44 +08:00
sddpljx
c39d03f8c9 修复 小米钱包 包名 2022-02-24 22:23:32 +08:00
Fankesyooni
e20dfab5b1 Merge pull request #34 from sddpljx/master
适配 铁路12306 中国移动 中国联通 权限管理服务 小米智能卡 小米钱包 阿里巴巴 图标
2022-02-24 22:09:14 +08:00
sddpljx
ffc9be3721 修复 小米智能卡图标颜色 2022-02-24 21:06:20 +08:00
sddpljx
126aedabfd 增加 铁路12306 中国移动 中国联通 权限管理服务 小米智能卡 小米钱包 阿里巴巴 图标 2022-02-24 21:03:38 +08:00
56661b03e6 Update README.md 2022-02-20 16:14:36 +08:00
Fankesyooni
c45658be68 Update issue templates 2022-02-20 16:13:13 +08:00
e0443ff97c Update README.md 2022-02-20 14:13:01 +08:00
9af735e252 Update README.md 2022-02-20 14:01:45 +08:00
c67fe2fa31 Update version to 1.71,fix more bugs 2022-02-20 13:57:46 +08:00
b03cf30e0a 取消圆角彩色图标优化 2022-02-20 13:52:40 +08:00
09191802ad Update version to 1.7,fix more bugs 2022-02-20 12:42:45 +08:00
64f252986b 增加通知图标兼容模式,修改回之前的方案 2022-02-20 12:36:13 +08:00
c073d350d0 修改文案 2022-02-20 12:14:17 +08:00
cbeaaa8733 优化代码 2022-02-20 12:04:52 +08:00
3b5e066e2d Merge code 2022-02-20 03:44:34 +08:00
79843eb0d0 修复一个彩色图标判断失误的问题,重新发布版本 1.67 2022-02-20 01:22:56 +08:00
7a4e254230 Update version to 1.66,fix more bugs 2022-02-20 00:24:07 +08:00
0534ab9218 新增“QQ浏览器”、“QQ阅读”通知优化图标 2022-02-20 00:20:19 +08:00
5cee229a99 优化日志打印文本 2022-02-19 23:48:32 +08:00
b6920e3ca1 从 AOSP 源码提取工具类修复 💩 MIUI 对 Android 系统源码的破坏导致灰度图标无法判断 2022-02-19 23:46:03 +08:00
Fankesyooni
a4f7c95f84 Update issue templates 2022-02-19 22:26:16 +08:00
38803846cd Merge code 2022-02-19 03:12:04 +08:00
fb44c4e945 Update version to 1.65,fix more bugs 2022-02-18 23:24:04 +08:00
a2fc95d765 Update version to 1.65,fix more bugs 2022-02-18 23:22:53 +08:00
0e3ef5418c 优化“哔哩哔哩漫画”通知优化图标、增加“讯飞输入法”、“讯飞输入法小米版”通知优化图标 2022-02-18 23:20:30 +08:00
4e5e2cee09 优化代码 2022-02-18 04:10:17 +08:00
7b4b728523 移除不必要的 Hook,修复 MIUI 12 下依然卡顿的问题 2022-02-18 04:04:04 +08:00
9b6540df65 更新 YukiHookAPI 版本 2022-02-18 03:58:22 +08:00
3e8982aad0 Update IconPackParams.kt 2022-02-17 21:59:32 +08:00
085f2498c8 Update IconPackParams.kt 2022-02-17 21:58:09 +08:00
a1e01d1d33 Merge to pending 2022-02-17 21:54:18 +08:00
03aa550487 Update IconPackParams.kt 2022-02-17 21:52:22 +08:00
ea632b8892 Merge code 2022-02-17 21:51:10 +08:00
Fankesyooni
69847a0b0b Merge pull request #29 from sddpljx/master
优化 Jump 图标,增加 斗鱼 图标
2022-02-17 21:44:57 +08:00
sddpljx
4cdbfa944d 优化Jump图标,增加斗鱼图标 2022-02-17 16:21:29 +08:00
Fankesyooni
9edb04cf08 Merge pull request #28 from naicfeng/master
优化 工商银行 网易邮箱大师 小米音乐 图标
2022-02-17 14:39:19 +08:00
naicfeng
071c98e8f3 优化 工商银行 网易邮箱大师 小米音乐 图标 2022-02-17 09:18:47 +08:00
Fankesyooni
a317cc07f5 Update issue templates 2022-02-17 05:16:52 +08:00
ef0392a168 Update version to 1.6,fix more bugs 2022-02-17 05:10:53 +08:00
32e9ee3c8b 修正调整部分功能和文案 2022-02-17 05:03:23 +08:00
296f12d07a 修复一个设置逻辑错误的问题 2022-02-17 04:47:15 +08:00
df99256231 优化“浏览器”、“小米视频”通知优化图标 2022-02-17 04:29:33 +08:00
60128bcb1a 完全修复 MIUI 12 状态栏小图标无法对 MIPUSH 生效的问题,优化 MIPUSH 未经过适配的图标为 APP 图标包的图标 2022-02-17 04:18:50 +08:00
54aec1051f Merge code 2022-02-17 03:08:25 +08:00
121170ba65 增加“皮皮虾”、“智联招聘”、“京东金融”、“慢慢买”、“识货”、“BOSS直聘”通知优化图标 2022-02-17 02:53:44 +08:00
a2d282c3f1 增加“应用商店”、“百度贴吧”通知优化图标 2022-02-17 02:28:13 +08:00
4d0098f1b8 优化大量通知图标适配颜色 2022-02-17 02:17:33 +08:00
49f6bc921c 优化调试日志处理方式 2022-02-17 01:45:16 +08:00
f94286351b 优化部分代码 2022-02-17 01:25:31 +08:00
faad964359 fix 2022-02-17 01:15:05 +08:00
78308ac558 通知图标优化界面增加快速滚动按钮 2022-02-17 01:14:05 +08:00
03fd389e13 完善贡献者昵称 2022-02-17 00:44:12 +08:00
fb067577af 优化阿里云盘图标 2022-02-17 00:34:57 +08:00
da5d4eba1b 合并代码 2022-02-17 00:17:08 +08:00
Fankesyooni
aa22ee05c6 Update issue templates 2022-02-17 00:06:38 +08:00
08873b3e1f 更新贡献文案 2022-02-16 23:37:34 +08:00
7bfd2046ca 更新贡献者名称 2022-02-16 23:31:12 +08:00
f57e658900 Merge remote-tracking branch 'origin/master' 2022-02-16 23:30:32 +08:00
Fankesyooni
b7ec4559cf Merge pull request #26 from naicfeng/master
适配 网易邮箱大师 小米音乐
2022-02-16 23:30:14 +08:00
c707f8a3f7 更新贡献者名称 2022-02-16 23:29:34 +08:00
naicfeng
350823f4ec 适配 小米音乐 2022-02-16 23:22:44 +08:00
naicfeng
26c6241d38 适配 网易邮箱大师 2022-02-16 23:17:25 +08:00
Fankesyooni
6e0c42638f Merge pull request #25 from naicfeng/master
修改 工商银行 图标增加边界,适配 Jump/虎扑/IT之家 图标 #24
2022-02-16 22:45:18 +08:00
naicfeng
8c6d7d7258 修改 工商银行 图标增加边界,适配 Jump/虎扑/IT之家 图标 #24 2022-02-16 22:29:21 +08:00
8b9ecc1d87 规范资源文件命名 2022-02-16 03:38:37 +08:00
df1df6aabf Update version to 1.51,fix more bugs 2022-02-16 02:26:17 +08:00
e618efe29e Update version to 1.51,fix more bugs 2022-02-16 02:12:58 +08:00
9468c0b696 修复通知栏单色图标颜色不显示的问题,增加 MIPUSH 单色颜色填充图标优化改进 2022-02-16 02:09:15 +08:00
9bf843eef4 修复通知栏单色图标颜色不显示的问题,增加 MIPUSH 单色颜色填充图标优化改进 2022-02-16 02:08:59 +08:00
a0f40012c6 修复通知栏单色图标颜色不显示的问题,增加 MIPUSH 单色颜色填充图标优化改进 2022-02-16 02:08:20 +08:00
b82e6d8bff 增加“中国大学MOOC”通知优化图标 2022-02-15 21:58:48 +08:00
d117a9a6e9 增加通知优化图标过滤搜索功能,更新版本到 1.5 2022-02-15 21:52:10 +08:00
850a382025 增加多个通知优化图标 2022-02-15 20:14:23 +08:00
5623f5f261 Merge code 2022-02-15 13:29:46 +08:00
c706ee377a Merge new version 2022-02-15 13:24:47 +08:00
547d90c01f 预发布版本 2022-02-15 05:31:46 +08:00
f0391b1875 修复 MIUI 12 的通知栏严重卡顿的问题 2022-02-15 05:30:50 +08:00
7faa4ede7d Enable R8 2022-02-15 05:17:25 +08:00
c865b39c97 Refactor to YukiHookAPI https://github.com/fankes/YukiHookAPI 2022-02-15 05:14:06 +08:00
b8b23c3398 修复 commit 文件丢失问题 2022-02-13 01:16:40 +08:00
bdd53eba88 修复 MIPUSH 图标相关的问题 2022-02-12 21:50:15 +08:00
83a15171e2 Update README.md 2022-02-12 00:57:14 +08:00
Fankesyooni
12485db355 Update README.md 2022-02-12 00:53:47 +08:00
1d0b97e8a3 移除 LSPosed 通知优化图标 2022-02-11 20:06:36 +08:00
18ce5f66c5 加了点没用的东西 2022-02-11 20:03:48 +08:00
8725dabe85 更新文案,更新许可证至 A-GPL3.0 2022-02-10 20:03:13 +08:00
44e68ceca1 更新文案,更新许可证至 A-GPL3.0 2022-02-10 20:01:05 +08:00
5497ac7912 Update version to 1.36,fix more bugs. 2022-02-08 20:58:03 +08:00
60115b9ecf 加入白痴文案,修改部分设置,加入提示 2022-02-08 20:53:48 +08:00
b43975e4e8 重新修改“原神”、“崩坏3”、“最右”通知优化图标,增加“小米云服务”、“小米运动”、“钉钉”、“剪映”、“贝壳找房”通知优化图标 2022-02-08 19:34:50 +08:00
d346b9c0d2 Update version to 1.35,fix more bugs. 2022-02-08 01:09:43 +08:00
8f8c260069 Update version to 1.35,fix more bugs. 2022-02-08 00:49:22 +08:00
3461a28881 修复一个严重的判断问题,尝试修复 MIPUSH 图标不能 Hook 成功的问题 2022-02-08 00:45:34 +08:00
b1b99ccdfe 为 LSPosed 模块激活状态添加状态栏、通知栏图标 2022-02-08 00:21:46 +08:00
3aa7ee2a6a 为 LSPosed 模块激活状态添加状态栏、通知栏图标 2022-02-08 00:20:29 +08:00
1829a44eb3 预增加搜索功能 2022-02-07 23:46:40 +08:00
b5219a00cc 适配“虎牙直播”、“虎牙直播 Play版”、“云闪付”、“中国工商银行”、“中国农业银行”、“墨•状态栏歌词”、“车来了”、“腾讯微云”、“最右”、“学习通”、“波洞”、“哔哩哔哩漫画”、“航旅纵横”、“米游社”、“原神”、“崩坏3”通知优化图标 2022-02-07 23:40:19 +08:00
da81e12a60 修复 MIUI 12 MIPUSH 通知图标问题,修改文案 2022-02-07 22:55:02 +08:00
57a14fdaf1 预发布版本 2022-02-07 22:40:08 +08:00
be18502fd8 优化代码,加入适配说明 2022-02-07 22:38:31 +08:00
4914ae20b2 将 su 命令更换为 Magisk 的开源库 libsu 2022-02-07 21:54:28 +08:00
3b338214fc 修正文案 2022-02-07 21:44:44 +08:00
3a484e4a63 加入旧版状态栏小图标 Hook 方式日志记录 TAG 2022-02-07 21:36:23 +08:00
199ad9fc66 加入旧版状态栏小图标 Hook 方式日志记录 TAG 2022-02-07 21:34:38 +08:00
51e3eb8784 修复一个 Hook 异常疑似系统界面崩溃问题 2022-02-07 21:31:25 +08:00
e05d65e7e5 修正文案 2022-02-07 21:16:26 +08:00
2fb557afd8 Update version to 1.3,fix more bugs. 2022-02-07 00:46:59 +08:00
8737aaac30 Update version to 1.3,fix more bugs. 2022-02-07 00:30:34 +08:00
993ceb5050 Update version to 1.3,fix more bugs. 2022-02-07 00:13:22 +08:00
b1baaf4403 修复一个问题 2022-02-07 00:05:18 +08:00
db9f866178 修复一个可能的权限问题 2022-02-07 00:02:25 +08:00
f2bccafd92 修复一些问题 2022-02-07 00:01:15 +08:00
d798ca944d 改回去了😅 2022-02-06 23:54:29 +08:00
ca81a61aae 修正并更改一些文案 2022-02-06 23:48:23 +08:00
cd4f7be354 增加“京东”、“小爱同学”、“小米SIM激活服务”通知优化图标 2022-02-06 23:44:55 +08:00
6c961f044f 彻底修复 MIUI 12 通知图标的问题 2022-02-06 23:29:30 +08:00
485f85873c Update version to 1.25,fix more bugs. 2022-02-05 22:57:04 +08:00
8202239f57 通知优化图标展示界面顶部增加适配的图标个数展示 2022-02-05 22:39:19 +08:00
7e4cd7f71a 增加“下载管理程序”、“MIUI天气”、“米家”、“和平精英”、“起点读书”、“高德地图”、“百度地图”、“招商银行”、“人民日报”、“即可”通知优化图标 2022-02-05 22:30:53 +08:00
f6c4448eed 适配 MIUI 12,修复在 MIUI 12 上不生效的问题,加入最低 MIUI 版本判断 2022-02-05 21:42:35 +08:00
45dde844b7 Update version to 1.2,fix more bugs. 2022-02-03 22:04:09 +08:00
8e987897fc 增加帮助文案 2022-02-03 21:58:27 +08:00
60e2a5b6ea 增加模块设置缓存功能,防止通知图标过多造成下拉通知栏卡顿 2022-02-03 21:34:02 +08:00
8a31373ebd 优化代码 2022-02-03 21:27:18 +08:00
963933f168 修改“微信”通知优化小图标配置 2022-02-03 21:23:51 +08:00
a72e89e57c 增加“QQ邮箱”通知优化小图标 2022-02-03 21:23:17 +08:00
c40b1bf3ee 增加“多看阅读”、“闲鱼”、“美团”、“美团外卖”通知优化小图标 2022-02-03 21:19:19 +08:00
3045c90580 优化淘宝、抖音通知优化图标大小 2022-02-03 21:06:22 +08:00
8e9c0127fa 待发布版本 2022-02-02 15:59:47 +08:00
7da1949de3 默认关闭模块调试日志输出 2022-02-02 15:53:08 +08:00
1bbacad3d2 默认关闭模块调试日志输出 2022-02-02 15:52:46 +08:00
6e6b566ea1 优化 lamprose 提交的通知优化图标,增加“大众点评”、“小米视频”、“腾讯视频”、“QQ音乐”、“酷狗音乐”、“滴滴出行”、“菜鸟”通知优化图标 2022-02-02 15:51:57 +08:00
bf5cd8de2b 修复 2022-02-02 15:07:26 +08:00
Fankesyooni
ec5796f37e Merge pull request #2 from lamprose/master
增加”小米商城“,”饿了么“,”小米有品“,”携程“,”App分享“,”小米社区“,”网易云音乐“,”什么值得买“,”王者荣耀“通知优化图标
2022-02-02 02:50:39 +08:00
lamprose
51353caec2 增加”小米商城“,”饿了么“,”小米有品“,”携程“,”App分享“,”小米社区“,”网易云音乐“,”什么值得买“,”王者荣耀“通知优化图标 2022-02-02 02:28:17 +08:00
f3ca453a9a Fix a commit 2022-02-02 00:40:24 +08:00
105 changed files with 6208 additions and 3001 deletions

29
.github/ISSUE_TEMPLATE/----------.md vendored Normal file
View 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
View 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
View File

@@ -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
View File

@@ -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.30387540746106484" />
<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">

View File

@@ -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.以上

722
LICENSE

File diff suppressed because it is too large Load Diff

359
PRIVACY.md Normal file
View File

@@ -0,0 +1,359 @@
### MIUI 原生通知图标 隐私政策
> 简体中文
版本1.0
修订与生效日期2022年4月25日
#### 前言
为帮助您使用 MIUI 原生通知图标产品(以下简称“本产品”)或服务,我们可能收集与提供服务相关的设备信息或申请设备权限,您有权拒绝或撤回授权;
我们采取了互联网业内标准的技术措施和数据安全措施来保护您的设备信息安全;
除非再次征得您的同意,我们不会将您的设备信息用于本政策未载明的其他目的;
在阅读本协议前,请确认您已年满 18 岁,否则请在父母的陪同下阅读本协议。
#### 目录
```
1. 引言
2. 本产品处理设备信息的法律依据
3. 我们如何收集和使用您的设备信息
3.1 向您提供本产品和/或服务的核心业务功能
3.2 征得授权同意的例外
4. 我们如何转让、公开披露您的设备信息
4.1 转让您的设备信息
4.2 公开披露
4.3 共享、转让、公开披露设备信息授权同意的例外
5. 您管理设备信息的权利
5.1 设备权限调用
6. 如何更新与修改本政策
7. 争议解决
8. 名词解释
```
1. 引言
【特别提示】
请您在使用我们的各项产品和/或服务前,仔细阅读并充分理解本政策。一旦您使用或继续使用本产品/服务,即表示您同意我们按照本政策处理您的相关信息。
2. 本产品处理设备信息的法律依据
如果您是中华人民共和国大陆地区的用户,我们将依据《中华人民共和国网络安全法》、《信息安全技术 个人信息安全规范》GB/T 35273-2017以及其他相关法律法规收集和使用您的设备信息或申请设备权限为您提供本产品或服务。 我们通常只会在征得您同意的情况下收集您的设备信息。
3. 我们如何收集和使用您的设备信息
我们会遵循正当、合法、必要的原则,出于本政策所述的以下目的,收集和使用您在使用服务过程中主动提供或因使用本产品和/或服务而产生的设备信息。如果我们要将您的设备信息用于本政策未载明的其它用途,或基于特定目的将收集而来的信息用于其他目的,我们将以合理的方式向您告知,并在使用前再次征得您的同意。
3.1 向您提供本产品和/或服务的核心业务功能
为实现 本产品的核心业务功能,我们可能需要向您收集设备信息。以下将详细列出 本产品的核心业务功能及为实现该功能所需收集的设备信息,若您拒绝收集,则无法使用该服务。
查看设备中的所有应用信息。 本产品会读取您的设备应用列表;
搜索功能。 当您使用 本产品提供的搜索功能时,我们可能会使用应用数据缓存,收集您设备上的信息并进行本地存储。 该信息通常无法单独识别您的个人身份。
3.2 征得授权同意的例外
根据相关法律法规的规定,在以下情形中,我们可以在不征得您的授权同意的情况下收集、使用一些必要的设备信息:
```
a. 与国家安全、国防安全直接相关的;
b. 与公共安全、公共卫生、重大公共利益直接相关的;
c. 与犯罪侦查、起诉、审判和判决执行等直接相关的;
d. 出于维护您或其他个人的生命、财产等重大合法权益但又很难得到本人同意的;
e. 所收集的设备信息是您自行向社会公众公开的;
f. 从合法公开披露的信息中收集到您的设备信息,如从合法的新闻报道、政府信息公开等渠道;
g. 根据您的要求签订和履行合同所必需的;
h. 用于维护 本产品的产品和/或服务的安全稳定运行所必需的,例如发现、处置产品或服务的故障;
i. 法律法规规定的其他情形。
```
4. 我们如何共享、转让、公开披露您的设备信息
4.1 转让您的设备信息
除非获取您的明确同意,我们不会将您的设备信息转让给任何公司、组织或个人。
4.2 公开披露
除非获取您的明确同意,我们不会公开披露您的设备信息。
4.3 共享、转让、公开披露设备信息授权同意的例外
根据相关法律法规的规定,在以下情形中,我们可以在不征得您的授权同意的情况下共享、转让、公开披露您的设备信息:
```
A. 与国家安全、国防安全有关的;
B. 与公共安全、公共卫生、重大公共利益有关的;
C. 与犯罪侦查、起诉、审判和判决执行等有关的;
D. 出于维护您或其他个人的生命、财产等重大合法权益但又很难得到本人同意的;
E. 您自行向社会公众公开的设备信息;
F. 从合法公开披露的信息中收集到的设备信息的,如合法的新闻报道、政府信息公开等渠道。
G. 法律法规规定的其他情形。
```
根据法律规定,共享、转让经去标识化处理的设备信息,且确保数据接收方无法复原并重新识别设备信息主体的,不属于设备信息的对外共享、转让及公开披露行为,对此类数据的保存及处理将无需另行向您通知并征得您的同意。
5. 您管理设备信息的权利
5.1 设备权限调用
我们在提供服务的过程中,可能需要您开通一些设备权限,例如网络连接、查看设备应用列表等访问权限。 您也可以在设备的【设置】功能中随时选择关闭部分或者全部权限,从而拒绝我们收集您相应的设备信息。在不同设备中,权限显示方式及关闭方式可能有所不同,具体请参考设备及系统开发方说明或指引。
6. 如何更新与修改本政策
6.1 本政策为本产品的重要组成部分。 本产品保留不时更新或修改本政策的权利。
6.2 未经您明确同意,我们不会削减您按照本政策所应享有的权利。我们会通过 App 客户端推送通知、弹窗形式等合理方式通知您,以便您能及时了解本政策所做的任何变更。
6.3 对于重大变更,视具体情况我们 可能还会提供更为显著的通知 说明本政策的具体变更内容。 重大变更包括但不限于:
```
A. 我们的服务模式发生重大变化。如处理设备信息的目的、处理的设备信息类型、设备信息的使用方式等;
B. 我们在所有权结构、组织架构等方面发生重大变化。如业务调整、破产并购等引起的所有者变更等;
C. 设备信息共享、转让或公开披露的主要对象发生变化;
D. 您参与设备信息处理方面的权利及其行使方式发生重大变化;
E. 我们负责处理设备信息安全的责任部门、联络方式及投诉渠道发生变化;
F. 设备信息安全影响评估报告表明存在高风险时。
```
6.4 若您不同意修改后的隐私政策,您有权并应立即停止使用 本产品的服务。如果您继续使用 本产品的服务,则视为您接受 本产品对本政策相关条款所做的修改。
7. 争议解决
7.1 如果您认为我们的设备信息处理行为损害了您的合法权益,您也可向有关政府部门进行反映。
8. 名词解释
本隐私政策中使用到的名词,在通常意义中有如下定义:
设备信息: 设备信息是指以电子或者其他方式记录的能够单独或者与其他信息结合识别设备身份的各种信息,包括但不限于设备的品牌、型号、系统版本、 唯一设备标识符、 网络 IP 地址、Cookie等
设备: 设备是指可用于访问本产品和/或服务的装置,例如台式计算机、笔记本电脑、平板电脑或智能手机。 唯一设备标识符: 唯一设备标识符(专属 ID 或 UUID是指由设备制造商编入到设备中的一串字符可用于以独有方式标识相应设备例如手机的 IMEI
号)。唯一设备标识符有多种用途,其中可在不能使用 Cookie例如在移动应用程序中时用以提供广告。
IP 地址: 每台上网的设备都会指定一个编号,称为互联网协议 ( IP ) 地址。这些编号通常都是根据地理区域指定的。IP 地址通常可用于识别设备连接至互联网时所在的位置。
信息收集技术: 我们在《MIUI 原生通知图标 隐私政策》中所述的“自动收集”包括以下方式: A. Cookie曲奇档案 Cookie 是您浏览网页时,网站服务器放在客户端(您的计算机、移动电话或其他智能终端内)里面的一个小小的文本文件,当您再次访问相应网站时,网站就可通过
Cookie 识别您的浏览器。Cookie 可能会存储用户偏好及其他信息。您可以将浏览器配置为拒绝所有 Cookie 或在网站发送 Cookie 时显示提示。不过,如果没有 Cookie某些网站功能或服务可能无法正常工作。 B. Web beacon网络信标 Web beacon
是装嵌在网站或电邮内的电子图像文件案或其他技术,可用于计算访客数目、记录您是否及何时阅览电邮或网站,或用以使用某些 Cookie。 C. Log files日志文件 Log files 储存自动收集的若干数据。该等数据包括互联网协议( IP )地址、浏览器类型、互联网服务提供商(
ISP )、引用/退出页面、操作系统、日期/时间戳和点击流数据等。 D. ET Tag实体标签 ET Tag 是在互联网浏览器与互联网服务器之间背后传送的 HTTP 协议标头,可代替 Cookie用以追踪个别使用者使我们可更深入地了解和改善我们的服务。 E. JavaScript
JavaScript 是一种编程语言用于制作更具互动性和动态的网页。JavaScript 可以设定 Cookie、阅读 Cookie 及删除 Cookie。
算法: 计算机在执行解题运算时遵循的流程或一系列规则。
应用数据缓存: 应用数据缓存是指设备上的一种数据存储机制。使用它有很多好处,例如,可让网络应用在未连接互联网的情况下运行,以及可通过提高内容加载速度来改善相关应用的性能。
非个人身份信息: 记录的与用户相关的信息,但实际上不可直接或间接识别您身份的信息,包括经过去标识化、匿名化处理或化名方式提供的设备信息。
去标识化: 指通过对设备信息的技术处理,使其在不借助额外信息的情况下,无法识别设备信息主体的过程。
匿名化: 指通过对设备信息的技术处理,使得设备信息主体无法被识别,且处理后的信息不能被复原的过程。
服务器日志: 与大多数网站一样,我们的服务器会自动记录您在访问网站时所发出的网页请求。这些“服务器日志”通常包括您的网络请求、互联网协议地址、浏览器类型、浏览器语言、请求的日期和时间及可以唯一识别您的浏览器的一个或多个 Cookie。
### MIUINativeNotifyIcon Privacy Policy
> English
Version: 1.0
Amendment and effective date: April 25, 2022
#### Preface
In order to help you use MIUINativeNotifyIcon products (hereinafter referred to as "this product") or services, we may collect device information
related to the provision of services or apply for device permissions, and you have the right to refuse or withdraw authorization;
We have adopted technical measures and data security measures that are standard in the Internet industry to protect the security of your device
information;
Unless we obtain your consent again, we will not use your device information for other purposes not specified in this policy;
Before reading this agreement, please confirm that you are at least 18 years old, otherwise please read this agreement with your parents.
#### content
````
1 Introduction
2. Legal basis for this product to process device information
3. How we collect and use your device information
3.1 Provide you with the core business functions of this product and/or service
3.2 Exceptions to Authorized Consent
4. How we transfer and publicly disclose your device information
4.1 Transfer your device information
4.2 Public disclosure
4.3 Exceptions to Authorization and Consent for Sharing, Transfer, and Public Disclosure of Device Information
5. Your Right to Manage Device Information
5.1 Device permission call
6. How to update and modify this policy
7. Dispute Resolution
8. Glossary
````
1 Introduction
【Special Note】
Please read and fully understand this policy before using our products and/or services. Once you use or continue to use this product/service, you
agree that we will process your relevant information in accordance with this policy.
2. Legal basis for this product to process device information
If you are a user in the mainland of the People's Republic of China, we will collect and use your Device information or apply for device
permissions to provide you with this product or service. We generally only collect your device information with your consent.
3. How we collect and use your device information
We will follow the principles of legitimacy, lawfulness, and necessity, and for the following purposes described in this policy, to collect and
use the device information that you actively provide during the use of the service or that arises from the use of this product and/or service. If
we want to use your device information for other purposes not specified in this policy, or use the collected information for other purposes based
on a specific purpose, we will inform you in a reasonable manner and ask again before use with your consent.
3.1 Provide you with the core business functions of this product and/or service
In order to implement the core business functions of this product, we may need to collect device information from you. The following will list in
detail the core business functions of this product and the device information that needs to be collected to achieve this function. If you refuse
to collect, you cannot use the service.
View all app information on the device. This product will read your device application list;
searching feature. When you use the search function provided by this product, we may use application data cache, collect information on your
device and store it locally. This information generally does not individually identify you as an individual.
3.2 Exceptions to Authorized Consent
According to relevant laws and regulations, we may collect and use some necessary device information without your authorization and consent under
the following circumstances:
````
a. Directly related to national security and national defense security;
b. Directly related to public safety, public health, and major public interests;
c. Directly related to criminal investigation, prosecution, trial and execution of judgments;
d. In order to protect your or other personal life, property and other major legitimate rights and interests, but it is difficult to obtain my consent;
e. The collected device information is disclosed to the public by you;
f. Your device information is collected from legally publicly disclosed information, such as legal news reports, government information disclosure and other channels;
g. Necessary to enter into and perform a contract at your request;
h. Necessary to maintain the safe and stable operation of the products and/or services of this product, such as finding and disposing of faults in the products or services;
i. Other situations stipulated by laws and regulations.
````
4. How we share, transfer, and publicly disclose your device information
4.1 Transfer your device information
We will not transfer your device information to any company, organization or individual without your express consent.
4.2 Public disclosure
We will not publicly disclose your device information without your express consent.
4.3 Exceptions to Authorization and Consent for Sharing, Transfer, and Public Disclosure of Device Information
According to relevant laws and regulations, we may share, transfer and publicly disclose your device information without your authorization and
consent in the following circumstances:
````
A. Related to national security and national defense security;
B. Related to public safety, public health, and major public interests;
C. Related to criminal investigation, prosecution, trial and execution of judgments;
D. In order to protect your or other personal life, property and other major legitimate rights and interests, but it is difficult to obtain my consent;
E. The device information that you disclose to the public by yourself;
F. Device information collected from legally publicly disclosed information, such as legal news reports, government information disclosure and other channels.
G. Other situations stipulated by laws and regulations.
````
According to the law, sharing and transferring de-identified device information and ensuring that the data recipient cannot restore and
re-identify the subject of the device information is not an act of external sharing, transfer and public disclosure of device information.
Storage and processing will not be required to notify you and obtain your consent.
5. Your Right to Manage Device Information
5.1 Device permission call
In the process of providing services, we may require you to activate some device permissions, such as network connection, viewing device
application list and other access permissions. You can also choose to turn off some or all permissions at any time in the [Settings] function of
the device, thereby refusing us to collect your corresponding device information. In different devices, the display method and closing method of
permissions may be different. For details, please refer to the instructions or guidelines of the device and system developers.
6. How to update and modify this policy
6.1 This policy is an important part of this product. This product reserves the right to update or modify this policy from time to time.
6.2 We will not reduce your rights under this Policy without your express consent. We will notify you through reasonable means such as app client
push notifications and pop-up windows, so that you can keep abreast of any changes to this policy.
6.3 For major changes, we may also provide a more prominent notice to explain the specific changes to this policy as the case may be. Significant
changes include, but are not limited to:
````
A. Significant changes to our service model. Such as the purpose of processing device information, the type of device information processed, the way of using device information, etc.;
B. We have made significant changes in our ownership structure, organizational structure, etc. Such as changes in owners caused by business adjustments, bankruptcy mergers and acquisitions, etc.;
C. The main object of equipment information sharing, transfer or public disclosure has changed;
D. Significant changes in your rights to participate in the processing of device information and the way you exercise it;
E. The responsible department, contact information and complaint channel that we are responsible for handling equipment information security have changed;
F. When the equipment information security impact assessment report indicates that there is a high risk.
````
6.4 If you do not agree with the revised Privacy Policy, you have the right and should immediately stop using the services of this product. If
you continue to use the services of this product, it is deemed that you accept the modifications made by this product to the relevant terms of
this policy.
7. Dispute Resolution
7.1 If you believe that our device information processing has damaged your legitimate rights and interests, you can also report to the relevant
government departments.
8. Glossary
Terms used in this Privacy Policy have the following definitions in their usual meanings:
Device information: Device information refers to various information recorded electronically or in other ways that can identify the identity of
the device alone or in combination with other information, including but not limited to the brand, model, system version, unique device
identifier, network IP address of the device , Cookies, etc.;
Device: A device is a device that can be used to access the Product and/or Service, such as a desktop computer, laptop, tablet or smartphone.
Unique Device Identifier: A Unique Device Identifier (Unique ID or UUID) is a string of characters programmed into a device by the device
manufacturer that can be used to uniquely identify the device (such as the IMEI of a mobile phone)
No). Unique device identifiers are used for a variety of purposes, including serving advertisements when cookies cannot be used, such as in
mobile applications.
IP Address: Every device that goes online is assigned a number called an Internet Protocol (IP) address. These numbers are usually assigned by
geographic area. An IP address can often be used to identify where a device is connected to the Internet.
Information collection technology: The "automatic collection" described in the "MIUINativeNotifyIcon Privacy Policy" includes the following
methods: A. Cookie (cookie file) Cookie is when you browse the web, the website server places it on the client (your A small text file in a
computer, mobile phone or other intelligent terminal), when you visit the corresponding website again, the website can pass Cookies identify your
browser. Cookies may store user preferences and other information. You can configure your browser to refuse all cookies or to display a prompt
when a website sends a cookie. However, some website features or services may not function properly without cookies. B. Web beacon (web beacon)
Web beacon An electronic image file or other technology embedded in a website or email that can be used to count visitors, record whether and
when you view an email or website, or to use certain cookies. C. Log files Log files store certain data collected automatically. This data
includes Internet Protocol (IP) address, browser type, Internet Service Provider (
ISP), referring/exit pages, operating system, date/time stamp and clickstream data, etc. D. ET Tag (Entity Tag) ET Tag is an HTTP protocol header
transmitted behind the Internet browser and Internet server, which can replace cookies to track individual users, so that we can better
understand and improve our Serve. E. JavaScript JavaScript is a programming language used to make more interactive and dynamic web pages.
JavaScript can set cookies, read cookies and delete cookies.
Algorithm: A process or set of rules that a computer follows when performing a problem-solving operation.
App data cache: App data cache refers to a data storage mechanism on the device. There are many benefits to using it, such as allowing web
applications to run without an internet connection, and improving the performance of related applications by increasing the speed of content
loading.
Non-Personally Identifiable Information: Information that is recorded about a user but does not actually identify you directly or indirectly,
including device information that has been de-identified, anonymized, or provided under a pseudonym.
De-identification: refers to the process of technical processing of device information to make it impossible to identify the subject of device
information without the aid of additional information.
Anonymization: refers to the process in which the subject of the device information cannot be identified and the processed information cannot be
recovered through the technical processing of the device information.
Server Logs: Like most websites, our servers automatically log the web page requests you make while visiting the website. These "server logs"
typically include your web request, internet protocol address, browser type, browser language, date and time of the request, and one or more
cookies that uniquely identify your browser.

151
README.md
View File

@@ -1,87 +1,136 @@
# MIUI 原生通知图标
![Eclipse Marketplace](https://img.shields.io/badge/build-passing-brightgreen)
![Eclipse Marketplace](https://img.shields.io/badge/license-GPL3.0-blue)
![Eclipse Marketplace](https://img.shields.io/badge/version-v1.15-green)
[![Blank](https://img.shields.io/badge/build-passing-brightgreen)](https://github.com/fankes/MIUINativeNotifyIcon)
[![Blank](https://img.shields.io/badge/license-AGPL3.0-blue)](https://github.com/fankes/MIUINativeNotifyIcon/blob/master/LICENSE)
[![Blank](https://img.shields.io/badge/version-v2.7-green)](https://github.com/fankes/MIUINativeNotifyIcon/releases)
[![Blank](https://img.shields.io/github/downloads/fankes/MIUINativeNotifyIcon/total?label=Release)](https://github.com/fankes/MIUINativeNotifyIcon/releases)
[![Blank](https://img.shields.io/github/downloads/Xposed-Modules-Repo/com.fankes.miui.notify/total?label=LSPosed%20Repo&logo=Android&style=flat&labelColor=F48FB1&logoColor=ffffff)](https://github.com/Xposed-Modules-Repo/com.fankes.miui.notify/releases)
[![Telegram](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](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'>![Eclipse Marketplace](https://img.shields.io/badge/download-v1.15-green)</a>
<br/><br/>
⚠️适配说明<br/>
[酷安 @星夜不荟](http://www.coolapk.com/u/876977)
- 此模块仅支持 Lsposed(作用域“系统界面”)、EdXposed(不推荐)、不支持太极无极(阴)
- 目前最低支持基于 Android 9 版本的 MIUI12 或 MIUI12.5(建议)
## 适配说明
# 禁止任何商业用途
- 此模块仅支持 <b>LSPosed</b>(作用域“系统界面”)、<b>~~EdXposed(随时停止支持)~~</b>、不支持<b>太极、无极</b>
本模块完全开源免费,如果好用你可以打赏支持开发,严禁未经许可进行二改贩卖,违者必惩必究。
- 请确保你使用的是 MIUI 官方版本,任何第三方官改包发生的问题,开发者没有义务去解决和修复,请自求多福
# 开始贡献
- 目前最低支持基于 Android 9 版本的 MIUI 12 或 MIUI 12.5(最低建议)
由于国内厂商 APP 的不规范彩色图标影响整体图标的美观,现在开放第三方 APP 的通知图标适配。<br/>
欢迎为通知图标优化名单贡献宝贵资源!<br/>
- 建议最低从 MIUI 12.5 `2021-5-18` 开发版以后开始使用模块,之前的版本可能或多或少存在 MIUI 自身 BUG 不生效、黑白块的问题
- [CONTRIBUTING](https://github.com/fankes/MIUINativeNotifyIcon/blob/master/CONTRIBUTING.md)
- 请始终保持最新版本的 LSPosed旧版本可能会出现 Hook 不生效的问题,若最新版本依然不生效请在作用域中长按“系统界面”(“系统 UI”)选择重新优化
# 历史背景
## 请勿用于非法用途
这个模块诞生来源于 MIUI 的乱改和不规范,本来 MIUI 9 之后,官方给出了原生通知图标样式,后面由于用户反应通知栏经常出现黑白块。 这当然不是系统的错,而是国内 APP 极其不规范的通知图标设计,于是 MIUI
选择直接忽略这个问题把全部图标都改成了 APP 的彩色图标, 使得之前拥有自有样式的原生图标也被破坏通知中“setSmallIcon”不再有效这个模块就是为了修复被 MIUI 开发组忽略的图标问题, 并完美地给 MIUI 修复了黑白块图标的问题。
<br/>
- 本模块完全开源免费,如果好用你可以打赏支持开发,但是请不要用于非法用途。
# 探索历程
- 本模块发布地址仅有 [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) 及**酷安应用市场**
,从其他非正规渠道下载到的版本或对您造成任何影响均与我们无关。
- 原生 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
选择放弃原生通知功能,而做出这种违反原生通知规则的做法,而这些彩色图标被设置为单色调图标,也确实会发生黑白块的问题,但是同时又会破坏遵守规范的图标。
- 真的没有办法了吗?在不断探索下,我找到了原生支持色彩判断的类
## 贡献通知图标优化名单
```
此项目是 `AndroidNotifyIconAdapt` 项目的一部分,详情请参考下方。
- [Android 通知图标规范适配计划](https://github.com/fankes/AndroidNotifyIconAdapt)
## 历史背景
这个模块诞生来源于 MIUI 的乱改和不规范,本来 MIUI 9 之后,官方给出了原生通知图标样式,后面由于用户反应通知栏经常出现黑白块。
这当然不是系统的错,而是国内 APP 和 `MIPUSH` 的通知极其不规范的通知图标设计。
但是呢,接到反馈后 MIUI 开发组选择直接忽略这个问题,在 `2021-5-18` 的开发版开始,把全部通知图标都改成了 APP 的彩色图标,使得之前拥有自有样式的原生图标也被破坏。
对于 Android 开发者来说,官方文档中的 `setSmallIcon` 不再适用于魔改后的 MIUI这将会严重破坏非常多的状态图标。
当然,国内的手机生态除了 `MIPUSH` 的营销通知就是社交软件的通知,可能大部分人都不会在意这件事情。
但是,这个模块就是为了修复被 MIUI 开发组忽略的图标问题才诞生的,并完美地给 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 把通知图标改成了这个鬼样子,寻找开发组提案也是无人问津,最后转念一想,自己干吧。
由于目前大量通知图标都来自 `MIPUSH` 发出的营销通知,而 `MIPUSH` 的图标都是统一的彩色应用图标,很多应用也没有适配这一特性, 在通知栏广告满天飞的情况下MIUI
选择放弃原生通知功能,而做出这种违反原生通知规则的做法,而这些彩色图标被设置为单色调图标,也确实会发生黑白块的问题,但是同时又会破坏遵守规范的图标。
真的没有办法了吗?在不断探索下,我找到了原生支持色彩判断的类。
```kotlin
com.android.internal.util.ContrastColorUtil
```
- 这个类中有一个方法可以拿出来判断图标的灰度效果
这个类中有一个方法可以拿出来判断图标的灰度效果
```java
ContrastColorUtil.getInstance().isGrayscaleIcon(drawable);
```kotlin
ContrastColorUtil.getInstance().isGrayscaleIcon(drawable)
```
- 问题就被解决了,顺便修了一下被 MIUI 破坏的通知图标以及优化了一下应用本身方块图标的圆角...
- 最后,我想大声问一句 MIUI 开发组:“就这?” 就这么简单的问题为什么拖了这么长时间也没有结论,还要交给用户去修复,这真的是一种负责任的表现吗?
- 后来一想,也是啊,被国内生态毒害的用户,怎么可能会去想到这些问题呢,最后只能是我自作多情,还对 MIUI 留有一点情怀吧。
- ——来自一个无可奈何的 MIUI 老用户
问题就被解决了,顺便修了一下被 MIUI 破坏的通知图标以及优化了一下应用本身方块图标的圆角......
# 许可证
最后,我想大声问一句 MIUI 开发组:“就这?” 就这么简单的问题为什么拖了这么长时间也没有结论,还要交给用户去修复,这真的是一种负责任的表现吗?
- [GPL-3.0](https://www.gnu.org/licenses/gpl-3.0.html)
后来一想,也是啊,被国内生态毒害的用户,怎么可能会去想到这些问题呢,最后只能是我自作多情,还对 MIUI 留有一点情怀吧。
——来自一个无可奈何的 MIUI 老用户
## 后记
近期重新适配了 MIUI 12、12.5、13 版本,每个版本的图标设置方法都不一样,而且改的乱七八糟的,我都要无语了,只能用了很多折中方案,毕竟我也没有那么大精力每个版本去修复,实在是累了。
特地的把自己能有的小米手机刷成各种 MIUI 版本去为酷友做专项适配,我也是很累了,也希望你们能够多多支持,也能让 MIUI 做得更好。
MIUI 再不重写,怕是永远会变成安卓之光。雷军,金凡!!
## 捐赠支持
- 工作不易,无意外情况此项目将继续维护下去,提供更多可能,欢迎打赏。<br/><br/>
<img src="https://github.com/fankes/YuKiHookAPI/blob/master/img-src/wechat_code.jpg" width = "200" height = "200"/>
## 隐私政策
- [PRIVACY](https://github.com/fankes/MIUINativeNotifyIcon/blob/master/PRIVACY.md)
## 许可证
- [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)
版权所有 © 2019-2022 Fankes Studio(qzmmcn@163.com)

View File

@@ -1,6 +1,7 @@
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'com.google.devtools.ksp' version '1.6.21-1.0.5'
}
android {
@@ -19,44 +20,55 @@ android {
defaultConfig {
applicationId "com.fankes.miui.notify"
minSdk 26
targetSdk 26
versionCode 3
versionName "1.15"
minSdk 28
targetSdk 31
versionCode rootProject.ext.appVersionCode
versionName rootProject.ext.appVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
minifyEnabled rootProject.ext.enableR8
shrinkResources rootProject.ext.enableR8
zipAlignEnabled rootProject.ext.enableR8
signingConfig signingConfigs.debug
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
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'
freeCompilerArgs = [
'-Xno-param-assertions',
'-Xno-call-assertions',
'-Xno-receiver-assertions'
]
}
buildFeatures {
viewBinding true
}
lintOptions {
checkReleaseBuilds 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.92'
ksp 'com.highcapable.yukihookapi:ksp-xposed:1.0.92'
implementation "com.github.topjohnwu.libsu:core:3.1.2"
implementation 'androidx.annotation:annotation:1.3.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.+'
implementation 'com.google.android.material:material:1.6.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

View File

@@ -20,29 +20,25 @@
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-dontwarn
-ignorewarnings
-optimizationpasses 10
-dontusemixedcaseclassnames
-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**
-assumenosideeffects class kotlin.jvm.internal.Intrinsics {
public static *** throwUninitializedProperty(...);
public static *** throwUninitializedPropertyAccessException(...);
}
-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
-keepclassmembers class * implements androidx.viewbinding.ViewBinding {
*** inflate(android.view.LayoutInflater);
}

View File

@@ -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>

View File

@@ -1 +1 @@
com.fankes.miui.notify.hook.HookMain
com.fankes.miui.notify.hook.HookEntry_YukiHookXposedInit

View File

@@ -0,0 +1 @@
com.fankes.miui.notify.hook.HookEntry

View File

@@ -1,50 +1,36 @@
/**
* 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")
package com.fankes.miui.notify.application
import android.app.Application
import androidx.appcompat.app.AppCompatDelegate
import com.highcapable.yukihookapi.hook.xposed.application.ModuleApplication
class MNNApplication : Application() {
companion object {
/** 全局静态实例 */
private var context: MNNApplication? = null
/** 调用全局静态实例 */
val appContext get() = context ?: error("App is death")
/** 自身 APP 是否已启动 */
var isMineStarted = false
}
class MNNApplication : ModuleApplication() {
override fun onCreate() {
super.onCreate()
/** 设置状态 */
isMineStarted = true
/** 设置静态实例 */
context = this
/** 跟随系统夜间模式 */
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
}

View File

@@ -1,46 +1,59 @@
/**
* 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 是否默认启用完全替换
* @param isEnabled 是否默认启用替换彩色图标 - 关闭后将全部停止替换
* @param isEnabledAll 是否默认启用替换全部图标
*/
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" +
" }"
}

View File

@@ -0,0 +1,48 @@
/*
* 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_FORCE_APP_ICON = PrefsData("_notify_icon_force_app_icon", false)
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_CORNER = PrefsData("_notify_icon_corner", 15)
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 IGNORED_ANDROID_VERSION_TO_LOW = PrefsData("_ignored_android_version_to_low", false)
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", "")
}

View 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"
}

View File

@@ -0,0 +1,62 @@
/*
* 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.IYukiHookXposedInit
@InjectYukiHookWithXposed(isUsingResourcesHook = false)
class HookEntry : IYukiHookXposedInit {
override fun onInit() = configs {
debugTag = "MIUINativeNotifyIcon"
isDebug = false
}
override fun onHook() = encase {
loadApp(SYSTEMUI_PACKAGE_NAME) {
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 -> loadHooker(SystemUIHooker)
}
}
}
}

View File

@@ -1,524 +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")
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 NotificationUtilClass =
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.NotificationUtil"
private const val NotificationHeaderViewWrapperInjectorClass =
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.row.wrapper.NotificationHeaderViewWrapperInjector"
private const val ExpandedNotificationClass =
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.ExpandedNotification"
private const val SystemUIApplicationClass = "$SYSTEMUI_PACKAGE_NAME.SystemUIApplication"
private const val ContrastColorUtilClass = "com.android.internal.util.ContrastColorUtil"
}
/** 仅作用于替换的 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
}
}
/** 仅作用于替换的 Hook 方法体 */
private val replaceToFalse = object : XC_MethodReplacement() {
override fun replaceHookedMethod(param: MethodHookParam?): Any {
return false
}
}
/**
* 忽略异常运行
* @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 = true)) 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 = true)) 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 [Class]
*/
private fun XC_LoadPackage.LoadPackageParam.findClass(name: String) =
classLoader.loadClass(name)
/**
* ⚠️ 这个是修复彩色图标的关键核心代码判断
* 判断是否为灰度图标 - 反射执行系统方法
* @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
}
/**
* 获取 [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 ?: ""
}
} catch (_: Throwable) {
"unknown"
}
/**
* 获取全局上下文
* @return [Context]
*/
private val XC_LoadPackage.LoadPackageParam.globalContext
get() = findClass(SystemUIApplicationClass)
.getDeclaredMethod("getContext").apply { isAccessible = true }
.invoke(null) as Context
/**
* Hook 状态栏小图标
* 区分系统版本 - 由于每个系统版本的方法不一样这里单独拿出来进行 Hook
* @param param Hook Param
*/
private fun XC_LoadPackage.LoadPackageParam.hookSmallIconOnSet(param: XC_MethodHook.MethodHookParam) =
runWithoutError(error = "GetSmallIconOnSet") {
/** 获取通知小图标 */
val iconDrawable = (param.result as Icon).loadDrawable(globalContext)
/** 判断是否不是灰度图标 */
val isNotGrayscaleIcon = !isGrayscaleIcon(globalContext, iconDrawable)
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
(param.args?.get(0) as? StatusBarNotification?)?.also { notifyInstance ->
/** 目标彩色通知 APP 图标 */
var customIcon: Icon? = null
if (HookMedium.getBoolean(HookMedium.ENABLE_COLOR_ICON_HOOK, default = true))
run {
IconPackParams.iconDatas.forEach {
if ((notifyInstance.opPkgName == it.packageName ||
findAppName(notifyInstance) == it.appName) &&
HookMedium.isAppNotifyHookOf(it)
) {
if (isNotGrayscaleIcon || HookMedium.isAppNotifyHookAllOf(it))
customIcon = Icon.createWithBitmap(it.iconBitmap)
return@run
}
}
}
when {
/** 如果开启了修复 APP 的彩色图标 */
customIcon != null && HookMedium.getBoolean(HookMedium.ENABLE_NOTIFY_ICON_HOOK, default = true) ->
logD(
content = "GetSmallIconOnSet -> " +
"hook Custom AppIcon [pkgName] ${notifyInstance.opPkgName} " +
"[appName] ${findAppName(notifyInstance)}"
) { param.result = customIcon }
/** 若不是灰度图标自动处理为圆角 */
isNotGrayscaleIcon ->
logD(
content = "GetSmallIconOnSet -> " +
"hook Color AppIcon [pkgName] ${notifyInstance.opPkgName} " +
"[appName] ${findAppName(notifyInstance)}"
) {
param.result = Icon.createWithBitmap(
iconDrawable.toBitmap().round(15.dp(globalContext))
)
}
}
} ?: logW(content = "GetSmallIconOnSet -> StatusBarNotification got null")
}
/**
* Hook 通知栏小图标
* 区分系统版本 - 由于每个系统版本的方法不一样这里单独拿出来进行 Hook
* @param param Hook Param
* @param isNew 是否为新版方式
*/
private fun XC_LoadPackage.LoadPackageParam.hookNotifyIconOnSet(param: XC_MethodHook.MethodHookParam, isNew: Boolean) =
runWithoutError(error = "AutoSetAppIconOnSet") {
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
(param.args?.get(if (isNew) 2 else 1) as? StatusBarNotification?)?.let { notifyInstance ->
/** 是否 Hook 彩色通知图标 */
val isHookColorIcon = HookMedium.getBoolean(HookMedium.ENABLE_COLOR_ICON_HOOK, default = true)
/** 获取 [Context] */
val context = if (isNew) param.args[0] as Context else globalContext
/** 新版风格反色 */
val newStyle = if (context.isSystemInDarkMode) 0xFF2D2D2D.toInt() else Color.WHITE
/** 旧版风格反色 */
val oldStyle = if (context.isNotSystemInDarkMode) 0xFF515151.toInt() else Color.WHITE
/** 获取图标框 */
val iconImageView = param.args[if (isNew) 1 else 0] as ImageView
/** 获取通知小图标 */
val iconDrawable = notifyInstance.notification.smallIcon.loadDrawable(context)
/** 判断图标风格 */
val isGrayscaleIcon = isGrayscaleIcon(context, iconDrawable)
/** 自定义默认小图标 */
var customIcon: Bitmap? = null
if (isHookColorIcon)
run {
IconPackParams.iconDatas.forEach {
if ((notifyInstance.opPkgName == it.packageName ||
findAppName(notifyInstance) == it.appName) &&
HookMedium.isAppNotifyHookOf(it)
) {
if (!isGrayscaleIcon || HookMedium.isAppNotifyHookAllOf(it))
customIcon = it.iconBitmap
return@run
}
}
}
/** 如果开启了修复 APP 的彩色图标 */
if (customIcon != null && HookMedium.getBoolean(HookMedium.ENABLE_NOTIFY_ICON_HOOK, default = true))
iconImageView.apply {
/** 设置自定义小图标 */
setImageBitmap(customIcon)
/** 上色 */
setColorFilter(if (isUpperOfAndroidS) newStyle else oldStyle)
/** 输出调试日志 */
logD(
content = "AutoSetAppIconOnSet -> " +
"hook Custom AppIcon [pkgName] ${notifyInstance.opPkgName} " +
"[appName] ${findAppName(notifyInstance)}"
)
}
else {
/** 重新设置图标 - 防止系统更改它 */
iconImageView.setImageDrawable(iconDrawable)
/** 判断是否开启 Hook 彩色图标 */
if (isHookColorIcon) {
/** 判断如果是灰度图标就给他设置一个白色颜色遮罩 */
if (isGrayscaleIcon)
logD(
content = "AutoSetAppIconOnSet -> " +
"hook Grayscale AppIcon [pkgName] ${notifyInstance.opPkgName} " +
"[appName] ${findAppName(notifyInstance)}"
) { iconImageView.setColorFilter(if (isUpperOfAndroidS) newStyle else oldStyle) }
else
iconImageView.apply {
clipToOutline = true
/** 设置一个圆角轮廓裁切 */
outlineProvider = object : ViewOutlineProvider() {
override fun getOutline(view: View, out: Outline) {
out.setRoundRect(
0,
0,
view.width,
view.height,
5.dp(context)
)
}
}
/** 清除原生的背景边距设置 */
if (isUpperOfAndroidS) setPadding(0, 0, 0, 0)
/** 清除原生的主题色背景圆圈颜色 */
if (isUpperOfAndroidS) background = null
/** 输出调试日志 */
logD(
content = "AutoSetAppIconOnSet -> " +
"hook Color AppIcon [pkgName] ${notifyInstance.opPkgName} " +
"[appName] ${findAppName(notifyInstance)}"
)
}
/** 否则一律设置灰度图标 */
} else
logD(
content = "AutoSetAppIconOnSet -> " +
"hook NonColor AppIcon [pkgName] ${notifyInstance.opPkgName} " +
"[appName] ${findAppName(notifyInstance)}"
) { iconImageView.setColorFilter(if (isUpperOfAndroidS) newStyle else oldStyle) }
}
} ?: logW(content = "AutoSetAppIconOnSet -> StatusBarNotification got null")
}
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")
/** Hook 被手动关闭停止 Hook */
!HookMedium.getBoolean(HookMedium.ENABLE_MODULE, default = true) ->
logW(content = "Aborted Hook -> Hook Closed")
else -> {
/** 强制回写系统的状态栏图标样式为原生 */
runWithoutError(error = "SubstituteSmallIcon") {
XposedHelpers.findAndHookMethod(
NotificationUtilClass,
lpparam.classLoader,
"shouldSubstituteSmallIcon",
lpparam.findClass(ExpandedNotificationClass),
replaceToFalse
)
}
/** 修复通知图标为彩色 */
runWithoutError(error = "IgnoreStatusBarIconColor") {
XposedHelpers.findAndHookMethod(
NotificationUtilClass,
lpparam.classLoader,
"ignoreStatusBarIconColor",
lpparam.findClass(ExpandedNotificationClass),
object : XC_MethodReplacement() {
override fun replaceHookedMethod(param: MethodHookParam) =
if (HookMedium.getBoolean(HookMedium.ENABLE_COLOR_ICON_HOOK, default = true))
try {
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
(param.args?.get(0) as? StatusBarNotification?)?.let { notifyInstance ->
/** 获取通知小图标 */
val iconDrawable =
notifyInstance.notification.smallIcon.loadDrawable(lpparam.globalContext)
/** 判断是否不是灰度图标 */
val isNotGrayscaleIcon =
!lpparam.isGrayscaleIcon(lpparam.globalContext, iconDrawable)
/** 获取目标修复彩色图标的 APP */
var isTargetApp = false
run {
IconPackParams.iconDatas.forEach {
if ((notifyInstance.opPkgName == it.packageName ||
lpparam.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] ${lpparam.findAppName(notifyInstance)}"
)
false
}
else let {
logD(
content = "IgnoreStatusBarIconColor -> " +
"hook Grayscale[${!isNotGrayscaleIcon}] AppIcon " +
"[pkgName] ${notifyInstance.opPkgName} " +
"[appName] ${lpparam.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
}
}
)
}
/** 强制回写系统的状态栏图标样式为原生 */
runWithoutError(error = "GetSmallIcon") {
try {
/** 新版方法 */
lpparam.findClass(NotificationUtilClass)
.getDeclaredMethod(
"getSmallIcon",
lpparam.findClass(ExpandedNotificationClass),
Int::class.java
).apply { isAccessible = true }
} catch (_: Throwable) {
/** 旧版方法 */
lpparam.findClass(NotificationUtilClass)
.getDeclaredMethod("getSmallIcon", lpparam.findClass(ExpandedNotificationClass))
.apply { isAccessible = true }
}.also {
XposedBridge.hookMethod(it, object : XC_MethodHook() {
override fun afterHookedMethod(param: MethodHookParam) {
lpparam.hookSmallIconOnSet(param)
}
})
}
}
/** 修复下拉通知图标自动设置回 APP 图标的方法 */
runWithoutError(error = "AutoSetAppIcon") {
var isNewWay = true
try {
/** 新版方法 */
lpparam.findClass(NotificationHeaderViewWrapperInjectorClass)
.getDeclaredMethod(
"setAppIcon",
Context::class.java,
ImageView::class.java,
lpparam.findClass(ExpandedNotificationClass)
).apply { isAccessible = true }
} catch (_: Throwable) {
isNewWay = false
/** 旧版方法 */
lpparam.findClass(NotificationHeaderViewWrapperInjectorClass)
.getDeclaredMethod(
"setAppIcon",
ImageView::class.java,
lpparam.findClass(ExpandedNotificationClass)
).apply { isAccessible = true }
}.also {
XposedBridge.hookMethod(it, object : XC_MethodReplacement() {
override fun replaceHookedMethod(param: MethodHookParam): Any? {
lpparam.hookNotifyIconOnSet(param, isNew = isNewWay)
return null
}
})
}
}
/** 干掉下拉通知图标自动设置回 APP 图标的方法 - Android 12 */
if (isUpperOfAndroidS)
runWithoutError(error = "ResetIconBgAndPaddings") {
XposedHelpers.findAndHookMethod(
NotificationHeaderViewWrapperInjectorClass,
lpparam.classLoader,
"resetIconBgAndPaddings",
ImageView::class.java,
lpparam.findClass(ExpandedNotificationClass),
replaceToNull
)
}
logD("hook Completed!")
}
}
}
}
}

View File

@@ -1,137 +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()
}
}
}

View File

@@ -0,0 +1,903 @@
/*
* 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.
*/
@file:Suppress("StaticFieldLeak")
package com.fankes.miui.notify.hook.entity
import android.app.NotificationManager
import android.app.WallpaperManager
import android.content.Context
import android.content.Intent
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.os.SystemClock
import android.service.notification.StatusBarNotification
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.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.fankes.miui.notify.utils.tool.SystemUITool
import com.highcapable.yukihookapi.hook.bean.VariousClass
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
import com.highcapable.yukihookapi.hook.factory.*
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 类
*/
object SystemUIHooker : YukiBaseHooker() {
/** 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 StatusBarNotificationPresenterClass = VariousClass(
"$SYSTEMUI_PACKAGE_NAME.statusbar.phone.StatusBarNotificationPresenter",
"$SYSTEMUI_PACKAGE_NAME.statusbar.phone.StatusBar"
)
/** 根据多个版本存在不同的包名相同的类 */
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 notificationPresenter: Any? = null
/** 仅监听一次主题壁纸颜色变化 */
private var isWallpaperColorListenerSetUp = false
/**
* 是否启用通知图标优化功能
* @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?>() ?: appContext
}
/**
* 注册主题壁纸改变颜色监听
*
* - 仅限在 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 {
notificationPresenter?.current {
method {
name = "updateNotificationsOnDensityOrFontScaleChanged"
emptyParam()
}.call()
}
}
/**
* 自动适配状态栏、通知栏自定义小图标
* @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") {
/**
* 设置默认通知图标
* @param drawable 通知图标
*/
fun setDefaultNotifyIcon(drawable: Drawable?) {
iconImageView.apply {
/** 重新设置图标 */
setImageDrawable(drawable)
/** 设置裁切到边界 */
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
}
}
/** 获取通知对象 - 由于 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 iconCorner = prefs.get(DataConst.NOTIFY_ICON_CORNER)
/** 通知图标原始颜色 */
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)
/** 处理自定义通知图标优化 */
when {
prefs.get(DataConst.ENABLE_NOTIFY_ICON_FORCE_APP_ICON) && isEnableHookColorNotifyIcon(isHooking = false) ->
setDefaultNotifyIcon(context.findAppIcon(notifyInstance.nfPkgName))
customIcon != null -> iconImageView.apply {
/** 设置不要裁切到边界 */
clipToOutline = false
/** 设置自定义小图标 */
setImageBitmap(customIcon)
/** 上色 */
setColorFilter(if (isUseAndroid12Style || customIconColor == 0) supportColor else customIconColor)
/** Android 12 设置图标外圈颜色 */
if (isUseAndroid12Style && customIconColor != 0)
background = DrawableBuilder()
.rectangle()
.cornerRadius(iconCorner.dp(context))
.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()
.rectangle()
.cornerRadius(iconCorner.dp(context))
.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 setDefaultNotifyIcon(notifyInstance.compatPushingIcon(context, iconDrawable))
}
}
}
}
/**
* 判断状态栏小图标颜色以及反射的核心方法
*
* 区分系统版本 - 由于每个系统版本的方法不一样这里单独拿出来进行 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 register() {
/** 解锁后重新刷新状态栏图标防止系统重新设置它 */
onAppLifecycle { registerReceiver(Intent.ACTION_USER_PRESENT) { _, _ -> if (isUsingCachingMethod) refreshStatusBarIcons() } }
/** 刷新图标缓存 */
SystemUITool.Host.onRefreshSystemUI(param = this) { recachingPrefs(it) }
}
/** 缓存图标数据 */
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 仅刷新缓存不刷新图标和通知改变 - 默认:否
* @return [Boolean] 是否成功
*/
private fun recachingPrefs(isRefreshCacheOnly: Boolean = false): Boolean {
/** 必要的延迟防止 Sp 存储不刷新 */
SystemClock.sleep(100)
/** 获取可读写状态 */
return prefs.isXSharePrefsReadable.also {
isUsingCachingMethod = true
prefs.clearCache()
cachingIconDatas()
if (isRefreshCacheOnly) return@also
refreshStatusBarIcons()
refreshNotificationIcons()
}
}
override fun onHook() {
/** 注册 */
register()
/** 缓存图标数据 */
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 ?: args().first().cast())?.also { context ->
val expandedNf = args(if (isUseLegacy) 1 else 0).cast<StatusBarNotification?>()
/** Hook 状态栏小图标 */
compatStatusIcon(
context = context,
expandedNf,
result<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 (args().first().any() != null) instance<ImageView>().also { registerWallpaperColorChanged(it) }
}
}
}
/** 注入通知控制器实例 */
StatusBarNotificationPresenterClass.hook {
injectMember {
allConstructors()
afterHook { notificationPresenter = instance }
}
}
/** 注入状态栏通知图标容器实例 */
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 = args().first().int() > 0 }
}.ignoredNoSuchMemberFailure()
/** 新版方法 - 旧版不存在 */
injectMember {
method {
name = "miuiShowNotificationIcons"
param(BooleanType)
}
beforeHook { isShowNotificationIcons = args().first().boolean() }
}.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)
}
}
}
/** 修改 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
)
}
}
}
}.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)
}
}
}
}.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()) args().last().cast<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(args().first().cast()!!, newPkgName)
}
Intent.ACTION_PACKAGE_REMOVED ->
IconAdaptationTool.removeNewAppSupportNotify(
context = args().first().cast()!!,
packageName = it.data?.schemeSpecificPart ?: ""
)
}
}
}
}
}
/** 自动检查通知图标优化更新的注入监听 */
MiuiClockClass.hook {
injectMember {
method { name = "updateTime" }
afterHook {
instance<View>().context.also {
/** 注册定时监听 */
if (isEnableHookColorNotifyIcon() && prefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX_AUTO))
IconAdaptationTool.prepareAutoUpdateIconRule(
context = it,
timeSet = prefs.get(DataConst.NOTIFY_ICON_FIX_AUTO_TIME)
)
}
}
}
}.ignoredHookClassNotFoundFailure()
}
}

View File

@@ -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)

View File

@@ -1,527 +1,138 @@
/**
* 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/24.
*/
@file:Suppress("MemberVisibilityCanBePrivate")
package com.fankes.miui.notify.params
import android.content.Context
import android.graphics.Color
import com.fankes.miui.notify.bean.IconDataBean
import com.fankes.miui.notify.utils.bitmap
import com.fankes.miui.notify.data.DataConst
import com.fankes.miui.notify.utils.factory.*
import com.highcapable.yukihookapi.hook.factory.modulePrefs
import com.highcapable.yukihookapi.hook.param.PackageParam
import org.json.JSONArray
import org.json.JSONObject
/**
* 通知栏小图标适配类
* 国内 APP 不规范的图标将由这里完成其自定义黑白小图标绘制
*
* 国内 APP 不规范的图标将由这里完成其自定义单色小图标绘制
* @param context 实例 - 二选一
* @param param 实例 - 二选一
*/
object IconPackParams {
class IconPackParams(private val context: Context? = null, private val param: PackageParam? = null) {
/**
* 通知栏小图标数组
* 默认使用包名进行匹配 - 若失败则使用 APP 名称进行匹配
* @return [Array]
* 已存储的 JSON 数据
* @return [String]
*/
val iconDatas by lazy {
arrayOf(
internal val storageDataJson get() = (context?.modulePrefs ?: param?.prefs)?.direct()?.get(DataConst.NOTIFY_ICON_DATAS)
/**
* 获取图标数据
* @return [Array] 通知栏小图标数组
*/
val iconDatas
get() = ArrayList<IconDataBean>().apply {
storageDataJson?.also {
if (it.isNotBlank()) runCatching {
JSONArray(it).also { array ->
for (i in 0 until array.length()) runCatching {
add(convertToBean(array.get(i) as JSONObject)!!)
}.onFailure { context?.snake(msg = "部分规则加载失败") }
}
}.onFailure { context?.snake(msg = "规则加载发生错误") }
}
}
/**
* 转换为 [IconDataBean]
* @param jsonObject Json 实例
* @return [IconDataBean] or null
*/
private fun convertToBean(jsonObject: JSONObject) = safeOfNull {
jsonObject.let {
IconDataBean(
isEnabled = true,
isEnabledAll = false,
appName = "Android 系统",
packageName = "android",
iconBitmap = ("iVBORw0KGgoAAAANSUhEUgAAAD4AAAA+CAYAAABzwahEAAAAAXNSR0IArs4c6QAAAARzQklUCAgI\n" +
"CHwIZIgAAAMCSURBVGiB7ZlLixRXGIafMzqC6MyoUfCCEFwoBpzZGK9hQGzQlW4SENGN4FZI9Ed4\n" +
"+Q8iuBdNQEVHhZCoW10oLt0JipfRqIwyj4vuoduxu27d1V2R80Bvur/z1vueS5061RCJRCKRSCQS\n" +
"iUQiFSKkFaiTwEHgHXA+hPC0dFcFUH8EjgFLgCshhL+7ETuuztpkWq31ymyvUGsNb3PMqseLig2p\n" +
"r/2W91UK3wj9vo3PV+pQEcGVbcQqFT4h9Bw/FBV+UtXwGUI/TmqfeHNTdwFTwOIOJR+AAyGEqQ7t\n" +
"lwC/ABPAT8BmYCUwBow0yt4Cb4AXwKPG5yHwTwjhvw66NeDPFF+1EMLdpHyJZOjZr0ZeXaOeUm+p\n" +
"HxPapfFRnVJPqquL+umKjBc7oV5SP3URthMzDe0TGXxkCp26j7eEnwSuUt8nq0jisusKdVJ9V8KI\n" +
"dkv5N1rr035mwEFbmbFA6FwbvLoAqAHDeS9UIsPAb2o5ntTl6s2Bjm0yN9RlWfNkurlZfwK6A2wp\n" +
"2nF94gGwJ4TwKq0wdaqro8A1qh8a6g9K19WRtMLE4Ooi4C/g5x4Z6wfbgCumrPm0ET8HTPbMUv/Y\n" +
"A5xOKui4xtUDwOWkmooj8GsI4VK7H9uGUtdSPyyMZbzII+B6Q28/9cNILymq/xrYHEJ4lqlavZhj\n" +
"GzmjLmxpO6ye7eE21a3+hayhd/v166YkbqnfzBo1qLfzpCtRf1bdmSX4vRzGDiXoHM6XsVT9f+e3\n" +
"H5onthvYkdo7TZIeFF7m0Clbf5fzRn3+dvZHDjGo75md2J5Tq2z939t+q65XP+ecitPqhjZaG9S3\n" +
"ObXK1v+krpvTaB3xg8CCnL04AtxTj6ij6ph6FLgPLM2pVbb+QuoZgZZ9XJ0C9vbAbJW5EULYB43g\n" +
"6hjwnGqds8tgBlgVQpiem+rb+P5DAywCtkJzjY8PzkvfGYdm8IkBGuk3E9AMvnGARvrNJmgGL/bn\n" +
"2v+TFdAMnvX4+T2wDJrBRwdopN9kfhMbiUQikUgkEolEIpGy+QJozXWVnxEugwAAAABJRU5ErkJg\n" +
"gg==").bitmap,
contributorName = "fankes"
),
IconDataBean(
isEnabled = true,
isEnabledAll = true,
appName = "手机管家",
packageName = "com.miui.securitycenter",
iconBitmap = ("iVBORw0KGgoAAAANSUhEUgAAADIAAAA7CAYAAAA5MNl5AAAAAXNSR0IArs4c6QAAAARzQklUCAgI\n" +
"CHwIZIgAAAXzSURBVGiB1ZrLi1xFFMa/ut13bnfTw4gOBMMkQUJcCAqiZBEQsxFchBAiItGNOzHg\n" +
"H+Aqg+jKTVausoi4kCS6EBQF0SGQLCITgviAyJhkHDKLzNvu+zxV9bmY7s7tnkf6UTeJPyhmum51\n" +
"1fnqnLr3dNUFHEPyFMnLJJdIRiSlVSKSSyJymeQp1+M6geTpJElukkxImn7K2tpa0mg0bi4vL3/w\n" +
"SI1fXl4+HMfxtTiOoyRJDEnT/jtIkUxMlmURyVmShx+aAJKfkrxHUpM0YRh2GdW3AOlua4wxSZJo\n" +
"EblH8mwhxs/Ozj4dx/GPaZpGg874oCVHLCI/z83N7RtZAMnDxpjfRURImizLtsxk0UVERBK5SfLV\n" +
"YQScIvlPO3wehxJFkSZ5t9lsvtuPgNPt+O+d+fX19YHWQIFFi8gSya67nWoJeDVN00u+7z/led6O\n" +
"QrVolP3ywB4ukBUAbyqlLiuSx621lzzPe6ws7JeNjQ09MTHxphKRpXK5/KS1FtZalMv/Sz1riqQA\n" +
"8LTWhYqw1mK3sB2Wlt3W01p7AAoZBACiKAKwKUREnPffmvz71nueh3Z4OYTlcvlDAIYkfN932XcX\n" +
"iqQBsEWAIw/dVUrtN8Yknuf5URShVqu56HcLHrBVxCho0e3+COB94P6kFCUCaAlpD5YvwyJa4Hke\n" +
"jDELSqnv8tcch20Xzhd6EAQAwLW1tQenEg7prBFXtNbBLaXUoXYdyQSAX9QtGMiFlitqtZoF8E6+\n" +
"rn03LDy0XJKm6S2l1C/5OqstrLEg2SXKpTDXj3K7urr6dm+lV96cryI94nqN/KmUer63Mr9GenG1\n" +
"ZkbuRYtu/2sBvLVDs2WguDQIcBBaogVlv4wwDP+o1+t/btdGKTU1Nze37+DBg7h9+/aW677vj+/f\n" +
"v/8KgIlh7XAVWhbAs0qprVb2Ccl5EZkaNh9z4mud6RujiFhcXHwJwN5RkkoXQsz8wvwbo3RQr9e/\n" +
"iKJoJFtchNY1pdSRYb88Pz//3NTU1K8YMV0a1SP6+vXrI3lj7969XzqwY2SPdOVUg3Lnzp1nDhw4\n" +
"8BcetRBrraRp+p0xJq3X69u2aTabV8bHxz/b7lqWZLN+4L847Ph5FEmN1v7WoOSf1LvENldWVo5M\n" +
"Tk525V8k9xlj/i6VSqVhxu4dw8PmM2Ao+lyYamxs7IVt6i+QdCECAKwHQD+wmWNmZmYm0zR9yeH2\n" +
"k/YArLvqrV+OHj16KQgCl5n3ugfgt1F6eNBvfK01xsfHO58vXrw4obU+4vL3SBRFv3kAPsLmjkch\n" +
"GGPQaDQ6n0+cOPEVcsmqA0FsNpsfeUqpq6urqxvA5uy5JgiCjkemp6drpVLplbwHR921McZs7Nmz\n" +
"56oHAL7vnwdQyN6vtbbjkTNnzlwE4HS7sVQqnQdyz484jtcrlcr4zl8ZifcAfA6gYa3tEjKoN0QE\n" +
"pVIJnuchSZJGtVp9AsilBpVK5WMRKWytAPgSDrzh+z6s2dzJNMZ83K7veqInSTIbBIGTlKGHCwBO\n" +
"AAhG7SiOY1SrVQC4oZR6uV3fm5r4JJcBbJ84PT40AUwqpTrnFL0BKgBOZllmgftnG48D7fOVOI7t\n" +
"ysrKybwIYJv0WSn1U5Zl5wCwVqsVtqE2KCIC3/dpjDk3OTn5U+/1HbPeKIoulMvlN0qlUlebIrd0\n" +
"tkNrDRFBtVqliHw9Nja27ZbTruk7yW9Jvk6y0+5hC2l7IsuyH4IgOLZTu12tUkodU0rNpGnadTRX\n" +
"ZKjFcdxZm1EUtY/rZnYTAfTxE1Mp9RrJ77F5HujC1l0h2TnZqlQqBPC9Uuo1ZwPEcfxJkiSZ6aHA\n" +
"VzWyOI4/cSYgD8njxpioSCFhGBpjTBSG4fFCRLRZWFg4RPKeyxdskiTJT8y9hYWFoXdmBobkNzrT\n" +
"4kLExsaG4eYLnN88NAF5wjA8TrIxipCWFxokiw2lBzE9PV0jOdOa0UGFiIjMkCzuAH5QSB4muUjS\n" +
"RFHUj4hFPsy3SgeF5HSapv/u9O5jo9H4NwzD6UdtZ98kSXI2juMlkmmrLLGo12AB/AciDjB9K6Gy\n" +
"5wAAAABJRU5ErkJggg==").bitmap,
contributorName = "fankes"
),
IconDataBean(
isEnabled = true,
isEnabledAll = false,
appName = "音质音效",
packageName = "com.miui.misound",
iconBitmap = ("iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAAXNSR0IArs4c6QAAAARzQklUCAgI\n" +
"CHwIZIgAAAMeSURBVGiB7Zg9bE5RHMaf4yMddChNidZSNVBvozSxlKRpJ2IQSYMQMVikaVh8bK2B\n" +
"xCISQ0mMRCIGMRCDdECEBB0QTQhKoww0UaHTz/De8jrv/3613t5K7m+7//Occ57nnnvvufdKOTk5\n" +
"OTn/G0AV0AR0AFVZ+5kWQDPwjD/8AK4BtVl7SwywhGjas/aYCOBhTJBJYHnWPiMBjsWEmOJ61l5D\n" +
"AWqB94bpmyFhVs2Wt3kp9fskrfBqbyQdlXTF0G+ZjqmKAwwZZ/1Q0HbAWqmsPZcBFEIun0LQ3mi0\n" +
"fczadxnATsPoA0/zxNA0z4a/BSm0G4zaPe94SNJ6r1aQ9CJq4CBsh6Qfkkacc3dS+EoHMGic7a2e\n" +
"5qChOR0z7oDR53glg4x5k00YmhbD1GDEmCcN/RRtlQhhvZLcDtFOerrnIboCMBER5EIaj0n3kTVG\n" +
"LeyJ9Mk7Xhai2ytpUcScXXGmSkkaZLVRGwvR+kFqgfmGbmXMnE1AfayzgNlYEUlaatTigkhSSwKN\n" +
"pMoEsVZqzgSxljjppSVJDaUHwFJJiz3NCaPfunhrRZIGqTNqaVbEX9FGQ/PaqLVGmSolaRDr0phJ\n" +
"kGFDYz3BCoB1EsuIDULxS2+hV/7gnCvbEANigzjnxiVd8mrnJb00+nbEeUwE0G1sVlcj9KsM/ZcQ\n" +
"7XZgW3CyBJyK2CAtbgD7JcmVDFonaW3JPDWSOiX1Gh76nXPWzSmgWtI3o6neORf5Wg+0ShoM5k7K\n" +
"uKT2qQEGKP7OScIoMT8WgHdGv05P0wBsNPoeTrkqAH0CWlN3igG4bPTrKWk/U1I/Z/TvS+HnK9As\n" +
"YHeKTmfjQgRGeo2+F4O2NqNthzHGLuAu8DnCz+97REAN8DRBiB5/soggm43+j4zVmOJI0rHDcMHg\n" +
"HZK6JZV+lv6U9FbFr7tbzrlXKYJUSxrR37v3d+dcNTCm8jfiTc65+9PwX3ko/gf26TdqiU9QJmB/\n" +
"9lokuu8yg+JX5WiCILP2N3LaAHtiQlib7dwE6AKGvQDDFB8w/wwXL5k5QI2KL39Nkh5Leuycs15j\n" +
"cnJycnJyMuEXxX+pSnClwogAAAAASUVORK5CYII=").bitmap,
contributorName = "fankes"
),
IconDataBean(
isEnabled = true,
isEnabledAll = true,
appName = "智能服务",
packageName = "com.miui.systemAdSolution",
iconBitmap = ("iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAAXNSR0IArs4c6QAAAARzQklUCAgI\n" +
"CHwIZIgAAAOiSURBVGiB3ZrNa1RXGMZ/7xioVYhdG4tWF4FUSxXrBzVtXBn8G7LpJlAC2Qgu7EI3\n" +
"+ie4Ebrof+DGldD4hWnKTDItLRFBXGQQN6UJpaGgfbq493bunDlz55w7k5lMHrgM9z1fzzPvec95\n" +
"77nX6CMkfQScAyacC6DhXCtm9me/xrZeGqfEv8pdX0R28TPwOLv6KSwIkg5JuiFpQ/3DRtrnoUEI\n" +
"2CdpUdJ6HwW4WE/H2LdTIk5Lqu6gABdVSaf7LWJa0uYARWTYlDTdLxGzQxDgYrZXETeHrSCHW2VF\n" +
"LA6buQeLsSLmhs24AHM+zm0boqQZ4AHwYSlX7jy2gatmtpQ3tghRsnavAGcGSKwMasA5M3ufGSpO\n" +
"hQV2vwhIOC7kDf97RElq8BMwOWBSZfECOG9mm9DqkQVGRwQkXFu8gqRxxSWA9zr1Lmne16AbK0lH\n" +
"JF2UdF3hudyGpPF8J1ciREjSQgGhs2WEOH18GcHlCjSn1sWYgYDVgrJql/KuMLNnwLeB1ZvcJT2J\n" +
"+AfWJR3I9yTpc+f+XohHJM0oyaoPdChfDeDzBKCiZI5dClQPsGZmfzu2U859LbCvm2ndFUlTnvIl\n" +
"j83FJUnjFeBC4KAZ1jw2l0Q1ss9P8e9f9wPbX6jQPBwIRYsQSZMpkTxqQD2y3yOuwU1DCjARK6RB\n" +
"eyBP4XjEzN4RPr0y7I+sn0e0kLqZvXVsU8AJT93Y6dULooX44uMzAE+wxnqkF0y4SWM3+IRkK54b\n" +
"rDXg12hKJVEhmfch2MQv5HD623LiYWb/MDivNGKE1M3sZd4g6TjJWr+Ef/kcmJAxwoW0ecPMXgGX\n" +
"C9oMKuDjPFJigBrwe2Dd165B0rHAto0KsBxQ8T3++CiEmW0TNr3+6FBvJnCo5TEz25L0lOJ8q077\n" +
"jr4fT3rj2Y2rgPfkA3hEkob8Zma/eMrPFnDK8NTMtsbSm4cUC1kzs38d2zHgR8f2jadtR4+YWcdD\n" +
"N0mfAF8XcMrwEJrPI92mly8+fPPXZ6uRPF8HQ9JB4HvgZED1ZWgKeU5x0Pviw0f6qGsws7+IWL2U\n" +
"nKv9QFh8NEi4t5yi3ABueyq/AN506MgdLDRb9eFjkgz4g4g235nZHdiLx0Gp4e6wWJXA3UwE7NUj\n" +
"07TgGslB8W7FNnAtLwLaz36zDW1+UKxKYD7iEXiPvOjJibk1bOY5lHv1lhMz+i9Dc2JG//V0Tszo\n" +
"fzCQEzP6n3A4gnbdRzV75jOnnoS40BA/PPsPeu6w84nPwM8AAAAASUVORK5CYII=").bitmap,
contributorName = "fankes"
),
IconDataBean(
isEnabled = true,
isEnabledAll = false,
appName = "浏览器",
packageName = "com.android.browser",
iconBitmap = ("iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAAXNSR0IArs4c6QAAAARzQklUCAgI\n" +
"CHwIZIgAAAPVSURBVGiB1ZpPaB1VFMZ/5/EWxcSFLqQJkrYQxeKyi9JdoSI0Fgu6FIm4UWMCKkgV\n" +
"CknFRWqLCD4oWKrgqlCEJpSABUHclC5CRUVMN7po81wUhISuuvhczAtvOjl3/r07L8m3eXDOved8\n" +
"37szc+eeM0YkSHoSOAUcAcaBsdQvQBdYT/2uAjfMbDMWh9qQNClpTtKK6mOlF2NyJwQcltQZgHwI\n" +
"HUmHhyFgQtKipM0GRGxhs5djoikR05K6DQrIoitpOraIM0MUkMWZWCKuN0x0QdJ/BWOuF/FsFYgQ\n" +
"cDrKP5KPk8DVHP/pHpfqkLTa8Eps4Xgq55uS7uSMXa0q4vJwNOi+ko00nXtU0nzOnMtlRcwMRUKC\n" +
"d3N4nM+ZN1MkYkLDecSuSTpR4k/9OjC/q8w+087MnQH2FyUoiXMB+y3glpltFAUwszlJTwBvZ1z7\n" +
"Sbh+sm2SkteOmDv2QkXhQUi66sTfVOp1Jv34fR8YjZU8Mr50bKMknPuQdCjiSkRfkR7H7wN5DkF/\n" +
"RQpvvF2AbwP2E9AX8vJwuNSHmf0M/OC4Eu6SRhq4rO5LOhhbjKSpQL6RFjAVOd+vwAUz+ydyXMxs\n" +
"BbjnuKbawFHHcQ6YLxHYBuRWB3eBZzO2oy2SAkEWD4CzjVOqh7uObbxNv8qRxgMz60h6BJxvlldl\n" +
"/OXYxkIr8jeAmX0BfNQkqxr43bGNI2nDeQo8nR4ladZ7VAyJ+GOQ9IxDZSMkZJ8T4J2iZ25F3JH0\n" +
"QQ0h+0JC1hyHd98g6b3IYirvN5LGnDhrLZLyZRZPeUHM7BIwVyVxAcaBqiUfj9t6i6QWW2YwAGbW\n" +
"AT6smDwPVfcij1s3tCLHHVs/s9lXwMcVCcTCq45tvQXcdhwvFUUzs4vAp4OyqoHXHNvt0Evjo9AN\n" +
"n4WkswPe8KXPLZJOBmKMtMzsIXAtM6dNycKcmX1O+HweG95ldc3MHm6dR246A2Yl7Zqjr6QXgLcc\n" +
"103oH6x+cga8CMw2xKsOpoFtGzVZ7vIbN/ckHSjKIOmNAe+TLfwraVnSqUz8Sfn1to5HJlQO+qaE\n" +
"kOcjCUljPhV/yfE/Vg7KEloMBPWuzezc5QbEHJP0WcC3mEcmr2T6egkxf0QW8mPAvq1k6pHJK2IX\n" +
"Hn+VNG6WlbwQNoX8InaKTF5boVBMSlATKNdWSBHJa/TckHRsB4QEGz3B1puZHcnh+Qrwi5KGzHPF\n" +
"f0sc5HHK7SH2yj1LAXcbWAB+k3RFJfodA2ApSulJ5dvTf0r6TslJMtalFac9nRKz9z8YSInZ+59w\n" +
"ZATt7Y9qHEG75jOnaEVo7fCHZ/8DGEL3uplW+PsAAAAASUVORK5CYII=").bitmap,
contributorName = "fankes"
),
IconDataBean(
isEnabled = true,
isEnabledAll = false,
appName = "QQ",
packageName = "com.tencent.mobileqq",
iconBitmap = ("iVBORw0KGgoAAAANSUhEUgAAAEwAAABMCAYAAADHl1ErAAAAAXNSR0IArs4c6QAAAARzQklUCAgI\n" +
"CHwIZIgAAATZSURBVHic7ZxNjF5TGMd/T6uliBk1pSgtxQwlqo2gKghiU4ZaCOIjRGwIiY8QCRs7\n" +
"S4suRJBYkUgXMiIipBYTiZmuKtRHW0biK8xrNE2l9be4d5LpeN/33nue877n3tHf5p259zzPfc4/\n" +
"z7kf5wuOUglLeXFJw8BmYD0wApwBrACW5UUOANPAPuAb4HNg0sx29j/aREgakvSUpHGFMyHpBUln\n" +
"p65Pz5C0VNJLkmYcQs3nkKRtkoZS1y8qkkYl/RBRqPlMS3oodT2jIOnlHgo1nzdT19eFpHf6KNYs\n" +
"O1LXO4hEYs0ynrr+lZD0SkKxZtmeWodSSLoztVJzeC52/aK+uEoaBP6I6TMC55nZt7GcLYrlKOeN\n" +
"yP5i8HZMZ9EEk7QRGI3lLyIbJG2N5Sxak1T2ZLoylr/ITJnZWTEcRckwSeuor1gAqyTdHMNRrCb5\n" +
"TCQ/veT5GE7cTVLSUuBP4Fh/OD1npZn97HEQI8O20AyxAO71OoghWB2fjJ1w38diNMk9wBqvnz5x\n" +
"EDjFzPaHOnBlmLIu5qaIBdmtY7PHgbdJXu60T8ElHmOvYCNO+xQkFWzYaZ+CCzzGXsHOddqnYK2k\n" +
"4HoHG+YXPTXUPiHLycY+g/Bk2EnAoMM+FYtxxO0V7ESHfUqODzX0CLbEYZua40INY/e4LniOClYR\n" +
"j2CtaFH0n99DDT2CneawTU3w969HsEcdtql5PNQwqHunYb2snQjqfQ3NsNtptlgAD4YYhWZYnYfU\n" +
"yhI09FY5wyStpfliQTb0dm1Vo5Am+USATV15sqpBpSaZ91C0aO43ZDtWmNlvZQtXzbC7WVhiATxc\n" +
"pXDVDNsBXFMpnPqz18zOKVu4tGDK5sTvCwqp/mwys1LTPKs0yXsCg2kC95UtWCXDdgPnB4VTf/4C\n" +
"Bszsn6KCpTIsn860UMWC7EF2U5mCZZvkXeGxNIb7yxQq1SQXeHOcpWVmhYMjhRmWPx0XulgAA2U+\n" +
"lco0ySZNZ/JyS1GBMoLdECGQpnB9UYGu97D82/EnHCPFDaTrt2VRhl3G/0ssgKu7nSwSbH3EQJrC\n" +
"pd1OFgl2YYfjh4GpoHDqwRTZ9M12dJ0/ViTYRR2OPwK8WmBbZ94j66pqR6ckAYoFW93m2F4ze61M\n" +
"VDVmwMzeBT5tc25VN8Miwdrd8Lfkvz+WCKyufJf/tlu0tbibYZFgy+b9/7SZ7cr//qREYHXlQ4D8\n" +
"9eGOaF515B4T/1kSLGl3j1fU9oIZZQPRc+sxd8n1TDdNijLsQP47aWa3tTn/eoF9HXnLzP6ee8DM\n" +
"HgPez//tOmZR9Ka/DVgH3Dj/Ivn5IeDXSuGmZ8TMvmp3QtIYcMjMbu3Z1VWPHQTKMuatb4y1RieQ\n" +
"jVV2fbrUhNVm9r3HgXsGYr7Q6QGvnz7wolcsiLvmezv17TubNLONMRzFFGwR8CX1651tAWvMbDqG\n" +
"s2iTgvMhqk3U66P8IHBFLLGgR1v6SZoANvTCdwW+Bi5u9zrk4ZiYziRdBVxHPWYnLgGelfSZmX2Q\n" +
"OpgjkLRV0sfpXq8KmVAddrCTNChpLLEYVRhXNoMymOB7mLIX1p3U76lYRAsYDt2/wvOUXEnzxAIY\n" +
"wLH02nPT30O2ccYoWVf2mYR/Hh0m23dsP9myltlXk9PJlhkuB052+v8F+AL4CGjWln9N5l/CCEZS\n" +
"HWRiiAAAAABJRU5ErkJggg==").bitmap,
contributorName = "fankes"
),
IconDataBean(
isEnabled = false,
isEnabledAll = false,
appName = "微信",
packageName = "com.tencent.mm",
iconBitmap = ("iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAYAAABV7bNHAAAAAXNSR0IArs4c6QAAAARzQklUCAgI\n" +
"CHwIZIgAAAZvSURBVHic7ZtbrF1VFYa/UbDWSktRELl4ioa2iAUURKXyACgXxQsoqKmaqAkqicqL\n" +
"JvpgohIjRnwQbdQHYkLRaOKtjQ1VMdVGShu1GppKQ5FWbKlwqOcUaUNty+fDXFs2i7171tyXtbbJ\n" +
"/pKTczL3nGOM9e+51ppzzHFgzJgxY8aM+X8lBmVInQ28DDgPWAKcBhwPPL/ochCYBvYA24AtwMMR\n" +
"cXBQMQyDvgVSrwbeCFwNnAnMrTj0APA34C5gfUSs6TeWkUGdUL+ibnVw/FW9WX1p09fXM+rL1dvU\n" +
"JwcoTJnJQqgXNX29Wag3qVNDFKbMTvWdTV/3jKgL1XU1ClPmO01r0BX1PHV7g+K0WKO+uAkNur7F\n" +
"1EuAtTzzmm6arcBlEfFYnU47CqSeBWwkrWNGiS3Asoh4si6Hs8oN6jxgNaMnDsA5wMo6HT5HIOB2\n" +
"YFGdQWRyjfrlupw96xZTLwN+U5fzPlkaEVuH7aQ8g74xbIcD5Ft1OPmfQOq7gKV1OB0Ql6iXD9tJ\n" +
"+wz6aObYA8AK4BPAj/qMYyPwGeBm4B8Z4z7ep99qqIvVpzMWblPqa0o2buhxEXhHyc4CdXPFsYfU\n" +
"hXUI9KnMi/p2Fzv3ZNqZUk/qYOd9GTY+MkxtWrfYlZnjtndpfyjTzlRETHZoz7nN3pTpM4uWQEsy\n" +
"x11VblBfAFyaaedU9eIO7TkP39dn+sxH3Z95a6h+ySJnY8oT/bwHG6r3qxcWdo5RP6gezBx/3LC0\n" +
"iSIwexy/m5Q2fS3VU63d2ADMI20nOrEP+HPRbzvwCLAXeBzYFRFH+vTfkX4FGjYHSDnr1cDaunfy\n" +
"AMfW7bAie4FvAndExI72D9TTSYcDS4FTSJvqY4FDwBRpVm8DdkTEw/0GMooCrQBuiYhdrQb1IuDt\n" +
"wDLgImB2BTsH1E3A74E1EbGp54jUp3p8wA6SHaYjpPa4rlV/qR7p0/Zhdb1pO9WTQA/1GUC/rFIX\n" +
"tMVzscPLg28ydw+n3jWkYKpwZymWz5u+8WHzNbXawan6yRoC6sTKthhmqz+s2f9vTRnUGQWasP7n\n" +
"0Po2//PVe2v23+JP6mndtJkFULwOV1WaboNhD3A9gGma/xR4Q43+2zkf+Jl6TKcP2/NBX60nHgA+\n" +
"HBGPFn/fzpA3nBW4EPjBjL3UlTVM6TVt/q6rwV8Oy8ualJP2JwAPAsMsHHhlRGxT5xe+npMPamMa\n" +
"mKS3U5Yp0or8zIwxjwOLImK61fCspH1ETAE39BBMVVZFxLbi7xs5uji/Ai6IiMWk59XeDD9rgfMj\n" +
"YhHwIWB/xXEnAjfN2Ev97JCm8HsK+3PVXUfp92gxw9pj+lxFH5Pq8aWxt2bE+E91Tmtsp4NDIuIW\n" +
"4OsVVa/KJOmbBbiGVKLXjd0R8USp7b6KfvZExL5S218qjgU4mVQtB3QRCCAiPg3cmmF4Jja3XfRM\n" +
"Kd6z1fJr/70V/SxRl5Xa3l1xbIs3m7HKzk3od+MLhb1Q76vQf9q0wr9CvTPT17Sp4Ott6k8yx2oq\n" +
"LZyoLKd6qfpAD47a+UBh6xR1X5+2hs1+U/lP91usnYhYB1wB9JPR21P8PgmYf7SOI8AcUklzNYEA\n" +
"ImIn8Mc+nLZetXOO2ms0mEXxJVYWyLRX6ecUs5X3PtyHjToR8lKurwZe1aH9MGlRt410KnEqMAEs\n" +
"AE4AWkcyrYTYPlLV/aiU9nXiCGlVnSXQBR3a1gBfjIg/lD9QX0i6jydIB5Ot09jdxc8rMnzXzRPA\n" +
"37NGqCvanvK71Pf36t1UtTrK3GNRVVvpGWRaNLUWW7cB50TE93sVCLi7j7F1cHdEVN/7qWebMm/v\n" +
"GIR39Qzzjpfr5nW5F3SiXTJufYj0vYZF6MaG9jgH9v9iPQi0GLifjKVGTbwlIlqb6uaCi4gHSM+z\n" +
"UWJ1uzjQ4AwCUJ9HWp2f22QcBY+QSoun2hsbnd4RcQhYTvWM37B4Gri+LA6MwP1fFIO/tcEQBK6N\n" +
"iA0z9mwS9XL1sZrfWPvV3LLB5lDPVR+sUaDrmr7mbNR56ndrEOfHVeJp/BlUJiL+HREfIxVM3TtE\n" +
"VxurdBo5gVpExC8iYhmp5HgVRfohk53AOuDXpEPKdirlthpdB+VgqsC4klQFexZwBinfNJf0JnoK\n" +
"+BcpL7UZ+B2wMSL+U4yfRTpuWs4zG++Fg6hjHEnU49SXqKcXPydbsV5avUrdot447DjHjBkzZsyY\n" +
"5vgviFEUXbpK+wsAAAAASUVORK5CYII=").bitmap,
contributorName = "fankes"
),
IconDataBean(
isEnabled = true,
isEnabledAll = false,
appName = "酷安",
packageName = "com.coolapk.market",
iconBitmap = ("iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAYAAABV7bNHAAAAAXNSR0IArs4c6QAAAARzQklUCAgI\n" +
"CHwIZIgAAATESURBVHic7ZpviFVFGMafWcvC/YMa2x/TLFs2My1pIZGiLAUtKohVRIoiKiOEIiIU\n" +
"qQ8VgVSyQrEmlF8K+mJYWWIQtaSWmxtYURttBJa1FGurpLabbb8+3LPs9e6dOXPmnGsE8/u0e2fm\n" +
"eZ/3veeeOTNzpEgkEolEIpFIJBKJRCKRSCQS8cXkGQzMltQmaZGkuZIuktQgaUjSz5L6JX0pab+k\n" +
"XmNMby631T2slrReUpOkjcaYZ4uOkRngDuATsvMdsAZoLsjHyioxHilCO9TQYuCLgMJUchxYD0zJ\n" +
"4aXJov0XUFdk3r6GNhZQmEqOAPcG+nnDobul6PxdRhqArhoUp5wuoC2Dp6s8NGfWsi6jRiYCX9W0\n" +
"NKdyn6evAx5aO4uogXMWA/ZJWuChc1TSXkm/SjqR6NZLOlfSPEnTM3jqNMascXi6U9LrnlpzajFz\n" +
"jhrZ4PEt7QIeBCY7dOqAW4CXgV88r6Qu4IIqWhOAAU8NgI9rVZyWlMC/E3BzBSYBTwMnPJLrB66s\n" +
"GP9UhuKMsqy4yowZ2e8I+DUwLaf+dGCrR3IjwO3JGNu0DtAD9FraDhZTlTHzNzmM/Ijj5xQQ6x7g\n" +
"H49CtQHPOdrrgZsd7XcX5VnADkegOYUFGos3F+hzxNwE3OZo7yjTOmrpc7gos1McRnxnjpC4jZYv\n" +
"5tGk/UOLp2HgjDKdakuPUdYVYXSpRfxv4MLcAdLjb07i/QAsTj572JH0yioatnsRQENeg7blRHcu\n" +
"4WweFgGNyd/NjmR3W8Zf5xjzUl5zeyzCT+YSDvfzniPZWY5xtjyc43wM/WQRvSFYNNzLMkeSL1b0\n" +
"nVrxf6tj7I48po5ZRFuCRcN81AODFi/9nHpjfh74A9gJzCj7/G1HkeaHGjtuEQy/LMN8vONIbknS\n" +
"p5Xxe1NDQHvSPs2hsTfUmG2tdE2B+ad5uMuR2PakzwOUnrJtdCT9nnH0WRhizrbEsK6uiwS41JEQ\n" +
"wJmUFqx/pvQD2AbMAr6xtPf5eKrcmjxg6bc0X+revO9oW2uMOWmMGVFp+6TqNF9Gu6QuSSOW9hZg\n" +
"eSZ3wHJLtQczCQWAe4nzqWWMz5aMi9+ymnTd2B4vpBLV476Wksj5jrErsM94PqzNanafRWgIaMpd\n" +
"jfHxOlMSaPfQmAl0BxZoBDg7i+FVDrG0330mgFdTzHdm1NsSWKQNWYJMBA45xN7KXInxMS4h/aRk\n" +
"T6D2avz2mMrJ9usAlqQIdgPzAhN4LDHk4jNgQoh+EmM28HnGImW6WtMWiqN0AK0eWmdR2raw3d/K\n" +
"6QUmhRanLGYdftu65VxcqWM99klMHpLkczy8U9K3kr6X1CcJSedJulxSi6TrJfnsY/dIutEYc8yj\n" +
"rxeUztpe8ey+zRizIov4ZZR27U4HH1C2CC0S4FrgoKePccdNaeJXA4drVZWETbUoTEUejcCbHl62\n" +
"hog3A7trUJhBkmOd0wXwUIqnk3nE11F6vaQINgPnFJh7ljwWUNpXqkpe8RnAC/idjlYyTOlh7oqC\n" +
"cs2TRxOwvYrHj8r7Bb+CR+ktsYWSbpU0X1KzpMmSRp9fhiUdkTSg0mt470rqMcb0h8asBcD9kp6Q\n" +
"NFVSt6RVxpiB/9ZVJBKJRCKRSCQSiUQikUgkEvl/8i8jWVdXsYky1AAAAABJRU5ErkJggg==").bitmap,
contributorName = "fankes"
),
IconDataBean(
isEnabled = true,
isEnabledAll = false,
appName = "支付宝",
packageName = "com.eg.android.AlipayGphone",
iconBitmap = ("iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAYAAABV7bNHAAAAAXNSR0IArs4c6QAAAARzQklUCAgI\n" +
"CHwIZIgAAAK8SURBVHic7ZpBitVAEIb/9hpxIcgIeg15C0HceAxlQLzHu4mLDAMD48JbKGQQXOg5\n" +
"fhdJIC8vnepOV3fnPepbTvKqqv+urq7uDGAYhmEYhmEYhnFdkDyQ7LhC7RirIomzB4FcTechAjjn\n" +
"qsb4rKbzS8AEEjCBBEwggaQCuIddJoSUQm8ZJGACCVgfJGAZJGACCZhAAiaQgAkkoLJDkGwA/NWw\n" +
"pcSTc+6VhqFrzaB7LUPXKtBD7QCqQbIpeQt5iRn0Rnh+VySKvUKyFRLoUDvGagQsr07b56UtsY/C\n" +
"c7XdayT1wqxBXxNeA3gx/Pnl5JXfAP4A+AXgp3PuX6K/DsDNyivPU30kM6T5kQHftDy0w++jagX7\n" +
"j4yrdnONOTTAhnKB3EIXIhjlCalXnEneZhDGRzv4ayb+pexRL865xNm67HyMYlXLntUiPTh+XHj0\n" +
"hH7HeICn+PK0gL8F8CE52mXUDqbRLMxclzJb7JdKSoEvmj3SYOZLS3WXmIiVSsdZzSoCT2c52xbK\n" +
"fncMqTMhtCyRUTxv6YvMjqJQecXi6bZ6zOLE77tRFIkM7LNig5zWn6JFkHl7Lh2xaglEuSEsLtZu\n" +
"TvP091xT7tD3YBrcAPgC4DE6s0pnUGDmdLP3c5wLR86OO2sBZz0lM1CcpWCZXyj//fbsvSzbPBPE\n" +
"mdkZr2DUWXM6dah+Wg4ckCjOzGbqXVWUQPNmsY0JdsWu+N/1W8RZ8KPSdEpO5rPckbzdGHBMvVCZ\n" +
"jA1+4wQaHCzNQugt4IHxM5mlc98qlHhpz34mf2D9snypN1l732fjk3Pue+TvohjG8xXAe8TH6Dca\n" +
"mQWxFD3vTcYlZnesQe2t9MjS9zjL4/Iuvy3GUnuOzYU+N0tjS/1weADwDv16Bs7X9Fib7tF/QPxW\n" +
"/cNeIMMkfs5huNnDsjEMwzAMwzAMoyb/AfL3c7cVoO+XAAAAAElFTkSuQmCC").bitmap,
contributorName = "fankes"
),
IconDataBean(
isEnabled = true,
isEnabledAll = false,
appName = "淘宝",
packageName = "com.taobao.taobao",
iconBitmap = ("iVBORw0KGgoAAAANSUhEUgAAAE8AAAA8CAYAAAAngufpAAAAAXNSR0IArs4c6QAAAARzQklUCAgI\n" +
"CHwIZIgAAAzFSURBVHicxVxfjF5FFf/Nbj92W8oqbCihGlbKH7MmlodiVVwNNCISk5o0MX3goaiN\n" +
"qaKxPOADCUpEYgIxfSAhmmKKphj+VKUQMfDQvhCIFrUQKxSlBc02YSsWdxu76+7Hz4dzzt7zzTcz\n" +
"997tH09yM9+dOzPnz5yZOXPmzBdwDoDkHgBXAngBwFEAhwG8CWAyhPDOuaDhbECoK0ByUH8OaPpe\n" +
"CKHbpF4IoUtyBMDfAFycKPYugGP6/QiA+0MIx6xuDT0Gi3Ql8uJ8NKH9tIHkYIJQ/71TV1/TCQos\n" +
"kJzVdIH9MKOCTtHRqcPXBqzN021nWa5x6yGSGwB8HsBqAKcA/A7A4yGE6ZKGQHq/C+AzLm8oUW5O\n" +
"83+kbXYg2jIQQpjX9hdxkFwNYA2AKwBcBuBSABcBGHH8TAOYgWj2cQCTAN4AcCSEcMy3afjOiEY6\n" +
"jRkhuTehISQ5SfImX77QzvNO83IwS3Is1QbJtSS3kdxN8qBq6FJhRtvYSXITnaZTtDs70toIsEPy\n" +
"gGPaD7dZR4wJsBPVN8GNNxAaST4QCWwDyQdIHirUXWj5pGBKBbnW875koWl6b8RcjulJksOFdu50\n" +
"jKaYJ8lJLTumeA9n8JWE0Aa8MnjYRXKV7/ylCHCYIhQmEMQMkeTmHEJWmlNq506SDyYYzAnrTGic\n" +
"b8sryAmSG1sLkNVQW1uD0MCQ7oi0zdKbHIE5mGHvHBZrhDGX0pQ20ESQXoh3NBFgarXtG4Y1sFLT\n" +
"96L0Gy3q2opr9HQBDLoHrtw0ZAWdQrWqngIwq2WX63MJgDHIiuzb6EbvBkOoVvX7SCKEcD8LFkVK\n" +
"eG87ZprAUU0HFGGX5DoAGzW/Tv27SkfM1ByA1wD8CcBLAF4F8A8Ab4cQppsQRhkFHwJwHYBNAL6g\n" +
"OEwYMW32rQsR4BshhF+VBOiR2dDdn1Dl1FAgdaWiM6pJPhqVaTqUDrMyI/pMlxS9rIzoRWM6N9xI\n" +
"XkUxeWIecrzNUOzK+jnQMb/eNRQL0E+yDzombK5bVxBYiuBJilkywYSZEAmn9SroBDzo8jY5HnIC\n" +
"tO97GglPC5kQttQIYW9G8Ka1MVHx+37qyhYxOqzP6Rus/bz5Tl7fQICWP+FlU4tE03WUXcYJVhp3\n" +
"kOS2qHws8HjF9O97HDFjlNV99AzLqY6/YU03NhTeXi+XJgg67vcoZbeQ3EJpukqF7JH6If8MyfWu\n" +
"np8aJik7mt0k79JOWHWaMkrx5IeudfiuBK0pGI/bqEWWKhznUYaZH66+Jw9Rt3GecJYN6CnK3rpn\n" +
"voueTvT0zW1NBEnR/pLg7NvdrYRXJ0hHQG6BuSuqb8Ml7m2/ZTrBBittC5o7lM4doYyOHmeApiXr\n" +
"wPIOxO3XOkMNSQhhPkeg2nYTAH4LMXxfAvDVEMIrVgbqYiK5HcAO9Nt19v4UgJ9BXE0A0HHPee73\n" +
"cohBv0zfL9A8+z4EYIV+N2N8NYDvhhDuiWjaDODRBE0eugDGQwh/NZ7rhDbsfmeHBHvNlHsT+ZZu\n" +
"KgyPcwVbjSY2H7qmfVtMFiWheWP3EHV19ILICTDRhgluIkFMidg2z2yD7yacvomfohjmzUnR1uM6\n" +
"ywrPMbs5amAPyatKQmS/Meo1MrapmgijCbTxpOxOCU7TZyL6YhwkuT8ptKihUVZmh2dkgbrq5ASY\n" +
"EFzKGK0zC84kzFJMoR1M+x6N550F2ozuI76N5BkGgJ8AeD96HQT2+3skvwTgyyGE3xtyP4FSJtR5\n" +
"kpsA/FKzuy4dgpyavQ6Z3G0xmgewAPGWXATgxgx9NrH/BcB9mjcL8a7MaTsnNe/fEGfCbKYtg79r\n" +
"mpKJaepqiLfmLfqh63pgW6EH4vw74vpRW5sy9XazZldBMcpz0GP5NwHm52qjdWvUdg7Wx/wuNsTK\n" +
"2LWGSnMAqfNIQoA2bDe6sj0GsyO8x/jVPG875vA/o2WHmTGY+5jMCJVVR9dt1czT3OlRUR16N2iB\n" +
"2wFcr59i/5elcwBuIXlBCOGLfujqsO2EEJ4ieSuAy0II93ihWfloyNvPNkeBXcVXOskbiLLj48Z3\n" +
"G+K60OoXS1FOseo0MXbHJ3ch9lu1JLXdssd2IY0173SAlfZPFPB5nNutXu7Q2w6C9wHYRxlqPwBw\n" +
"rRbxlri5r7eTfDqEsI9uRxJpY88Bdgbs+4kWArAtl99xnKe/V0B2Hucrrcsh2vOC7oDscP5UQ3Qr\n" +
"NB1ICs8Yd0J8FsCzFFfUDyErsRfggv7+NoB9cCpN2af6VXOZlvXbrkFUZydG3JoCA4b30yQPQ7Zf\n" +
"1tYyl5bmu9sBvKJl5lGt+DkwHs/3jGTBCXEwhNANIfyY5BMA9kDmQxOgtfNR0zqnfdcD2FlD2FJh\n" +
"JYCrG5Tz2r4A0cBXEt9aQVF4Bi5upaMhYTeQPATgIxFyGxa+F/0JWSN8Dpq4f9owb4I7DnFeAHUT\n" +
"fz8smjzxClQE1SgbXk86ggxOon/ueF/0vpB5lgqDLR4z+L/lgooMmh65LipGW00Aqp42n5tv462E\n" +
"yfBBTY3wM3k20YUIft6l86h2Gafc+38gQZUPhxD+wGoXZPScV4PL+JyNMxqBQzgKOQMFRBhzmh50\n" +
"xW04/BHAYwD+pe9zmhqjs/rYexey0l4BYNG9FYHNtc8BuBUyVZzS/HkA/y1tx2wO11dbbW0hKPn0\n" +
"gEp47YY7K2t8R2TjmQ2UjJpaClDOWOtsrkdbtJfccTg7b3PUdg7nNqvXWPPcKroOwHbNNhtvELLR\n" +
"fxGoVmmrh/6eLE3yg6o1FxbK9NEG1YQaD+9AziOOynNdB2Z/pu28FDikP9U0Vu/9qWhRrVd04Ud5\n" +
"bYaDLTTFyE5nNqXK2LC1mGmz53Jw3HA2Ep7TursBXIN0LMvjUR0729gMYBxiV01BYmHeDiFMn83g\n" +
"arozCrcwfB/A0RDCQ4mOqzt0MoH+sy0Rub3fYoAiE8HYWi+O7jTn5EGK93ZVhCd1IpfDu8vXsd/R\n" +
"+zDJ2yiOTJK8L66j76Xw32TsSlHznPYMA/i5Zqe2ZXv9kHXpaogDEai0dUjzVkN6exZIzlVmOpRW\n" +
"Pxu2A1RvjDPoRwF8BcDXAVzu6iy3OqiCuoejMjk4DrUaQgjdumFrCB7SxuPhavV/kam3BtU+2Nez\n" +
"dl5MzJOLTDWFaIEaB/A1ALegmsfMHhyCW4gc3sshHmKgPN8d8yZQVnis5rmtSkgsANOIl0MIzysT\n" +
"xrRN+h8oEAJIiD+QFljJaDWNP6m0jgL4LIAtAG525WxL6AViYRx+YRpHFZtXEt6riq8TQpgv3cOY\n" +
"p8Te5Tb1xsAjvsGoTN3yf7LwrWQrGt1rdA67Fb03jKwjUgGaKwBYEGZHy36ihk7j1W8C+jUvmuds\n" +
"/5rqkSFIzz6i7ykTY0Uiz+P9sNVl5e01F1EJjBYfohZrbk6DVrrfRvN1NfisEyzk4j2g7Bh4DNU8\n" +
"lzNyn6y5K5YTgrV3M8kt6u7qqllhc0qTsN6u0me4TUMGIW71uUSdEdU4uEXtmoiuGAcgm4DXrB4Q\n" +
"aZ6b5+6C9GpdbPIuTXOT/FShrsHDJL8J4M+Q/ekIZK40P11pDhqMfpvQ7gfwa8gty5j+dyJ/440Q\n" +
"bayb71KLmwD7T7vq9niHclhY2Wrrojql9tpAKqpgknKnY1Rx+/skPtziNvuu6XM1dJTjVFgxO87m\n" +
"sbp2V6Hu9uOBqF6OwFTMSa6chwOUYMg4KMnHABqYUW2KUjob9nCCVackD7tHWFnhddpQGyXuCNzg\n" +
"6rUNs8gJ8gQlxm8ixsne3cVBLf88VXMi2iwyvk5RdpZ4BZtdH7Bvuz0RBa3LBYfnIptKt31mKUNs\n" +
"K6OQ2xxTlHjnq6I8G67WqU2mjXxILctBLjHTpNzBzfdEgjHK/PdctuU0riOUMLetjKJF2fKKp5Y3\n" +
"wa1i/f26WOv6FCVQjMw7kLbGPdhq9FII4WNNiTbE7iRuHMCnIObBpahswWnIvtH+g+BVAG9GW69F\n" +
"2uLAIoduAJX9tmg3uj3vGMQDfTXyK6zlvwvgyhDCO8yssltYTerWEyXPgnlSW3mL2SLYOlVvKXWj\n" +
"dkZIbmd1UbC0usZxKUncwTUex6cA/T1zHNITje5+ZZiwnUTO6Vn7RxCsdkFjkDPktyDaehRiW9q2\n" +
"byXEOXEtgM+h11FQMogHAXyn7uJeyq+1gVWUZDz+k/Eo5xqYXsmbQGlUtb4y2kMQe5f59axC7A0W\n" +
"L+mdBZk0BlaL0Hala4a9K3XuSQnSC22KEpC5NB4TQhynxCM3v8B2lsEJ74EGWtYkZnmGciLYbwgX\n" +
"IHsPg+4MQN+zdzH+X0Bx/a8F8EkAH4f45S5Dr+ckB8cAvAzgNwCeCCFMaZv1dywUGv+jz9k8rDlT\n" +
"oLReAjGBxiAH5xdDXO8LEFPodVRm0HRUtxWf/wMVHEsUTW3uUgAAAABJRU5ErkJggg==").bitmap,
contributorName = "fankes"
),
IconDataBean(
isEnabled = true,
isEnabledAll = false,
appName = "小米穿戴",
packageName = "com.xiaomi.wearable",
iconBitmap = ("iVBORw0KGgoAAAANSUhEUgAAAC4AAAAuCAYAAABXuSs3AAAAAXNSR0IArs4c6QAAAARzQklUCAgI\n" +
"CHwIZIgAAAI4SURBVGiB7Zq9ahtBFEa/WVKmNshBpZ/AgUDAMcTunSpu3Cov4E5voFcQ+AECLpw+\n" +
"NiKG4EBcGgKp4zIuJFBlnRQ7Eip2du7+WOuBHFgQo733nh1mZ3ZHkjyAAwbADTDl+TAldxoATusA\n" +
"PeCyUz0bl0BPkhz5VXyV9F5pcCXp0AEDSeOubSryyQE3kt50bVKRHw6YSnrZtUlFZg6ga4s6ZF0L\n" +
"1OVFS3kWkr5LupB0K+neH5K07Y9dSR8kvVUbHdZwXp0DI2CrQr0tHzNvUriJ+DnQb9BhfZ9jY+IL\n" +
"YFhXuOAChj7nk4ovgOO2pNfkj6vKVxVvracL5IdPJX5uKH4AjIFf5E91U/95DBwY4s1j3io+p+RG\n" +
"BHaAiSHPBNgpydPHONtYxUclxfaAv8Y8+HP3SvKN2hJ/JDBPk/d0Fel1+cKeJ5/nH9sQvy7pHcvw\n" +
"CDEpyXsdC7YsvReB5IeS9g3xIfYJ37BfYsEW8dtA+0dDbIzQmvAzFmgRvw+0vzPExgjlCNVc0UT8\n" +
"lSE2RihHK+IufkrrRGtaxHuB9j/VXCrlCNVcYRHfDrR/M8TGCOUI1VxhEd8NtH82xMYI5XgdjUx1\n" +
"AUp2ybcMlUzSadEXzrnfko4kPRjyLHmQdORjiziVZQgbeyjZx1pI9EViSZKvbpDwy/JSPrntiXWS\n" +
"2xBap7MtuLa2mTe+6fl/f3zTZJJmXUvUYJZJuuvaogZ3maSzri1qcJbsD7SZcw5JJ77huXMl6cQ7\n" +
"55DYnxD+AevUWpo12Yg8AAAAAElFTkSuQmCC").bitmap,
contributorName = "fankes"
),
IconDataBean(
isEnabled = true,
isEnabledAll = false,
appName = "微博",
packageName = "com.sina.weibo",
iconBitmap = ("iVBORw0KGgoAAAANSUhEUgAAADgAAAAyCAYAAAAJHRh4AAAAAXNSR0IArs4c6QAAAARzQklUCAgI\n" +
"CHwIZIgAAARUSURBVGiB7VrtcRMxEH3K8IdfBBrgmIGfzFwHmApwB7gD3EHcAe4gTgUJFdipIE4F\n" +
"MRXkqODxY3WxLGulvQ8wMLwZz/jGJ2mfdm/3ac8OfxBIngP4DKAGUAHYBD9vnHO3JzFsDJA8J3nH\n" +
"Mu5IfvGb8feA5MxALsYlyerUtptActqDIEk+kvxyavtNILnoSZKU0D0KW3cKIiX4sGtDb+I/HwxD\n" +
"twA+OueaX2XbLwMlCc1J7gqeXJ/a1sEwhPKsvXfUECVZQ0KpgtSyHaSWfbOGjQ/PC3+5g4RdE9dA\n" +
"v9YGwIvENA2AN6OEqg+dzyQfxggbkjfKHA8kJ9G9Ncmm5MUh5C4oadqC+UCCLa4ZZEuSE+W+uyHE\n" +
"Jsx7LIVNeeaniFh4olpCWURjlsp9r/qQu+hIrBNBhXDKq1VwT6Ws+bbrQhatqGHVh2Cw/jyabx39\n" +
"vkkRfGacvAawBjBE4CY96D3x2l9WkMx5H2dA59yS5BT7gn+QcCCZM8a7olWU582aSHKYBHNWlFDP\n" +
"PceXjKQXJWuGCMM0VRvfl8j1Ufg5g7+yW5gfZcLo93DT4mzakHz+u8gNwTSyaxv8Nk/YvKM8jzUA\n" +
"nCnkJgAus+79faij60b5DufcyjlXOecmzrktkCDomV+PbmZ/3ETXYTYulp6DLEp5qIdmyzFx33qi\n" +
"hXNuRRIQfborTRCXiWv8OeSAY+8BEJLWCZ4IUuRPXFss+A5R/FtIyOxSO+ujow4+U6RPAiHG2Wzq\n" +
"UkdDQ9F/cQLouu6UaQUS4prRKaILnF9oBelHlvADwBLAMnXW4v48GO58sZ/p0/0CeY9u/bpXBjsP\n" +
"Jrd6b8NEi46iUUuq5NHfo4Yc82e7EMnmUo6gdtQIkXyo2V3GPTIT1jyWYirJLgRL0kkj11fplEha\n" +
"W4e2E3thkq0ypm+TtoXawqCEvCVUbefLwiTJnWb303wKasudtseGFn5JLerxLVYRfvEZ9k3ZIcil\n" +
"/mTk9EGOoKYWptH1FaRF5wC89NcW5DapKMEgJauIHEEtxsMUfeucm7XKxdfGOUTdDIGlDJi8fAbF\n" +
"GGPTdKmMsySAnJcsCimpU2OcacZQL6bqeSyAxQM5Az8NHP8ElSD0JBDef0TEb0zpTdCVFiE+c5c8\n" +
"eGU5KoWTphqsWoGvuK9TB7KJUsPWhezeZKIDxvHdsjj1wp2cKLr/0Ru1pk22xVk4nNeijvq9c2C6\n" +
"e5xTHDPaFEeLJmccbTp0oY23EDznYceqhdp8ooRr6WUJqZxEgnkson1QZzwkmXoej5qw0bia0lq/\n" +
"8WQ2/vs8R8yPtbzrGP4qLCKZ8uQDM89Pj3VK7xTpN7v3ab5kgCZ4Hygd6s56lOQHP9aSjFYc4c8+\n" +
"2VfYlJq0hF7XGuybTcBhjayij9UTtwBmnercUFCSgCWZ9EXjPTb6v5Y6/QnBGzCFeMMip3K4h3h8\n" +
"45wzya4+GPQvC0oCqCGSLReCbSjvIH3TXm97/+M//kH8BEhmToz+KexyAAAAAElFTkSuQmCC").bitmap,
contributorName = "fankes"
),
IconDataBean(
isEnabled = true,
isEnabledAll = false,
appName = "抖音",
packageName = "com.ss.android.ugc.aweme",
iconBitmap = ("iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAAXNSR0IArs4c6QAAAARzQklUCAgI\n" +
"CHwIZIgAAALtSURBVGiB7Znfa41xHMdfHynkxwVN0UhYbGkNhRpFcaFYbtzaDSK2/AGKC5e4oEZZ\n" +
"SSkuXLASU2q1C7VWcrNxoQwrbNiYm928XZyz9Th7znm+3+fHOc/K6/Kc7+fzfb/O0/f7PN/zQJVQ\n" +
"NNeT9F+QVtAUqE9SnCeRuiTFllaKKCTJYVi9mY3G6Z+nKwJwrNYBInFY7JI0WOuckTiKSNLpOP3z\n" +
"tkYAfgMNZvbVp3/e1gjAcuCFb1EeRQCaJY1Iaqt1kDl4rJFSbktaH9U/j2skjB/AM6AbGAXGzGwi\n" +
"OGC+iJTSZ2YHgh/kdY14818kb+RJ5H2S4jyJ3Ae64hYvTDKzpN1AG4WzRB2wGBgBxs3som8/Mzsn\n" +
"qQc4g+eTsLeIpJVAB3AU2FlmWJ9v3xnMrBfolbQPaAcOA2uj6rxEJHUAncDmOCF9MLN+oL847y6g\n" +
"FdgIrAFWlY53Eik+ItwD9qeW1AMzGwAGKo2JFJG0l+Ivk2cq7lqSljAPJCB6+71RlRQpUFZE0lng\n" +
"ZBWzJCJURNIKClvsvKHcYu8AGh17vAEeUzgvDFG4t5S7v1QXSUOOp7dbxavn0jOKy0kyz7kikrbg\n" +
"djVOmVl3ksnTJGyNtDrUvcyTBISLbHWoy922HCYS9a/4L+B5BlkSESayOqLmlZlNZxEmCXEOVsO+\n" +
"BZKWOQwbj5FlljCR7xE1cZ6Amx3GvIvRd5YwkahfpqW4RfvgIvLWs+c/hIl8cKg74TlPe8T3P83s\n" +
"k2fPykhqcbgLT0na5tjvjkO/h6lKBCb/6DD5U0kVj7ySjjj0kaTOrES6HANMSeqQtKmkfrukq449\n" +
"piXtyEqkUdKkY5AZPksalPTHs+5aJhIBmSuegeLwRdKGrEUWSXqdsciFTCUCMg0ZSjyqikRAZk8G\n" +
"Eg+qKhGQaZI0nJLEpZpIlMjcTSAwIul8TSWCSDooqcdDYELSTUnrsswV+2WopCbgOHCIwhmmDlgK\n" +
"fAPGKLy4eQL0mNlk8qiV+Qt8xU94PoUr+AAAAABJRU5ErkJggg==").bitmap,
contributorName = "fankes"
),
IconDataBean(
isEnabled = true,
isEnabledAll = false,
appName = "快手",
packageName = "com.smile.gifmaker",
iconBitmap = ("iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAAXNSR0IArs4c6QAAAARzQklUCAgI\n" +
"CHwIZIgAAATHSURBVGiBzZptiBZVFMf/R7ZNhQjckoxeNqwPbrZs2habRFZkVmZJKGYSRPQGRVpf\n" +
"IoLdCCPQ+mBEoEUFZbUF+aXEvuzaC2agbaYLS7ZL0btltfmWSb8+zDx6m2dm7p15Ztv+cJl57jn3\n" +
"nPOfmXvvmTOPqUEAJ0laIKlT0hmSJkkakPSZpAEz29OojzEFcBqwFhglH68CF4x3vKkAFgNfeAi4\n" +
"+A14eLzj/hdiEmXx0njHL0kC7muARA2PjzeJWcDhCogA3FF1fFaAyMuSbgtQ/U7Sdkk7JM2SNFvS\n" +
"6QmdEUltZnY44aNVUoekVkl/SxqutaRuKQDzA6/0+ozx61N0lznyTuDjHLt7gEVVEHkugMRCj43u\n" +
"hP47cf884FCAfYBVjRL51OOgJ8BGM/VX/aFAAi6eLEui2WP4ADAt0NaNBQL+BuiLjy7+AjrLEGn1\n" +
"ONxRwNa0QBIrEuNWJORvlCHS5XG6oaC9rzz2ujPGJefYdFc+IcD3AY/8h1ASMX7OkY1KWpchWyfJ\n" +
"XYLbXWEIkR898gsDbEiSgBMl5SWQW83s+zRB3P+10zXblXuJmJmPyPk+GwnnJ+TIv/SM/905n+MK\n" +
"Qu6IJPXnyE4FHgi0c7dHfrlHfpZzviXQ53EAqz0TdBiY6rERmh0szRi/NKF3XRkiM4H9ngDeJ+MF\n" +
"Cpgbkw3BEDA3ZfxQQi9o70oLZlVAEHuBlUBXPKYr/u27CEkcAl4BeuJjMoVZm4yvSPY7WdJOSdN9\n" +
"umOMfZIuSdYCQie7zOygpMVVR1UCz1RS0ADagJGCj0oV2AcsqeBC1JHp/Y8I/EI0T3ITxeA5kkHo\n" +
"dkm3SroqcMgRRSlPaNtmZptCDDdEpAaipbBWoGtW9KpbF5iZHanCXxoqIVIUQJOkKZJanJb1e6/T\n" +
"NprZQJrNMSECnCtpeSI49/zkBszfaWbPJzsziQC9kprkVDJ0vKJxNGfcNEWVlLFCv5ldkexsygjm\n" +
"CWXvGUeBEUWkRuI2LOmjONU+JGm3imXF1YPyhbjPgfNiG23ArsZX3lT0hRKZmxyIv+Jew3bg7IrJ\n" +
"DAEbgEeAhcA5ZYj0Of0zgGXAGg+5rcSZaQkyo7HtNcAtwMyiT1QWkXdz9CYClwI/pQS0BWgpSGYX\n" +
"0JbjbypwJQE1tDQi3rIL9dWNGt4j+poVSubZWHcy0AEsAR4FXge+dfQ+TIsjddVy8EcA96wl/GpJ\n" +
"rwE3m9kgUcLXq+zVbG98vFhS3oSelNbpS+NDiOThekVkzMwGJb3VoD1JmpjW6SOyvwLHi+QvKhRB\n" +
"qTsyucIAqkKpOzJlDAIJwRJJZ0p6LEWWSsQ32VsajagozKxfOpazpSH10fIRmdFIUDFWmlk/Ud3r\n" +
"phy97ngfGZQ0T1JXhl7qHakD9SnKtR79npy94WlH70XPPhKK3rJENgPtOfpZRN52dO6vgMBOiv7p\n" +
"gPqq3ijRd8TlQDswydFNI/Ir0BHL5wAHSwS+G3gBuBe4qBABJ7iQfzfUPo2l5VorHFvdGTpJfAI8\n" +
"RZSahGW4DvLeEBdIukvSDQVtbjSzuk/JwGWSrpF0StxaJH0Qt21mNlrQTzEQVdFXE71r+HDskfpf\n" +
"gyiLfRDYBPyZQuSe8YqtdBUFmCBpvqJsFUmDZvZmVYEVxT/gE25lNuhldAAAAABJRU5ErkJggg==").bitmap,
contributorName = "fankes"
),
IconDataBean(
isEnabled = true,
isEnabledAll = false,
appName = "哔哩哔哩",
packageName = "tv.danmaku.bili",
iconBitmap = ("iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAAXNSR0IArs4c6QAAAARzQklUCAgI\n" +
"CHwIZIgAAALMSURBVGiB7Zm9axRBGMafV4KIUZCgBFTEkKgg+FUFtMk/YNDCRhEVg5ViIdgoJBZq\n" +
"kc5SBAuNgqXa+FFYiEUawRQSOY0SQhBF8IO0P4vbwN3ezN7czu4lxf7gipt9n3eed3dndmdWqqio\n" +
"qHABjAMLwCxwu8C8t4EaMAeMF5XX19kErUwBvRE5e5McaSaK9J7udM7RIcBrYCBHvoFE62KhjBqW\n" +
"O571dAowAwx3kGs40fh4VWYhkxkdA3wHRgPyjCaxWZwrrZDExJU2BgDGMvRjAfrrnfqyQPO7JW1t\n" +
"aNoi6Ukb2TVJ71JthyXdbKObknSv4f+8mX0O8ekFuAXMB5zBspkD7mR59V4RoCZpMOpMFE/NzHa5\n" +
"DqxxNQLvtfqKkKQh4K3rQEshwCVJB0u3lJ8jQMs4c12RU10wE8vJdEPTGAE2SPrrEf+TdEHSYvG+\n" +
"WuiTtE9S1mvKDjObdx4BBn3TRhluQ8iYyUYa49K3Vr8n341ybAYR9PKYLmStJ246zksUn0KCnNOv\n" +
"g6UII7EEjcnQQloANlFfDC0m9+zTDvUjwP2Ge7649UeSvO3ASmKPOeKCzeBepJ3I6yn3FZF02dF2\n" +
"vgO9azl7OqeXqEJcbI/Ub8wrLLqQFaMqRFLN0fY1Ip8k/cgrjCnEtcvxpgN9evUoSV9yemmmk+k3\n" +
"iX/cEPMC2NlBX3uB6UT7B5gswlNuEbAN2BNagEO/H1gX66knr4FlzCxqI83MPsR6kKpZa/URWshK\n" +
"ruGHQoJCCzkTYSQW32vPL68COOCZIaC+ax50dooA6KP+LcZH02o2vfmwWdlP1yVJs5J+F2+9Bf9z\n" +
"QpKZNXnvSR38CTyTdNSjXy/pUJS9YniQbnCNkbtdMBLLw3RDSyFm9lzSxa7YycdVM3sZHE19KVrL\n" +
"GGzd5htw1ue37fcR4Ljq3zX6k59vy6gsPkqakfTIzLoxyVRUVFR0gf/L83vOF7040QAAAABJRU5E\n" +
"rkJggg==").bitmap,
contributorName = "fankes"
),
IconDataBean(
isEnabled = true,
isEnabledAll = false,
appName = "知乎",
packageName = "com.zhihu.android",
iconBitmap = ("iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAAXNSR0IArs4c6QAAAARzQklUCAgI\n" +
"CHwIZIgAAAN3SURBVGiB7ZpLiBRXFIa/X5QYjAnIDIFBiIK6SMhCAgoK0iNiRFyoqCiCRCUGXLhx\n" +
"52rwsU0cRBRxIROCoCARRBAce5JFHgYSyEMRDC5iFjJRXMS4/F10Vbosu6vqVlVPj+IHDbfqnHvu\n" +
"+bvurXuqukUOthcC7+X59ZhHkn7NclCnk7b3AKuBlcCCHiRWhgdAE/hG0ulcb9tfe/pzx/bHybyV\n" +
"EuFav8Pe86Gk3wFmxGdsj/Qvn9KceO7I9s6+TpRq7Ib2FVkz1V9ljWyAtpAP+phIVVZBW8j7JYP8\n" +
"A1ysJZ3yDNheOjM6mFMiwDZJF20/rTOrkrwzI9+nI7GIjcDsOjMqSxkh5yXF02lTnclUYWa+ywuM\n" +
"AtieQ6uMCWWiRB+ARpZRELSjj0taE/VZDywr2G8L7TvjsKRgMTk5DodekRtxQ9JV4GrBJKDHt/hQ\n" +
"IeMlx7nZ6aTzy6KJoKtXsBT4LeG/L2lInF9bIE4jYNyivo2Qu1byauzr4vNmQLxaKSpkEjgOYPsC\n" +
"8FEXv77tKUWFjABDtseArRl+b1RPqRxFF/vJgn59E1K2ROnGayFVeWWEhGyIu4C/cny+A4a72JoB\n" +
"YwVTVMiYpC/znLJ2Ydt/0MMypaiQa8ldNk3BMuIHpoGQrzJsl4hKc9tNcsrtXlHHYr9bQ4zK1CHk\n" +
"dqLdt/fEdQi5CWB7gNYU21VDzGDKPOom+UnSrai9UtJuANsLgMMVYwdR9Yok32ntsD0XQNIR4EzF\n" +
"2EFUEfIncA7A9ipgM3AhNkr6DLhcKbsAqgj5XNJk1N4GzALW2R5N+OyltX90o9P+M5H4hFHgkTNN\n" +
"M9F3yPbfKfuBhH1Ft8fXyH4vOv+LWy/8yuTYKLvYv0i0twNDKfuo7ceSxoDM3/5oPevMk3SoZC5A\n" +
"+HstgP2STkX93gK+BZZ28HsC7JR0ORX//ykjadj2u5IeRPE2AAe7jJtVMbQK1YApdT3Z2/axHP+f\n" +
"bTcy7IOJWEcD8kjTCBFyMiXik4L9mhm2/bbn2x4vGKsbhYV8Gvktsr3D9vmKA8c0bf9XQ5xGvEYm\n" +
"gYGMOTjdWRzvI3f6mkY17ku6+yoI+R7aO/uNDMfpzpXnjmyP1LDoppp2bZcS87L9hWNA0kNIFY2S\n" +
"xBRWrBWYAN6ORUD235yWA0tovfkY7OQ3hfxLq2a7Bfwo6Wyf8+kdzwC8NyXjf0uu9wAAAABJRU5E\n" +
"rkJggg==").bitmap,
contributorName = "fankes"
),
IconDataBean(
isEnabled = true,
isEnabledAll = false,
appName = "小红书",
packageName = "com.xingin.xhs",
iconBitmap = ("iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAAXNSR0IArs4c6QAAAARzQklUCAgI\n" +
"CHwIZIgAAAJ+SURBVGiB7ZkrjxVBEIXPIYTwC9BAEBgSDGYFWcCRiyGAwWzYDQ4C4WF4LQqBQSIJ\n" +
"CeZKwCGAgCAIXmIBxeJY+BEHsUNyM7e7pqt7tgcxXzKip27VrcrpnurpAUZGRiyY4yRp1QxKmvb/\n" +
"AkmLsjk4RF7bM3zuGLYpyU/tm5IWM/5nDpKv+oiTosauiN9qh18SVm7bnLXcMmwPSP52xuuN5EKa\n" +
"6XE0Zid5uZeMMvEocs2wXS9NpJSkQho1jkfMv0je7y+lPFIVuWDYrvaRSCmdhTRqnIyYP5B80m9K\n" +
"eaT0kRXDdgVI7hOhHmD59dMzAEDSQsejfSppybD/MGJ39RZXE+1S5FyH/XRzxbjrSaaE6BqRtAfA\n" +
"ckHsdZKPCvxdWIv9WGHsamoAdiFnC+JWVQOwC/lcELeqGoC92O9hs9ADEXvsqVJdDcAohOQGgIsh\n" +
"m6SvRszqagD+bTwknQKwP2IeRA0goxDYO91B1ACchUiaADgUMQ+mBuBX5JJhG0wNwPeGOIHRJIdU\n" +
"A/Cdopy3jJJetu+RPOLOKJOkQho1TnT8rN1Xun7fK6lTy9rhhnhL8rk3mRJS3hB3ADjjjBtspFtJ\n" +
"iiJ7Aex0xHxM8mNmPtl0FkLyG4B3jpiDHEakPrWWsbmYg0eis5D8U5RRJkmFkFwDsLbFuRRhTi1J\n" +
"E0m7ayVTgvmhR9JT+PrBYZJvZvznmmSL3OOg18kfkxo1PLxo+VvHRKXMFWFNLXNLEuBGa2x9EOqd\n" +
"YCFK25LM8ozk+xn/JQBV11ZMEa8aN1vjqmoAgUIy1JiS/DLjX10NIKyIV43brXF1NYBwQ3wIYAPA\n" +
"vgT/nyS//xs0aqw318jIyEj//AXLwAqzwAEk3wAAAABJRU5ErkJggg==").bitmap,
contributorName = "fankes"
),
// TODO 可继续在这里添加更多 APP
)
appName = it.getString("appName"),
packageName = it.getString("packageName"),
isEnabled = it.getBoolean("isEnabled"),
isEnabledAll = it.getBoolean("isEnabledAll"),
iconBitmap = it.getString("iconBitmap").bitmap,
iconColor = safeOfNan { Color.parseColor(it.getString("iconColor")) },
contributorName = it.getString("contributorName")
)
}
}
}
/**
* 拼接图标数组数据
* @param dataJson1 图标数据 JSON
* @param dataJson2 图标数据 JSON
* @return [String] 拼接后的数据
*/
fun splicingJsonArray(dataJson1: String, dataJson2: String) = safeOf(default = "[]") {
dataJson1.replace(oldValue = "]", newValue = "") + "," + dataJson2.replace(oldValue = "[", newValue = "")
}
/**
* 是否不为合法 JSON
* @param json 数据
* @return [Boolean]
*/
fun isNotVaildJson(json: String) = !isJsonArray(json) && !isJsonObject(json)
/**
* 是否为 JSON 数组
* @param json 数据
* @return [Boolean]
*/
fun isJsonArray(json: String) = json.trim().let { it.startsWith("[") && it.endsWith("]") }
/**
* 是否为 JSON 实例
* @param json 数据
* @return [Boolean]
*/
fun isJsonObject(json: String) = json.trim().let { it.startsWith("{") && it.endsWith("}") }
/**
* 是否为异常地址
* @param json 数据
* @return [Boolean]
*/
fun isHackString(json: String) = json.contains(other = "Checking your browser before accessing")
/**
* 比较图标数据不相等
* @param dataJson 图标数据 JSON
* @return [Boolean] 是否不相等
*/
fun isCompareDifferent(dataJson: String) = storageDataJson?.trim() != dataJson.trim()
/**
* 保存图标数据
* @param dataJson 图标数据 JSON
*/
fun save(dataJson: String) = context?.modulePrefs?.put(DataConst.NOTIFY_ICON_DATAS, dataJson)
}

View File

@@ -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>()
}
}

View File

@@ -1,123 +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() }
/** 设置列表元素和 Adapter */
findViewById<ListView>(R.id.config_list_view).apply {
adapter = object : BaseAdapter() {
private val inflater = LayoutInflater.from(context)
override fun getCount() = IconPackParams.iconDatas.size
override fun getItem(position: Int) = IconPackParams.iconDatas[position]
override fun getItemId(position: Int) = position.toLong()
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
var cView = convertView
val holder: ViewHolder
if (convertView == null) {
holder = ViewHolder()
cView = inflater.inflate(R.layout.adapter_config, null).also {
holder.appIcon = it.findViewById(R.id.adp_app_icon)
holder.appName = it.findViewById(R.id.adp_app_name)
holder.pkgName = it.findViewById(R.id.adp_app_pkg_name)
holder.cbrName = it.findViewById(R.id.adp_cbr_name)
holder.switchOpen = it.findViewById(R.id.adp_app_open_switch)
holder.switchAll = it.findViewById(R.id.adp_app_all_switch)
}
cView.tag = holder
} else holder = convertView.tag as ViewHolder
getItem(position).also {
holder.appIcon.setImageBitmap(it.iconBitmap)
holder.appName.text = it.appName
holder.pkgName.text = it.packageName
holder.cbrName.text = "贡献者:" + it.contributorName
HookMedium.isAppNotifyHookOf(it).also { e ->
holder.switchOpen.isChecked = e
holder.switchAll.isEnabled = e
}
holder.switchOpen.setOnCheckedChangeListener { btn, b ->
if (!btn.isPressed) return@setOnCheckedChangeListener
HookMedium.putAppNotifyHookOf(it, b)
holder.switchAll.isEnabled = b
}
holder.switchAll.isChecked = HookMedium.isAppNotifyHookAllOf(it)
holder.switchAll.setOnCheckedChangeListener { btn, b ->
if (!btn.isPressed) return@setOnCheckedChangeListener
HookMedium.putAppNotifyHookAllOf(it, b)
}
}
return cView!!
}
inner class ViewHolder {
lateinit var appIcon: ImageFilterView
lateinit var appName: TextView
lateinit var pkgName: TextView
lateinit var cbrName: TextView
lateinit var switchOpen: MaterialSwitch
lateinit var switchAll: MaterialSwitch
}
}
}
/** 设置点击事件 */
findViewById<View>(R.id.config_cbr_button).setOnClickListener {
try {
startActivity(Intent().apply {
action = "android.intent.action.VIEW"
data = Uri.parse("https://github.com/fankes/MIUINativeNotifyIcon")
/** 防止顶栈一样重叠在自己的 APP 中 */
flags = Intent.FLAG_ACTIVITY_NEW_TASK
})
} catch (e: Exception) {
Toast.makeText(this, "无法启动系统默认浏览器", Toast.LENGTH_SHORT).show()
}
}
}
}

View File

@@ -1,206 +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
}
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 版本:$miuiVersion"
when {
/** 判断是否为 MIUI 系统 */
isNotMIUI ->
showDialog {
title = "不是 MIUI 系统"
msg = "此模块专为 MIUI 系统打造,当前无法识别你的系统为 MIUI所以模块无法工作。\n" +
"如有问题请联系 酷安 @星夜不荟"
confirmButton(text = "退出") { finish() }
noCancelable()
}
/** 判断最低系统版本 */
isLowerAndroidP ->
showDialog {
title = "系统版本过低"
msg = "此模块最低支持基于 Android 9 的 MIUI 系统,你的系统版本过低不再进行适配。\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 = true)
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()
}
}
}
/**
* 判断模块是否激活
* @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)
}

View File

@@ -0,0 +1,274 @@
/*
* 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.YukiHookAPI
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 (YukiHookAPI.Status.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
fun saveState() {
putAppNotifyHookAllOf(it, b)
SystemUITool.refreshSystemUI(context = this@ConfigureActivity)
}
if (b) showDialog {
title = "全部替换"
msg = "此功能仅针对严重不遵守规范的 APP 通知图标才需要开启例如APP 推送通知后无法识别出现的黑白块图标。\n\n" +
"此功能在一般情况下请保持关闭并跟随在线规则的配置,并不要随意改变此配置," +
"开启后 APP 的通知图标可能会被规则破坏,你确定还要开启吗?"
confirmButton { saveState() }
cancelButton { btn.isChecked = btn.isChecked.not() }
noCancelable()
} else saveState()
}
}
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 {
showDialog {
title = "感谢你的贡献"
msg = "通知图标优化名单需要大家的共同维护才能得以完善,请选择你的贡献方式。"
confirmButton(text = "贡献规则") { openBrowser(url = "https://github.com/fankes/AndroidNotifyIconAdapt/blob/main/CONTRIBUTING.md") }
cancelButton(text = "请求适配") { openBrowser(url = "https://github.com/fankes/MIUINativeNotifyIcon/issues/new/choose") }
neutralButton(text = "暂时不用")
}
}
/** 装载数据 */
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()
}
}

View File

@@ -0,0 +1,359 @@
/*
* 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 android.widget.SeekBar
import androidx.core.view.isGone
import androidx.core.view.isVisible
import com.fankes.miui.notify.BuildConfig
import com.fankes.miui.notify.R
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.fankes.miui.notify.utils.tool.YukiPromoteTool
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.hook.factory.modulePrefs
class MainActivity : BaseActivity<ActivityMainBinding>() {
companion object {
/** 窗口是否启动 */
internal var isActivityLive = false
/** 模块版本 */
private const val moduleVersion = BuildConfig.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 */
YukiHookAPI.Status.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()
}
if (isLowerAndroidR && modulePrefs.get(DataConst.IGNORED_ANDROID_VERSION_TO_LOW).not())
showDialog {
title = "Android 版本过低"
msg = "你当前使用的 Android 版本过低,模块的部分功能可能会发生问题," +
"由于设备有限,无法逐一调试,若有好的建议可向我们贡献代码提交适配请求,建议在 Android 11 及以上版本中使用效果最佳。"
confirmButton(text = "我知道了") { modulePrefs.put(DataConst.IGNORED_ANDROID_VERSION_TO_LOW, value = true) }
noCancelable()
}
/** 推广、恰饭 */
YukiPromoteTool.promote(context = this)
}
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.notifyIconCustomCornerItem.isVisible = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX) &&
modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FORCE_APP_ICON).not()
binding.notifyIconForceAppIconItem.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.notifyIconForceAppIconSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FORCE_APP_ICON)
binding.notifyIconFixNotifySwitch.isChecked = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX_NOTIFY)
binding.notifyIconAutoSyncSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX_AUTO)
binding.notifyIconCustomCornerSeekbar.progress = modulePrefs.get(DataConst.NOTIFY_ICON_CORNER)
binding.notifyIconCustomCornerText.text = "${modulePrefs.get(DataConst.NOTIFY_ICON_CORNER)} dp"
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.notifyIconCustomCornerItem.isVisible = b && modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FORCE_APP_ICON).not()
binding.notifyIconForceAppIconItem.isVisible = b
binding.notifyIconFixNotifyItem.isVisible = b
binding.notifyIconAutoSyncItem.isVisible = b
SystemUITool.refreshSystemUI(context = this)
}
binding.notifyIconForceAppIconSwitch.setOnCheckedChangeListener { btn, b ->
if (btn.isPressed.not()) return@setOnCheckedChangeListener
fun saveState() {
binding.notifyIconCustomCornerItem.isVisible = b.not()
modulePrefs.put(DataConst.ENABLE_NOTIFY_ICON_FORCE_APP_ICON, b)
SystemUITool.refreshSystemUI(context = this)
}
if (b) showDialog {
title = "破坏性功能警告"
msg = "开启这个功能后,任何通知栏中的通知图标都会被强制替换为当前推送通知的 APP 的图标," +
"某些系统级别的 APP 通知图标可能会显示异常或发生图标丢失。\n\n" +
"此功能仅面向一些追求图标美观度的用户,我们不推荐开启这个功能,且发生任何 BUG 都不会去修复,仍然继续开启吗?"
confirmButton { saveState() }
cancelButton { btn.isChecked = btn.isChecked.not() }
noCancelable()
} else saveState()
}
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.notifyIconCustomCornerSeekbar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
binding.notifyIconCustomCornerText.text = "$progress dp"
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
modulePrefs.put(DataConst.NOTIFY_ICON_CORNER, seekBar.progress)
SystemUITool.refreshSystemUI(context = this@MainActivity)
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {}
})
/** 通知图标优化名单按钮点击事件 */
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 {
YukiHookAPI.Status.isXposedModuleActive && (isModuleRegular.not() || isModuleValied.not()) -> R.drawable.bg_yellow_round
YukiHookAPI.Status.isXposedModuleActive -> R.drawable.bg_green_round
else -> R.drawable.bg_dark_round
}
)
binding.mainImgStatus.setImageResource(
when {
YukiHookAPI.Status.isXposedModuleActive -> R.mipmap.ic_success
else -> R.mipmap.ic_warn
}
)
binding.mainTextStatus.text =
when {
YukiHookAPI.Status.isXposedModuleActive && isModuleRegular.not() && modulePrefs.get(DataConst.ENABLE_MODULE).not() -> "模块已停用"
YukiHookAPI.Status.isXposedModuleActive && isModuleRegular.not() -> "模块已激活,请重启系统界面"
YukiHookAPI.Status.isXposedModuleActive && isModuleValied.not() -> "模块已更新,请重启系统界面"
YukiHookAPI.Status.isXposedModuleActive -> "模块已激活"
else -> "模块未激活"
}
binding.mainTextApiWay.isVisible = YukiHookAPI.Status.isXposedModuleActive
binding.mainTextApiWay.text = "Activated by ${YukiHookAPI.Status.executorName} API ${YukiHookAPI.Status.executorVersion}"
}
override fun onResume() {
super.onResume()
/** 刷新模块状态 */
refreshModuleStatus()
/** 检查模块激活状态 */
SystemUITool.checkingActivated(context = this) { isValied ->
isModuleRegular = true
isModuleValied = isValied
refreshModuleStatus()
}
}
}

View File

@@ -0,0 +1,61 @@
/*
* 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.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
import com.highcapable.yukihookapi.hook.xposed.application.ModuleApplication.Companion.appContext
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
}
/** 拉取云端数据 */
IconRuleManagerTool.sync(appContext) {
/** 刷新系统界面 */
SystemUITool.refreshSystemUI()
/** 结束当前窗口 */
runOnUiThread { delayedRun(ms = 1000) { finish() } }
}
/** 切换到后台 */
moveTaskToBack(true)
}
}

View File

@@ -0,0 +1,79 @@
/*
* 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.core.content.res.ResourcesCompat
import androidx.core.view.ViewCompat
import androidx.viewbinding.ViewBinding
import com.fankes.miui.notify.R
import com.fankes.miui.notify.utils.factory.isNotSystemInDarkMode
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()
/** 初始化沉浸状态栏 */
ViewCompat.getWindowInsetsController(window.decorView)?.apply {
isAppearanceLightStatusBars = isNotSystemInDarkMode
isAppearanceLightNavigationBars = isNotSystemInDarkMode
}
ResourcesCompat.getColor(resources, R.color.colorThemeBackground, null).also {
window?.statusBarColor = it
window?.navigationBarColor = it
window?.navigationBarDividerColor = it
}
/** 装载子类 */
onCreate()
}
/** 回调 [onCreate] 方法 */
abstract fun onCreate()
}

View File

@@ -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()
}
}

View File

@@ -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
}
}

View File

@@ -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()
}

View File

@@ -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);
}
}

View File

@@ -1,257 +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.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
/**
* 系统深色模式是否没开启
* @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 [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 = "")
}
} + " " + 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()
}

View File

@@ -1,37 +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 {
fun getBoolean(key: String, default: Boolean = false) = pref.getBoolean(key, default)
private val pref: XSharedPreferences
get() {
val preferences = XSharedPreferences(BuildConfig.APPLICATION_ID)
preferences.makeWorldReadable()
preferences.reload()
return preferences
}
}

View File

@@ -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.
*/

View File

@@ -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 {

View File

@@ -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.
*/

View File

@@ -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.
*/

View File

@@ -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.
*/

View File

@@ -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.
*/

View File

@@ -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.
*/

View File

@@ -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.
*/

View File

@@ -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.
*/

View File

@@ -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.
*/

View File

@@ -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.
*/

View File

@@ -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.
*/

View File

@@ -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.
*/

View File

@@ -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 initiate 对话框方法体
*/
fun Context.showDialog(isUseBlackTheme: Boolean = false, initiate: DialogBuilder.() -> Unit) =
DialogBuilder(context = this, isUseBlackTheme).apply(initiate).show()
/**
* 显示时间选择对话框
* @param timeSet 当前时间 - 不写将使用当前时间格式HH:mm
* @param result 回调 - 小时与分钟 HH:mm
*/
fun Context.showTimePicker(timeSet: String = "", result: (String) -> Unit) =
TimePickerDialog(this, { _, h, m -> result("${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 callback 点击事件
*/
fun confirmButton(text: String = "确定", callback: () -> Unit = {}) {
if (isUsingAndroidX)
runInSafe { instanceAndroidX?.setPositiveButton(text) { _, _ -> callback() } }
else runInSafe { instanceAndroid?.setPositiveButton(text) { _, _ -> callback() } }
}
/**
* 设置对话框取消按钮
* @param text 按钮文本内容
* @param callback 点击事件
*/
fun cancelButton(text: String = "取消", callback: () -> Unit = {}) {
if (isUsingAndroidX)
runInSafe { instanceAndroidX?.setNegativeButton(text) { _, _ -> callback() } }
else runInSafe { instanceAndroid?.setNegativeButton(text) { _, _ -> callback() } }
}
/**
* 设置对话框第三个按钮
* @param text 按钮文本内容
* @param callback 点击事件
*/
fun neutralButton(text: String = "更多", callback: () -> Unit = {}) {
if (isUsingAndroidX)
runInSafe { instanceAndroidX?.setNeutralButton(text) { _, _ -> callback() } }
else runInSafe { instanceAndroid?.setNeutralButton(text) { _, _ -> callback() } }
}
/** 取消对话框 */
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()
}
}

View File

@@ -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) }
}

View File

@@ -0,0 +1,538 @@
/*
* 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.ApplicationInfo
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.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.highcapable.yukihookapi.hook.xposed.application.ModuleApplication.Companion.appContext
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
/**
* 系统版本是否低于 Android 11
* @return [Boolean] 是否符合条件
*/
inline val isLowerAndroidR get() = Build.VERSION.SDK_INT < Build.VERSION_CODES.R
/**
* 当前设备是否是 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) }
/**
* 获取 APP 是否为 DEBUG 版本
* @param name APP 包名
* @return [Boolean]
*/
fun Context.isAppDebuggable(name: String) =
safeOfFalse { (packageManager?.getPackageInfo(name, 0)?.applicationInfo?.flags?.and(ApplicationInfo.FLAG_DEBUGGABLE) ?: 0) != 0 }
/**
* 对数值自动补零
* @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
}
/**
* 是否有 Root 权限
* @return [Boolean]
*/
val isRootAccess get() = safeOfFalse { Shell.rootAccess() }
/**
* 执行命令
* @param cmd 命令
* @param isSu 是否使用 Root 权限执行 - 默认:是
* @return [String] 执行结果
*/
fun execShell(cmd: String, isSu: Boolean = true) = safeOfNothing {
(if (isSu) Shell.su(cmd) else Shell.sh(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(if (this is Service) applicationContext else this, T::class.java).apply {
if (this@navigate !is Activity) flags = Intent.FLAG_ACTIVITY_NEW_TASK
})
}
/**
* 弹出 [Snackbar]
* @param msg 提示内容
* @param actionText 按钮文本 - 不写默认取消按钮
* @param callback 按钮事件回调
*/
fun Context.snake(msg: String, actionText: String = "", callback: () -> 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) { callback() }
}.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) }

View File

@@ -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)
}
}

View File

@@ -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 result 成功后回调 - ([String] 最新版本,[Function] 更新对话框方法体)
*/
fun checkingForUpdate(context: Context, version: String, result: (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()
result(name) { showUpdate() }
}
}
}
}
})
}
/**
* 检查网络连接情况
* @param context 实例
* @param callback 已连接回调
*/
private fun checkingInternetConnect(context: Context, callback: () -> 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 { callback() } }
}
})
}
/**
* 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
}

View File

@@ -0,0 +1,192 @@
/*
* 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.BuildConfig
import com.fankes.miui.notify.hook.HookEntry
import com.fankes.miui.notify.utils.factory.*
/**
* 通知图标适配推送通知类
*
* 这个类需要在 [HookEntry] 中调用
*/
object IconAdaptationTool {
/** 当前模块的包名 */
private const val MODULE_PACKAGE_NAME = BuildConfig.APPLICATION_ID
/** 推送通知的渠道名称 */
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) {
if (context.isAppDebuggable(packageName)) return
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(
MODULE_PACKAGE_NAME,
"${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(
MODULE_PACKAGE_NAME,
"${MODULE_PACKAGE_NAME}.ui.activity.auto.NotifyIconRuleUpdateActivity"
)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
)
}
}
}
}

View File

@@ -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 callback 成功后回调
*/
fun syncByHand(context: Context, callback: () -> 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, callback)
}
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)
callback()
}
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)
callback()
}
else -> context.snake(msg = "请输入有效内容")
}
}
}
}
neutralButton(text = "取消")
}
}
}
/**
* 从在线地址同步规则
* @param context 实例
* @param sourceType 同步地址类型 - 默认自动获取已存储的键值
* @param customUrl 自定义同步地址 - 默认自动获取已存储的键值
* @param callback 成功后回调
*/
fun sync(
context: Context,
sourceType: Int = context.modulePrefs.get(DataConst.SOURCE_SYNC_WAY),
customUrl: String = context.modulePrefs.get(DataConst.SOURCE_SYNC_WAY_CUSTOM_URL),
callback: () -> Unit
) {
when (sourceType) {
TYPE_SOURCE_SYNC_WAY_1 ->
onRefreshing(context, url = "https://raw.fastgit.org/fankes/AndroidNotifyIconAdapt/main", callback)
TYPE_SOURCE_SYNC_WAY_2 ->
onRefreshing(context, url = "https://raw.githubusercontent.com/fankes/AndroidNotifyIconAdapt/main", callback)
TYPE_SOURCE_SYNC_WAY_3 ->
if (customUrl.isNotBlank())
if (customUrl.startsWith("http://") || customUrl.startsWith("https://"))
onRefreshingCustom(context, customUrl, callback)
else context.snakeOrNotify(title = "同步失败", msg = "同步地址不是一个合法的 URL")
else context.snakeOrNotify(title = "同步失败", msg = "同步地址不能为空")
else -> context.snakeOrNotify(title = "同步异常", msg = "同步类型错误")
}
}
/**
* 开始更新数据
* @param context 实例
* @param url
* @param callback 成功后回调
*/
private fun onRefreshing(context: Context, url: String, callback: () -> Unit) = checkingInternetConnect(context) {
fun doParse(result: (Boolean) -> Unit = {}) {
wait(context, url = "$url/OS/$OS_TAG/NotifyIconsSupportConfig.json") { isDone1, ctOS ->
result(true)
wait(context, url = "$url/APP/NotifyIconsSupportConfig.json") { isDone2, ctAPP ->
result(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)
callback()
}
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, callback) }
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 callback 成功后回调
*/
private fun onRefreshingCustom(context: Context, url: String, callback: () -> Unit) = checkingInternetConnect(context) {
fun doParse(result: () -> Unit = {}) {
wait(context, url) { isDone, content ->
result()
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)
callback()
}
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 callback 已连接回调
*/
private fun checkingInternetConnect(context: Context, callback: () -> Unit) =
if (context is AppCompatActivity) context.showDialog {
title = "准备中"
progressContent = "正在检查网络连接情况"
noCancelable()
baseCheckingInternetConnect(context) { isDone ->
cancel()
if (isDone) callback() 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) callback() else pushNotify(context, title = "网络不可用", msg = "无法连接到互联网,无法更新通知图标规则")
}
/**
* 检查网络连接情况
* @param context 实例
* @param result 已连接回调
*/
private fun baseCheckingInternetConnect(context: Context, result: (Boolean) -> Unit) =
wait(context, url = "https://www.baidu.com") { isDone, _ -> result(isDone) }
/**
* 发送 GET 请求内容并等待
* @param context 实例
* @param url 请求地址
* @param result 回调 - ([Boolean] 是否成功,[String] 成功的内容或失败消息)
*/
private fun wait(context: Context, url: String, result: (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 { result(false, e.toString()) } ?: result(false, e.toString())
}
override fun onResponse(call: Call, response: Response) {
val bodyString = response.body?.string() ?: ""
(context as? Activity?)?.runOnUiThread { result(true, bodyString) } ?: result(true, bodyString)
}
})
}.onFailure { result(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>()
}
}
}

View File

@@ -0,0 +1,134 @@
/*
* 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.Context
import com.fankes.miui.notify.hook.HookConst.SYSTEMUI_PACKAGE_NAME
import com.fankes.miui.notify.utils.factory.*
import com.google.android.material.snackbar.Snackbar
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.hook.factory.dataChannel
import com.highcapable.yukihookapi.hook.param.PackageParam
import com.highcapable.yukihookapi.hook.xposed.channel.data.ChannelData
/**
* 系统界面工具
*/
object SystemUITool {
private val CALL_HOST_REFRESH_CACHING = ChannelData("call_host_refresh_caching", false)
private val CALL_MODULE_REFRESH_RESULT = ChannelData("call_module_refresh_result", false)
/**
* 宿主注册监听
*/
object Host {
/**
* 监听系统界面刷新改变
* @param param 实例
* @param result 回调 - ([Boolean] 是否成功)
*/
fun onRefreshSystemUI(param: PackageParam, result: (Boolean) -> Boolean) {
param.dataChannel.with { wait(CALL_HOST_REFRESH_CACHING) { put(CALL_MODULE_REFRESH_RESULT, result(it)) } }
}
}
/**
* 检查模块是否激活
* @param context 实例
* @param result 成功后回调
*/
fun checkingActivated(context: Context, result: (Boolean) -> Unit) = context.dataChannel(SYSTEMUI_PACKAGE_NAME).checkingVersionEquals(result)
/**
* 重启系统界面
* @param context 实例
*/
fun restartSystemUI(context: Context) =
context.showDialog {
title = "重启系统界面"
msg = "你确定要立即重启系统界面吗?\n\n" +
"部分 MIUI 内测和开发版中使用了状态栏主题可能会发生主题失效的情况,这种情况请再重启一次即可。\n\n" +
"重启过程会黑屏并等待进入锁屏重新解锁。"
confirmButton {
execShell(cmd = "pgrep systemui").also { pid ->
if (pid.isNotBlank())
execShell(cmd = "kill -9 $pid")
else toast(msg = "ROOT 权限获取失败")
}
}
cancelButton()
}
/**
* 刷新系统界面状态栏与通知图标
* @param context 实例
* @param isRefreshCacheOnly 仅刷新缓存不刷新图标和通知改变 - 默认:否
* @param callback 成功后回调
*/
fun refreshSystemUI(context: Context? = null, isRefreshCacheOnly: Boolean = false, callback: () -> Unit = {}) = runInSafe {
if (YukiHookAPI.Status.isXposedModuleActive)
context?.showDialog {
title = "请稍后"
progressContent = "正在等待系统界面刷新"
/** 是否等待成功 */
var isWaited = false
/** 设置等待延迟 */
delayedRun(ms = 5000) {
if (isWaited) return@delayedRun
cancel()
context.snake(msg = "预计响应超时,建议重启系统界面", actionText = "立即重启") { restartSystemUI(context) }
}
checkingActivated(context) { isValied ->
when {
isValied.not() -> {
cancel()
isWaited = true
context.snake(msg = "请重启系统界面以生效模块更新", actionText = "立即重启") { restartSystemUI(context) }
}
else -> context.dataChannel(SYSTEMUI_PACKAGE_NAME).with {
wait(CALL_MODULE_REFRESH_RESULT) {
cancel()
isWaited = true
callback()
if (it.not()) context.snake(msg = "刷新失败,建议重启系统界面", actionText = "立即重启") { restartSystemUI(context) }
}
put(CALL_HOST_REFRESH_CACHING, isRefreshCacheOnly)
}
}
}
noCancelable()
}
else context?.snake(msg = "模块没有激活,更改不会生效")
}
/**
* 显示需要重启系统界面的 [Snackbar]
* @param context 实例
*/
fun showNeedRestartSnake(context: Context) =
if (YukiHookAPI.Status.isXposedModuleActive)
context.snake(msg = "设置需要重启系统界面才能生效", actionText = "立即重启") { restartSystemUI(context) }
else context.snake(msg = "模块没有激活,更改不会生效")
}

View File

@@ -0,0 +1,59 @@
/*
* 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/5/30.
*/
package com.fankes.miui.notify.utils.tool
import android.content.Context
import com.fankes.miui.notify.utils.factory.openBrowser
import com.fankes.miui.notify.utils.factory.showDialog
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.hook.factory.modulePrefs
import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
/**
* [YukiHookAPI] 的自动推广工具类
*/
object YukiPromoteTool {
/** 推广已读存储键值 */
private val YUKI_PROMOTE_READED = PrefsData("yuki_promote_readed", false)
/**
* 显示推广对话框
* @param context 实例
*/
fun promote(context: Context) {
fun saveReaded() = context.modulePrefs.put(YUKI_PROMOTE_READED, value = true)
if (context.modulePrefs.get(YUKI_PROMOTE_READED).not())
context.showDialog {
title = "面向开发者的推广"
msg = "你想快速拥有一个自己的 Xposed 模块吗,你只需要拥有基础的 Android 开发经验以及使用 Kotlin 编程语言即可。\n\n" +
"快来体验 YukiHookAPI这是一个使用 Kotlin 重新构建的高效 Xposed Hook API助你的开发变得更轻松。"
confirmButton(text = "去看看") {
context.openBrowser(url = "https://github.com/fankes/YukiHookAPI")
saveReaded()
}
cancelButton(text = "我不是开发者") { saveReaded() }
noCancelable()
}
}
}

View File

@@ -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()
)
}
}

View File

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

View File

@@ -0,0 +1,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>

View 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>

View 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>

View 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>

View 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>

View File

@@ -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,19 +24,74 @@
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="返回" />
<TextView
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="2.5dp"
android:layout_weight="1"
android:singleLine="true"
android:text="通知图标优化名单"
android:textColor="@color/colorTextGray"
android:textSize="25sp"
android:textStyle="bold" />
android:gravity="center|start"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:singleLine="true"
android:text="通知图标优化名单"
android:textColor="@color/colorTextGray"
android:textSize="19sp"
android:textStyle="bold" />
<TextView
android:id="@+id/config_title_count_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:text="适配列表正在等待装载"
android:textColor="@color/colorTextDark"
android:textSize="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
@@ -45,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"
@@ -56,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
@@ -64,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"
@@ -90,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"

View File

@@ -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,41 +316,198 @@
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:paddingTop="15dp">
<com.fankes.miui.notify.view.MaterialSwitch
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
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"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:text="启用通知图标优化"
android:textColor="@color/colorTextGray"
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="13dp"
android:layout_marginRight="13dp"
android:layout_marginBottom="10dp"
android:background="@drawable/button_round"
android:background="@drawable/bg_button_round"
android:gravity="center"
android:padding="10dp"
android:singleLine="true"
@@ -259,14 +518,246 @@
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
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="15dp"
android:layout_marginRight="15dp"
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_custom_corner_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginBottom="5dp"
android:gravity="center|start"
android:text="调整通知栏中的图标边框圆角大小"
android:textAllCaps="false"
android:textColor="@color/colorTextGray"
android:textSize="15sp" />
<androidx.appcompat.widget.AppCompatSeekBar
android:id="@+id/notify_icon_custom_corner_seekbar"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginTop="5dp"
android:max="15"
android:min="0"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:progress="15" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:gravity="center"
android:orientation="horizontal"
android:paddingTop="5dp"
android:paddingBottom="15dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:alpha="0.75"
android:ellipsize="end"
android:gravity="center"
android:maxWidth="100dp"
android:singleLine="true"
android:text="当前"
android:textColor="@color/colorTextGray"
android:textSize="13.5sp" />
<TextView
android:id="@+id/notify_icon_custom_corner_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:gravity="center"
android:maxWidth="100dp"
android:singleLine="true"
android:text="15 dp"
android:textColor="@color/colorTextGray"
android:textSize="15sp"
android:textStyle="bold" />
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:alpha="0.6"
android:lineSpacingExtra="6dp"
android:text="你可以拖拽滑动条来调整通知栏中图标的边框圆角大小,仅支持 Android 12 风格以及 MIUI 经典样式的通知图标。"
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/notify_icon_force_app_icon_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:orientation="vertical">
<com.fankes.miui.notify.ui.view.MaterialSwitch
android:id="@+id/notify_icon_force_app_icon_switch"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_marginBottom="5dp"
android:text="通知栏中的图标强制为 APP 图标"
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="此选项默认关闭,开启后下拉通知栏中的通知图标将会被替换为 APP 自身图标,但是不会更改状态栏中的通知图标,这是一个破坏原生通知图标的行为,仅针对部分有需要的用户而添加,我们不推荐开启这个功能,请根据个人偏好进行选择是否需要开启。"
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/notify_icon_fix_notify_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
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="15dp"
android:layout_marginRight="15dp"
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 +766,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 +809,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 +830,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="使用帮助&amp;说明"
android:textColor="@color/colorTextGray"
android:textSize="12sp" />
</LinearLayout>
@@ -342,8 +864,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 +874,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.模块仅支持 LSPosedEdXposed 也可以使用但随时停止支持,由于模块涉及到修改系统应用,不支持其它 Hook 框架,在 LSPosed 的作用域中,只需勾选“系统界面”(旧版本为“系统 UI”)即可,应用设置后需要重启系统界面。"
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
@@ -362,8 +884,8 @@
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:alpha="0.8"
android:lineSpacingExtra="6dp"
android:text="Q.哪些是已知问题?\nA.MIUI 自己的系统应用的通知图标仍然可能出现黑白块的情况,可使用通知图标优化暂时修复其图标问题,后期只能等官方修复(基本上没什么可能性)。动态小图标可能会在高版本系统中闪烁,这是 MIUI 的问题,后期仍在想解决办法。"
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 +893,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 +906,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 +935,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 +948,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>

View File

@@ -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,11 +77,11 @@
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"
android:text="全替换 "
android:text="全替换 "
android:textColor="@color/colorTextGray"
android:textSize="13sp" />
</LinearLayout>

View 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>

View 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>

View 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>

View 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>

View File

Before

Width:  |  Height:  |  Size: 201 KiB

After

Width:  |  Height:  |  Size: 201 KiB

View File

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

View File

@@ -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>

View 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>

View File

@@ -1,3 +1,4 @@
<resources>
<string name="app_name">MIUI 原生通知图标</string>
<string name="tile_name">通知图标</string>
</resources>

Some files were not shown because too many files have changed in this diff Show More