mirror of
https://github.com/fankes/MIUINativeNotifyIcon.git
synced 2025-09-06 02:35:32 +08:00
Compare commits
45 Commits
Author | SHA1 | Date | |
---|---|---|---|
e6cff940a7 | |||
3f7ea97812 | |||
8f8810e92a | |||
e65624c044 | |||
eabac2bd2d | |||
bde952c72c | |||
|
3e362591b6 | ||
|
ea29c089f6 | ||
cff1eb1958 | |||
83c98b2ad3 | |||
0d7f323232 | |||
0d63b0a14d | |||
6684d7f376 | |||
89321af1ce | |||
d7a9f1e413 | |||
edf199d9a6 | |||
8d6a05e02c | |||
c7d9b2661b | |||
d0a32e08d9 | |||
b0f9e44f8a | |||
1e749d2f64 | |||
c886bbd6cf | |||
ec45839029 | |||
6fd2294529 | |||
|
5913da8183 | ||
|
fcf2889668 | ||
|
6d784f1283 | ||
cd8ceec765 | |||
5325ac37d6 | |||
07fa6965ad | |||
4c88a5fbc6 | |||
da61a52c13 | |||
3314f9fb57 | |||
ebb1bec36f | |||
|
d5d2e2107c | ||
|
c39d03f8c9 | ||
|
e20dfab5b1 | ||
|
ffc9be3721 | ||
|
126aedabfd | ||
56661b03e6 | |||
|
c45658be68 | ||
e0443ff97c | |||
9af735e252 | |||
c67fe2fa31 | |||
b03cf30e0a |
4
.github/ISSUE_TEMPLATE/----bug---.md
vendored
4
.github/ISSUE_TEMPLATE/----bug---.md
vendored
@@ -25,7 +25,7 @@ assignees: fankes
|
|||||||
|
|
||||||
**使用的 Xposed 框架名称与框架版本(必填)**
|
**使用的 Xposed 框架名称与框架版本(必填)**
|
||||||
|
|
||||||
*
|
* (例如:LSPosed Zygisk/Riru 版本号)
|
||||||
|
|
||||||
**同时使用的带有系统界面作用域的 Xposed 模块(选填)**
|
**同时使用的带有系统界面作用域的 Xposed 模块(选填)**
|
||||||
|
|
||||||
@@ -46,6 +46,8 @@ assignees: fankes
|
|||||||
|
|
||||||
</code></pre></details>
|
</code></pre></details>
|
||||||
|
|
||||||
|
<!--- 注意:只接受 MIUI 正规官方版本系统,如果你正在使用 MIUI 官改(第三方改版)请不要提交任何 BUG 与问题,开发者无义务解决 --->
|
||||||
|
|
||||||
<!--- 提交时请将括号内容包括括号全部删除,填入你自己的内容 --->
|
<!--- 提交时请将括号内容包括括号全部删除,填入你自己的内容 --->
|
||||||
<!--- 请保留模板原始标题 --->
|
<!--- 请保留模板原始标题 --->
|
||||||
<!--- 不按规定提交的 issues 将直接被关闭 --->
|
<!--- 不按规定提交的 issues 将直接被关闭 --->
|
||||||
|
8
.idea/misc.xml
generated
8
.idea/misc.xml
generated
@@ -6,13 +6,19 @@
|
|||||||
<entry key="app/src/main/res/drawable-night/dark_round.xml" value="0.256" />
|
<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-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-v24/ic_launcher_foreground.xml" value="0.44871794871794873" />
|
||||||
|
<entry key="app/src/main/res/drawable/bg_green_round.xml" value="0.255" />
|
||||||
|
<entry key="app/src/main/res/drawable/bg_yellow_round.xml" value="0.255" />
|
||||||
<entry key="app/src/main/res/drawable/permotion_round.xml" value="0.256" />
|
<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/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/activity_config.xml" value="0.42168674698795183" />
|
<entry key="app/src/main/res/layout/activity_config.xml" value="0.42168674698795183" />
|
||||||
<entry key="app/src/main/res/layout/activity_login.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.36160137752905724" />
|
<entry key="app/src/main/res/layout/activity_main.xml" value="0.36160137752905724" />
|
||||||
<entry key="app/src/main/res/layout/adapter_config.xml" value="0.4375" />
|
<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_icon_search.xml" value="0.4307692307692308" />
|
||||||
|
<entry key="app/src/main/res/layout/dia_source_from_string.xml" value="0.4307692307692308" />
|
||||||
<entry key="app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml" value="0.44871794871794873" />
|
<entry key="app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml" value="0.44871794871794873" />
|
||||||
</map>
|
</map>
|
||||||
</option>
|
</option>
|
||||||
|
@@ -1,44 +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
|
|
||||||
iconColor = 0, // 通知栏中显示的图标颜色 - 设置为 0 使用系统默认颜色 (不设置颜色可不写)
|
|
||||||
contributorName = "" // 贡献者昵称
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
- 图标大小建议保持在 50x50
|
|
||||||
- 提交时请将后方的注释删除,否则不予合并代码
|
|
||||||
|
|
||||||
## 其它要求
|
|
||||||
|
|
||||||
- 1.调试性质或大批量注释代码,禁止提交
|
|
||||||
- 2.类名和方法名仅能由开发者进行修改和提交,禁止随意修改项目名称、方法名称以及类名
|
|
||||||
- 3.禁止随意更新项目依赖以及增加新的依赖,有问题请提前提交到 issues 进行说明
|
|
||||||
- 4.禁止更新项目版本号,版本号交由开发者合并代码并发布 release 版本
|
|
||||||
- 5.代码语言要求,请统一使用 Kotlin,除特殊情况外,不接受其他语言的提交
|
|
||||||
- 6.以上
|
|
12
README.md
12
README.md
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/app/src/main/ic_launcher-playstore.png" width = "100" height = "100"/>
|
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/app/src/main/ic_launcher-playstore.png" width = "100" height = "100"/>
|
||||||
<br/>
|
<br/>
|
||||||
@@ -12,11 +12,12 @@ Fix the native notification bar icon function abandoned by the MIUI development
|
|||||||
# 开始使用
|
# 开始使用
|
||||||
|
|
||||||
点击下载最新版本
|
点击下载最新版本
|
||||||
<a href='https://github.com/fankes/MIUINativeNotifyIcon/releases'></a>
|
<a href='https://github.com/fankes/MIUINativeNotifyIcon/releases'></a>
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
⚠️ 适配说明<br/>
|
⚠️ 适配说明<br/>
|
||||||
|
|
||||||
- 此模块仅支持 LSPosed(作用域“系统界面”)、~~EdXposed(随时停止支持)~~、不支持太极无极
|
- 此模块仅支持 LSPosed(作用域“系统界面”)、~~EdXposed(随时停止支持)~~、不支持太极无极
|
||||||
|
- 请确保你使用的是 MIUI 官方版本,任何第三方官改包发生的问题,开发者没有义务去解决和修复,请自求多福
|
||||||
- 目前最低支持基于 Android 9 版本的 MIUI 12 或 MIUI 12.5(最低建议)
|
- 目前最低支持基于 Android 9 版本的 MIUI 12 或 MIUI 12.5(最低建议)
|
||||||
- 建议最低从 MIUI 12.5 `2021-5-18` 开发版以后开始使用模块,之前的版本可能或多或少存在 MIUI 自身 BUG 不生效、黑白块的问题
|
- 建议最低从 MIUI 12.5 `2021-5-18` 开发版以后开始使用模块,之前的版本可能或多或少存在 MIUI 自身 BUG 不生效、黑白块的问题
|
||||||
- 请始终保持最新版本的 LSPosed,旧版本可能会出现 Hook 不生效的问题
|
- 请始终保持最新版本的 LSPosed,旧版本可能会出现 Hook 不生效的问题
|
||||||
@@ -28,12 +29,11 @@ Fix the native notification bar icon function abandoned by the MIUI development
|
|||||||
[Release](https://github.com/fankes/MIUINativeNotifyIcon/releases)
|
[Release](https://github.com/fankes/MIUINativeNotifyIcon/releases)
|
||||||
及[蓝奏云](https://fankes.lanzouy.com/b030o2e8h),从其他非正规渠道下载到的版本或对您造成任何影响均与我们无关。
|
及[蓝奏云](https://fankes.lanzouy.com/b030o2e8h),从其他非正规渠道下载到的版本或对您造成任何影响均与我们无关。
|
||||||
|
|
||||||
# 开始贡献
|
# 贡献通知图标优化名单
|
||||||
|
|
||||||
由于国内厂商 APP 的不规范彩色图标影响整体图标的美观,现在开放第三方 APP 的通知图标适配。<br/>
|
此项目是 `AndroidNotifyIconAdapt` 项目的一部分,详情请参考下方。<br/>
|
||||||
欢迎为通知图标优化名单贡献宝贵资源!<br/>
|
|
||||||
|
|
||||||
- [CONTRIBUTING](https://github.com/fankes/MIUINativeNotifyIcon/blob/master/CONTRIBUTING.md)
|
- [Android 通知图标规范适配计划](https://github.com/fankes/AndroidNotifyIconAdapt)
|
||||||
|
|
||||||
# 历史背景
|
# 历史背景
|
||||||
|
|
||||||
|
@@ -68,10 +68,11 @@ dependencies {
|
|||||||
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1'
|
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1'
|
||||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
|
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
|
||||||
compileOnly 'de.robv.android.xposed:api:82'
|
compileOnly 'de.robv.android.xposed:api:82'
|
||||||
implementation 'com.highcapable.yukihookapi:api:1.0.2'
|
implementation 'com.highcapable.yukihookapi:api:1.0.3'
|
||||||
ksp 'com.highcapable.yukihookapi:ksp-xposed:1.0.2'
|
ksp 'com.highcapable.yukihookapi:ksp-xposed:1.0.3'
|
||||||
implementation 'com.geyifeng.immersionbar:immersionbar:3.2.0'
|
implementation 'com.geyifeng.immersionbar:immersionbar:3.2.0'
|
||||||
implementation 'com.geyifeng.immersionbar:immersionbar-ktx:3.2.0'
|
implementation 'com.geyifeng.immersionbar:immersionbar-ktx:3.2.0'
|
||||||
|
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
|
||||||
implementation 'androidx.core:core-ktx:1.7.0'
|
implementation 'androidx.core:core-ktx:1.7.0'
|
||||||
implementation 'androidx.appcompat:appcompat:1.4.1'
|
implementation 'androidx.appcompat:appcompat:1.4.1'
|
||||||
implementation 'com.google.android.material:material:1.5.0'
|
implementation 'com.google.android.material:material:1.5.0'
|
||||||
|
@@ -3,6 +3,8 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
package="com.fankes.miui.notify">
|
package="com.fankes.miui.notify">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".application.MNNApplication"
|
android:name=".application.MNNApplication"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
@@ -18,7 +20,7 @@
|
|||||||
android:value="true" />
|
android:value="true" />
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="xposeddescription"
|
android:name="xposeddescription"
|
||||||
android:value="MIUI 状态栏原生图标,修复 12.5、13 后期被破坏的彩色图标。\n开发者:酷安 @星夜不荟" />
|
android:value="为金凡教我做事的 MIUI 修复 12.5、13 后期被破坏的彩色图标。\n开发者:酷安 @星夜不荟" />
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="xposedminversion"
|
android:name="xposedminversion"
|
||||||
android:value="93" />
|
android:value="93" />
|
||||||
|
@@ -28,7 +28,7 @@ import java.io.Serializable
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 通知栏小图标 bean
|
* 通知栏小图标 bean
|
||||||
* @param appName APP 名称 - 仅限默认语言区域
|
* @param appName APP 名称
|
||||||
* @param packageName 包名
|
* @param packageName 包名
|
||||||
* @param iconBitmap 图标位图
|
* @param iconBitmap 图标位图
|
||||||
* @param iconColor 通知栏中显示的图标颜色 - 设置为 0 使用系统默认颜色
|
* @param iconColor 通知栏中显示的图标颜色 - 设置为 0 使用系统默认颜色
|
||||||
@@ -47,4 +47,13 @@ data class IconDataBean(
|
|||||||
) : Serializable {
|
) : Serializable {
|
||||||
fun toEnabledName() = ("$appName$packageName").base64 + "_enable"
|
fun toEnabledName() = ("$appName$packageName").base64 + "_enable"
|
||||||
fun toEnabledAllName() = ("$appName$packageName").base64 + "_enable_all"
|
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" +
|
||||||
|
" }"
|
||||||
}
|
}
|
@@ -32,6 +32,14 @@ object HookConst {
|
|||||||
const val ENABLE_COLOR_ICON_HOOK = "_color_icon_hook"
|
const val ENABLE_COLOR_ICON_HOOK = "_color_icon_hook"
|
||||||
const val ENABLE_COLOR_ICON_COMPAT = "_color_icon_compat"
|
const val ENABLE_COLOR_ICON_COMPAT = "_color_icon_compat"
|
||||||
const val ENABLE_NOTIFY_ICON_FIX = "_notify_icon_fix"
|
const val ENABLE_NOTIFY_ICON_FIX = "_notify_icon_fix"
|
||||||
|
const val NOTIFY_ICON_DATAS = "_notify_icon_datas"
|
||||||
|
|
||||||
|
const val SOURCE_SYNC_WAY = "_source_sync_way"
|
||||||
|
const val SOURCE_SYNC_WAY_CUSTOM_URL = "_source_sync_way_custom_url"
|
||||||
|
|
||||||
|
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"
|
const val SYSTEMUI_PACKAGE_NAME = "com.android.systemui"
|
||||||
}
|
}
|
@@ -22,6 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.fankes.miui.notify.hook
|
package com.fankes.miui.notify.hook
|
||||||
|
|
||||||
|
import android.app.NotificationManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
@@ -34,6 +35,7 @@ import android.view.View
|
|||||||
import android.view.ViewOutlineProvider
|
import android.view.ViewOutlineProvider
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import androidx.core.graphics.drawable.toBitmap
|
import androidx.core.graphics.drawable.toBitmap
|
||||||
|
import com.fankes.miui.notify.bean.IconDataBean
|
||||||
import com.fankes.miui.notify.hook.HookConst.ENABLE_COLOR_ICON_COMPAT
|
import com.fankes.miui.notify.hook.HookConst.ENABLE_COLOR_ICON_COMPAT
|
||||||
import com.fankes.miui.notify.hook.HookConst.ENABLE_COLOR_ICON_HOOK
|
import com.fankes.miui.notify.hook.HookConst.ENABLE_COLOR_ICON_HOOK
|
||||||
import com.fankes.miui.notify.hook.HookConst.ENABLE_MODULE
|
import com.fankes.miui.notify.hook.HookConst.ENABLE_MODULE
|
||||||
@@ -54,6 +56,7 @@ import com.highcapable.yukihookapi.hook.param.PackageParam
|
|||||||
import com.highcapable.yukihookapi.hook.type.android.ContextClass
|
import com.highcapable.yukihookapi.hook.type.android.ContextClass
|
||||||
import com.highcapable.yukihookapi.hook.type.android.DrawableClass
|
import com.highcapable.yukihookapi.hook.type.android.DrawableClass
|
||||||
import com.highcapable.yukihookapi.hook.type.android.ImageViewClass
|
import com.highcapable.yukihookapi.hook.type.android.ImageViewClass
|
||||||
|
import com.highcapable.yukihookapi.hook.type.java.BooleanType
|
||||||
import com.highcapable.yukihookapi.hook.type.java.IntType
|
import com.highcapable.yukihookapi.hook.type.java.IntType
|
||||||
import com.highcapable.yukihookapi.hook.xposed.proxy.YukiHookXposedInitProxy
|
import com.highcapable.yukihookapi.hook.xposed.proxy.YukiHookXposedInitProxy
|
||||||
|
|
||||||
@@ -69,20 +72,27 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
private const val NotificationHeaderViewWrapperInjectorClass =
|
private const val NotificationHeaderViewWrapperInjectorClass =
|
||||||
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.row.wrapper.NotificationHeaderViewWrapperInjector"
|
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.row.wrapper.NotificationHeaderViewWrapperInjector"
|
||||||
|
|
||||||
/** MIUI 新版本存在的类 */
|
|
||||||
private const val NotificationHeaderViewWrapperClass =
|
|
||||||
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.NotificationHeaderViewWrapper"
|
|
||||||
|
|
||||||
/** MIUI 新版本存在的类 */
|
|
||||||
private const val NotificationViewWrapperClass =
|
|
||||||
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.NotificationViewWrapper"
|
|
||||||
|
|
||||||
/** 未确定是否只有旧版本存在的类 */
|
|
||||||
private const val ExpandableNotificationRowClass = "$SYSTEMUI_PACKAGE_NAME.statusbar.ExpandableNotificationRow"
|
|
||||||
|
|
||||||
/** 原生存在的类 */
|
/** 原生存在的类 */
|
||||||
private const val ContrastColorUtilClass = "com.android.internal.util.ContrastColorUtil"
|
private const val ContrastColorUtilClass = "com.android.internal.util.ContrastColorUtil"
|
||||||
|
|
||||||
|
/** 根据多个版本存在不同的包名相同的类 */
|
||||||
|
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(
|
private val NotificationUtilClass = VariousClass(
|
||||||
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.NotificationUtil",
|
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.NotificationUtil",
|
||||||
@@ -96,6 +106,9 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 缓存的通知优化图标数组 */
|
||||||
|
private var iconDatas = ArrayList<IconDataBean>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* - 这个是修复彩色图标的关键核心代码判断
|
* - 这个是修复彩色图标的关键核心代码判断
|
||||||
*
|
*
|
||||||
@@ -128,8 +141,21 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
NotificationUtilClass.clazz.hasMethod(name = "ignoreStatusBarIconColor", ExpandedNotificationClass.clazz)
|
NotificationUtilClass.clazz.hasMethod(name = "ignoreStatusBarIconColor", ExpandedNotificationClass.clazz)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否为旧版本 MIUI 方案
|
||||||
|
*
|
||||||
|
* 拥有 “handleHeaderViews” 方法
|
||||||
|
* @return [Boolean]
|
||||||
|
*/
|
||||||
|
private val PackageParam.hasHandleHeaderViews
|
||||||
|
get() = safeOfFalse {
|
||||||
|
NotificationHeaderViewWrapperClass.clazz.hasMethod(name = "handleHeaderViews")
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前通知栏的样式
|
* 获取当前通知栏的样式
|
||||||
|
*
|
||||||
|
* - ❗新版本可能不存在这个方法
|
||||||
* @return [Boolean]
|
* @return [Boolean]
|
||||||
*/
|
*/
|
||||||
private val PackageParam.isShowMiuiStyle
|
private val PackageParam.isShowMiuiStyle
|
||||||
@@ -137,15 +163,6 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
NotificationUtilClass.clazz.method { name = "showMiuiStyle" }.get().invoke() ?: false
|
NotificationUtilClass.clazz.method { name = "showMiuiStyle" }.get().invoke() ?: false
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取 [ExpandedNotificationClass] 的应用名称
|
|
||||||
* @param instance 通知实例
|
|
||||||
* @return [String]
|
|
||||||
*/
|
|
||||||
private fun PackageParam.findAppName(instance: Any?) = safeOf(default = "<unknown>") {
|
|
||||||
ExpandedNotificationClass.clazz.method { name = "getAppName" }.get(instance).invoke() ?: "<empty>"
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 适配通知栏、状态栏图标
|
* 适配通知栏、状态栏图标
|
||||||
*
|
*
|
||||||
@@ -159,10 +176,51 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
private fun StatusBarNotification.compatNotifyIcon(context: Context, iconDrawable: Drawable) = safeOf(iconDrawable) {
|
private fun StatusBarNotification.compatNotifyIcon(context: Context, iconDrawable: Drawable) = safeOf(iconDrawable) {
|
||||||
/** 给 MIPUSH 设置 APP 自己的图标 */
|
/** 给 MIPUSH 设置 APP 自己的图标 */
|
||||||
if (isXmsf && opPkgName.isNotBlank())
|
if (isXmsf && opPkgName.isNotBlank())
|
||||||
context.packageManager.getPackageInfo(opPkgName, 0).applicationInfo.loadIcon(context.packageManager)
|
findAppIcon(context)
|
||||||
else iconDrawable
|
else iconDrawable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取推送通知的应用名称
|
||||||
|
* @param context 实例
|
||||||
|
* @return [String]
|
||||||
|
*/
|
||||||
|
private fun StatusBarNotification.findAppName(context: Context) = safeOf(default = "<unknown>") {
|
||||||
|
context.packageManager.getPackageInfo(opPkgName, 0).applicationInfo.loadLabel(context.packageManager)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取通知栏、状态栏 APP 图标
|
||||||
|
* @param context 实例
|
||||||
|
* @return [Drawable] 适配的图标
|
||||||
|
*/
|
||||||
|
private fun StatusBarNotification.findAppIcon(context: Context) = safeOf(notification.smallIcon.loadDrawable(context)) {
|
||||||
|
context.packageManager.getPackageInfo(opPkgName, 0).applicationInfo.loadIcon(context.packageManager)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打印日志
|
||||||
|
* @param tag 标识
|
||||||
|
* @param context 实例
|
||||||
|
* @param expandedNf 通知实例
|
||||||
|
* @param isCustom 是否为通知优化生效图标
|
||||||
|
* @param isGrayscale 是否为灰度图标
|
||||||
|
*/
|
||||||
|
private fun PackageParam.printLogcat(
|
||||||
|
tag: String,
|
||||||
|
context: Context,
|
||||||
|
expandedNf: StatusBarNotification?,
|
||||||
|
isCustom: Boolean,
|
||||||
|
isGrayscale: Boolean
|
||||||
|
) {
|
||||||
|
if (prefs.getBoolean(ENABLE_MODULE_LOG)) loggerD(
|
||||||
|
msg = "$tag --> [${expandedNf?.findAppName(context)}][${expandedNf?.opPkgName}] " +
|
||||||
|
"custom [$isCustom] " +
|
||||||
|
"grayscale [$isGrayscale] " +
|
||||||
|
"xmsf [${expandedNf?.isXmsf}]"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取推送通知的包名
|
* 获取推送通知的包名
|
||||||
*
|
*
|
||||||
@@ -203,11 +261,31 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
*/
|
*/
|
||||||
private val PackageParam.globalContext
|
private val PackageParam.globalContext
|
||||||
get() = safeOfNull {
|
get() = safeOfNull {
|
||||||
if (SystemUIApplicationClass.clazz.hasMethod(name = "getContext"))
|
SystemUIApplicationClass.clazz.method { name = "getContext" }.ignoredError().get().invoke<Context>()
|
||||||
SystemUIApplicationClass.clazz.method { name = "getContext" }.get().invoke<Context>()
|
|
||||||
else null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动适配状态栏、通知栏自定义小图标
|
||||||
|
* @param isGrayscaleIcon 是否为灰度图标
|
||||||
|
* @param packageName APP 包名
|
||||||
|
* @return [Pair] - ([Bitmap] 位图,[Int] 颜色)
|
||||||
|
*/
|
||||||
|
private fun PackageParam.compatCustomIcon(isGrayscaleIcon: Boolean, packageName: String): Pair<Bitmap?, Int> {
|
||||||
|
var customPair: Pair<Bitmap?, Int>? = null
|
||||||
|
if (prefs.getBoolean(ENABLE_NOTIFY_ICON_FIX, default = true))
|
||||||
|
run {
|
||||||
|
if (iconDatas.isNotEmpty())
|
||||||
|
iconDatas.forEach {
|
||||||
|
if (packageName == it.packageName && isAppNotifyHookOf(it)) {
|
||||||
|
if (!isGrayscaleIcon || isAppNotifyHookAllOf(it))
|
||||||
|
customPair = Pair(it.iconBitmap, it.iconColor)
|
||||||
|
return@run
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return customPair ?: Pair(null, 0)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook 状态栏小图标
|
* Hook 状态栏小图标
|
||||||
*
|
*
|
||||||
@@ -228,32 +306,23 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
if (!prefs.getBoolean(ENABLE_COLOR_ICON_HOOK, default = true)) return@safeRun
|
if (!prefs.getBoolean(ENABLE_COLOR_ICON_HOOK, default = true)) return@safeRun
|
||||||
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
|
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
|
||||||
expandedNf?.also { notifyInstance ->
|
expandedNf?.also { notifyInstance ->
|
||||||
|
/** 判断是 MIUI 样式就停止 Hook */
|
||||||
|
if (context.isMiuiNotifyStyle) {
|
||||||
|
it(notifyInstance.findAppIcon(context).toBitmap())
|
||||||
|
return@safeRun
|
||||||
|
}
|
||||||
/** 判断是否不是灰度图标 */
|
/** 判断是否不是灰度图标 */
|
||||||
val isNotGrayscaleIcon = notifyInstance.isXmsf || !isGrayscaleIcon(context, iconDrawable)
|
val isNotGrayscaleIcon = notifyInstance.isXmsf || !isGrayscaleIcon(context, iconDrawable)
|
||||||
|
|
||||||
/** 目标彩色通知 APP 图标 */
|
/** 目标彩色通知 APP 图标 */
|
||||||
var customIcon: Bitmap? = null
|
val customIcon = compatCustomIcon(!isNotGrayscaleIcon, notifyInstance.opPkgName).first
|
||||||
if (prefs.getBoolean(ENABLE_NOTIFY_ICON_FIX, default = true))
|
|
||||||
run {
|
|
||||||
IconPackParams.iconDatas.forEach {
|
|
||||||
if ((notifyInstance.opPkgName == it.packageName ||
|
|
||||||
findAppName(notifyInstance) == it.appName) &&
|
|
||||||
isAppNotifyHookOf(it)
|
|
||||||
) {
|
|
||||||
if (isNotGrayscaleIcon || isAppNotifyHookAllOf(it))
|
|
||||||
customIcon = it.iconBitmap
|
|
||||||
return@run
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/** 打印日志 */
|
/** 打印日志 */
|
||||||
if (prefs.getBoolean(ENABLE_MODULE_LOG))
|
printLogcat(tag = "StatusIcon", context, notifyInstance, isCustom = customIcon != null, !isNotGrayscaleIcon)
|
||||||
loggerD(msg = "Icon --> [${findAppName(notifyInstance)}][${notifyInstance.opPkgName}] custom [${customIcon != null}] grayscale [${!isNotGrayscaleIcon}] xmsf [${notifyInstance.isXmsf}]")
|
|
||||||
when {
|
when {
|
||||||
/** 处理自定义通知图标优化 */
|
/** 处理自定义通知图标优化 */
|
||||||
customIcon != null -> it(customIcon!!)
|
customIcon != null -> it(customIcon)
|
||||||
/** 若不是灰度图标自动处理为圆角 */
|
/** 若不是灰度图标自动处理为圆角 */
|
||||||
isNotGrayscaleIcon -> it(notifyInstance.compatNotifyIcon(context, iconDrawable).toBitmap().round(15.dp(context)))
|
isNotGrayscaleIcon -> it(notifyInstance.compatNotifyIcon(context, iconDrawable).toBitmap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -265,106 +334,102 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
* @param context 实例
|
* @param context 实例
|
||||||
* @param expandedNf 通知实例
|
* @param expandedNf 通知实例
|
||||||
* @param iconImageView 通知图标实例
|
* @param iconImageView 通知图标实例
|
||||||
|
* @param isExpanded 通知是否展开 - 可做最小化通知处理
|
||||||
*/
|
*/
|
||||||
private fun PackageParam.hookNotifyIconOnSet(context: Context, expandedNf: StatusBarNotification?, iconImageView: ImageView) =
|
private fun PackageParam.hookNotifyIconOnSet(
|
||||||
safeRun(msg = "AutoSetAppIconOnSet") {
|
context: Context,
|
||||||
/** 如果没开启修复 APP 的彩色图标 */
|
expandedNf: StatusBarNotification?,
|
||||||
if (!prefs.getBoolean(ENABLE_COLOR_ICON_HOOK, default = true)) return@safeRun
|
iconImageView: ImageView,
|
||||||
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
|
isExpanded: Boolean
|
||||||
expandedNf?.let { notifyInstance ->
|
) = safeRun(msg = "AutoSetAppIconOnSet") {
|
||||||
/** 是否开启修复 APP 的彩色图标 */
|
/** 判断是 MIUI 样式就停止 Hook */
|
||||||
val isNotifyIconFix = prefs.getBoolean(ENABLE_NOTIFY_ICON_FIX, default = true)
|
if (context.isMiuiNotifyStyle) return@safeRun
|
||||||
|
/** 如果没开启修复 APP 的彩色图标 */
|
||||||
|
if (!prefs.getBoolean(ENABLE_COLOR_ICON_HOOK, default = true)) return@safeRun
|
||||||
|
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
|
||||||
|
expandedNf?.let { notifyInstance ->
|
||||||
|
|
||||||
/** 新版风格反色 */
|
/** 新版风格反色 */
|
||||||
val newStyle = if (context.isSystemInDarkMode) 0xFF2D2D2D.toInt() else Color.WHITE
|
val newStyle = if (context.isSystemInDarkMode) 0xFF2D2D2D.toInt() else Color.WHITE
|
||||||
|
|
||||||
/** 旧版风格反色 */
|
/** 旧版风格反色 */
|
||||||
val oldStyle = if (context.isNotSystemInDarkMode) 0xFF707070.toInt() else Color.WHITE
|
val oldStyle = if (context.isNotSystemInDarkMode) 0xFF707070.toInt() else Color.WHITE
|
||||||
|
|
||||||
/** 通知图标原始颜色 */
|
/** 通知图标原始颜色 */
|
||||||
val iconColor = notifyInstance.notification.color
|
val iconColor = notifyInstance.notification.color
|
||||||
|
|
||||||
/** 是否有通知栏图标颜色 */
|
/** 是否有通知栏图标颜色 */
|
||||||
val hasIconColor = iconColor != 0
|
val hasIconColor = iconColor != 0
|
||||||
|
|
||||||
/** 通知图标适配颜色 */
|
/** 通知图标适配颜色 */
|
||||||
val supportColor = iconColor.let {
|
val supportColor = iconColor.let {
|
||||||
when {
|
when {
|
||||||
isUpperOfAndroidS -> newStyle
|
isUpperOfAndroidS -> newStyle
|
||||||
it == 0 -> oldStyle
|
it == 0 || !isExpanded -> oldStyle
|
||||||
else -> it
|
else -> it
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** 获取通知小图标 */
|
/** 获取通知小图标 */
|
||||||
val iconDrawable = notifyInstance.notification.smallIcon.loadDrawable(context)
|
val iconDrawable = notifyInstance.notification.smallIcon.loadDrawable(context)
|
||||||
|
|
||||||
/** 判断图标风格 */
|
/** 判断图标风格 */
|
||||||
val isGrayscaleIcon = !notifyInstance.isXmsf && isGrayscaleIcon(context, iconDrawable)
|
val isGrayscaleIcon = !notifyInstance.isXmsf && isGrayscaleIcon(context, iconDrawable)
|
||||||
|
|
||||||
/** 自定义默认小图标 */
|
/** 自定义默认小图标 */
|
||||||
var customIcon: Bitmap? = null
|
var customIcon: Bitmap?
|
||||||
|
|
||||||
/** 自定义默认小图标颜色 */
|
/** 自定义默认小图标颜色 */
|
||||||
var customIconColor = 0
|
var customIconColor: Int
|
||||||
|
compatCustomIcon(isGrayscaleIcon, notifyInstance.opPkgName).also {
|
||||||
if (isNotifyIconFix) run {
|
customIcon = it.first
|
||||||
IconPackParams.iconDatas.forEach {
|
customIconColor = if (isUpperOfAndroidS || isExpanded) it.second else 0
|
||||||
if ((notifyInstance.opPkgName == it.packageName ||
|
}
|
||||||
findAppName(notifyInstance) == it.appName) &&
|
/** 打印日志 */
|
||||||
isAppNotifyHookOf(it)
|
printLogcat(tag = "NotifyIcon", context, notifyInstance, isCustom = customIcon != null, isGrayscaleIcon)
|
||||||
) {
|
/** 处理自定义通知图标优化 */
|
||||||
if (!isGrayscaleIcon || isAppNotifyHookAllOf(it)) {
|
if (customIcon != null)
|
||||||
customIcon = it.iconBitmap
|
iconImageView.apply {
|
||||||
customIconColor = it.iconColor
|
/** 设置自定义小图标 */
|
||||||
return@run
|
setImageBitmap(customIcon)
|
||||||
}
|
/** 上色 */
|
||||||
|
setColorFilter(if (isUpperOfAndroidS || customIconColor == 0) supportColor else customIconColor)
|
||||||
|
/** Android 12 设置图标外圈颜色 */
|
||||||
|
if (isUpperOfAndroidS && customIconColor != 0)
|
||||||
|
background = DrawableBuilder().rounded().solidColor(customIconColor).build()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/** 重新设置图标 - 防止系统更改它 */
|
||||||
|
iconImageView.setImageDrawable(iconDrawable)
|
||||||
|
/** 判断如果是灰度图标就给他设置一个白色颜色遮罩 */
|
||||||
|
if (isGrayscaleIcon) iconImageView.apply {
|
||||||
|
/** 设置图标着色 */
|
||||||
|
setColorFilter(supportColor)
|
||||||
|
/** Android 12 设置图标外圈颜色 */
|
||||||
|
if (isUpperOfAndroidS && hasIconColor)
|
||||||
|
background = DrawableBuilder().rounded().solidColor(iconColor).build()
|
||||||
|
} else iconImageView.apply {
|
||||||
|
/** 重新设置图标 */
|
||||||
|
setImageDrawable(notifyInstance.compatNotifyIcon(context, iconDrawable))
|
||||||
|
/** 设置裁切到边界 */
|
||||||
|
clipToOutline = true
|
||||||
|
/** 设置一个圆角轮廓裁切 */
|
||||||
|
outlineProvider = object : ViewOutlineProvider() {
|
||||||
|
override fun getOutline(view: View, out: Outline) {
|
||||||
|
out.setRoundRect(
|
||||||
|
0, 0,
|
||||||
|
view.width, view.height, 5.dp(context)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
/** 清除原生的背景边距设置 */
|
||||||
/** 处理自定义通知图标优化 */
|
if (isUpperOfAndroidS) setPadding(0, 0, 0, 0)
|
||||||
if (customIcon != null)
|
/** 清除原生的主题色背景圆圈颜色 */
|
||||||
iconImageView.apply {
|
if (isUpperOfAndroidS) background = null
|
||||||
/** 设置自定义小图标 */
|
|
||||||
setImageBitmap(customIcon)
|
|
||||||
/** 上色 */
|
|
||||||
setColorFilter(if (isUpperOfAndroidS || customIconColor == 0) supportColor else customIconColor)
|
|
||||||
/** Android 12 设置图标外圈颜色 */
|
|
||||||
if (isUpperOfAndroidS && customIconColor != 0)
|
|
||||||
background = DrawableBuilder().rounded().solidColor(customIconColor).build()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/** 重新设置图标 - 防止系统更改它 */
|
|
||||||
iconImageView.setImageDrawable(iconDrawable)
|
|
||||||
/** 判断如果是灰度图标就给他设置一个白色颜色遮罩 */
|
|
||||||
if (isGrayscaleIcon) iconImageView.apply {
|
|
||||||
/** 设置图标着色 */
|
|
||||||
setColorFilter(supportColor)
|
|
||||||
/** Android 12 设置图标外圈颜色 */
|
|
||||||
if (isUpperOfAndroidS && hasIconColor)
|
|
||||||
background = DrawableBuilder().rounded().solidColor(iconColor).build()
|
|
||||||
} else iconImageView.apply {
|
|
||||||
/** 重新设置图标 */
|
|
||||||
setImageDrawable(notifyInstance.compatNotifyIcon(context, iconDrawable))
|
|
||||||
/** 设置裁切到边界 */
|
|
||||||
clipToOutline = true
|
|
||||||
/** 设置一个圆角轮廓裁切 */
|
|
||||||
outlineProvider = object : ViewOutlineProvider() {
|
|
||||||
override fun getOutline(view: View, out: Outline) {
|
|
||||||
out.setRoundRect(
|
|
||||||
0, 0,
|
|
||||||
view.width, view.height, 5.dp(context)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/** 清除原生的背景边距设置 */
|
|
||||||
if (isUpperOfAndroidS) setPadding(0, 0, 0, 0)
|
|
||||||
/** 清除原生的主题色背景圆圈颜色 */
|
|
||||||
if (isUpperOfAndroidS) background = null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook 通知栏小图标颜色
|
* Hook 通知栏小图标颜色
|
||||||
@@ -375,38 +440,26 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
* @return [Boolean] 是否忽略通知图标颜色
|
* @return [Boolean] 是否忽略通知图标颜色
|
||||||
*/
|
*/
|
||||||
private fun PackageParam.hookIgnoreStatusBarIconColor(context: Context, expandedNf: StatusBarNotification?) =
|
private fun PackageParam.hookIgnoreStatusBarIconColor(context: Context, expandedNf: StatusBarNotification?) =
|
||||||
if (prefs.getBoolean(ENABLE_COLOR_ICON_HOOK, default = true)) safeOfFalse {
|
if (!context.isMiuiNotifyStyle)
|
||||||
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
|
if (prefs.getBoolean(ENABLE_COLOR_ICON_HOOK, default = true)) safeOfFalse {
|
||||||
expandedNf?.let { notifyInstance ->
|
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
|
||||||
/** 获取通知小图标 */
|
expandedNf?.let { notifyInstance ->
|
||||||
val iconDrawable =
|
/** 获取通知小图标 */
|
||||||
notifyInstance.notification.smallIcon.loadDrawable(context)
|
val iconDrawable = notifyInstance.notification.smallIcon.loadDrawable(context)
|
||||||
|
|
||||||
/** 判断是否不是灰度图标 */
|
/** 判断是否不是灰度图标 */
|
||||||
val isNotGrayscaleIcon = notifyInstance.isXmsf || !isGrayscaleIcon(context, iconDrawable)
|
val isNotGrayscaleIcon = notifyInstance.isXmsf || !isGrayscaleIcon(context, iconDrawable)
|
||||||
|
|
||||||
/** 获取目标修复彩色图标的 APP */
|
/** 获取目标修复彩色图标的 APP */
|
||||||
var isTargetFixApp = false
|
val isTargetFixApp = compatCustomIcon(!isNotGrayscaleIcon, notifyInstance.opPkgName).first != null
|
||||||
/** 如果开启了自定义通知图标优化 */
|
/**
|
||||||
if (prefs.getBoolean(ENABLE_NOTIFY_ICON_FIX, default = true))
|
* 只要不是灰度就返回彩色图标
|
||||||
run {
|
* 否则不对颜色进行反色处理防止一些系统图标出现异常
|
||||||
IconPackParams.iconDatas.forEach {
|
*/
|
||||||
if ((notifyInstance.opPkgName == it.packageName ||
|
if (isTargetFixApp) false else isNotGrayscaleIcon
|
||||||
findAppName(notifyInstance) == it.appName) &&
|
} ?: true
|
||||||
isAppNotifyHookOf(it)
|
} else false
|
||||||
) {
|
else true
|
||||||
if (isNotGrayscaleIcon || isAppNotifyHookAllOf(it)) isTargetFixApp = true
|
|
||||||
return@run
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* 只要不是灰度就返回彩色图标
|
|
||||||
* 否则不对颜色进行反色处理防止一些系统图标出现异常
|
|
||||||
*/
|
|
||||||
if (isTargetFixApp) false else isNotGrayscaleIcon
|
|
||||||
} ?: true
|
|
||||||
} else false
|
|
||||||
|
|
||||||
override fun onHook() = encase {
|
override fun onHook() = encase {
|
||||||
configs {
|
configs {
|
||||||
@@ -425,6 +478,9 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
!prefs.getBoolean(ENABLE_MODULE, default = true) -> loggerW(msg = "Aborted Hook -> Hook Closed")
|
!prefs.getBoolean(ENABLE_MODULE, default = true) -> loggerW(msg = "Aborted Hook -> Hook Closed")
|
||||||
/** 开始 Hook */
|
/** 开始 Hook */
|
||||||
else -> {
|
else -> {
|
||||||
|
/** 缓存图标数据 */
|
||||||
|
iconDatas = IconPackParams(param = this).iconDatas
|
||||||
|
/** 执行 Hook */
|
||||||
NotificationUtilClass.hook {
|
NotificationUtilClass.hook {
|
||||||
/** 强制回写系统的状态栏图标样式为原生 */
|
/** 强制回写系统的状态栏图标样式为原生 */
|
||||||
injectMember {
|
injectMember {
|
||||||
@@ -433,10 +489,10 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
param(ExpandedNotificationClass.clazz)
|
param(ExpandedNotificationClass.clazz)
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 因为之前的 MIUI 版本的状态栏图标颜色会全部设置为白色的 - 找不到修复的地方就直接判断版本了
|
* 为了防止 MIUI 自身的版本不同造成的各种 BUG
|
||||||
* 对于之前没有通知图标色彩判断功能的版本判断是 MIUI 样式就停止 Hook
|
* 判断是 MIUI 样式就停止 Hook
|
||||||
*/
|
*/
|
||||||
replaceAny { if (hasIgnoreStatusBarIconColor) false else isShowMiuiStyle }
|
replaceAny { globalContext?.isMiuiNotifyStyle ?: isShowMiuiStyle }
|
||||||
}
|
}
|
||||||
if (hasIgnoreStatusBarIconColor)
|
if (hasIgnoreStatusBarIconColor)
|
||||||
injectMember {
|
injectMember {
|
||||||
@@ -447,7 +503,7 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
replaceAny {
|
replaceAny {
|
||||||
hookIgnoreStatusBarIconColor(
|
hookIgnoreStatusBarIconColor(
|
||||||
context = globalContext ?: error("GlobalContext got null"),
|
context = globalContext ?: error("GlobalContext got null"),
|
||||||
expandedNf = args[0] as? StatusBarNotification?
|
expandedNf = firstArgs as? StatusBarNotification?
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -468,86 +524,86 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
}.onFind { isUseLegacy = true }
|
}.onFind { isUseLegacy = true }
|
||||||
}
|
}
|
||||||
afterHook {
|
afterHook {
|
||||||
/** 对于之前没有通知图标色彩判断功能的版本判断是 MIUI 样式就停止 Hook */
|
(globalContext ?: firstArgs as Context).also { context ->
|
||||||
if (hasIgnoreStatusBarIconColor || !isShowMiuiStyle)
|
hookSmallIconOnSet(
|
||||||
(globalContext ?: args[0] as Context).also { context ->
|
context = context,
|
||||||
hookSmallIconOnSet(
|
args[if (isUseLegacy) 1 else 0] as? StatusBarNotification?,
|
||||||
context = context,
|
(result as Icon).loadDrawable(context)
|
||||||
args[if (isUseLegacy) 1 else 0] as? StatusBarNotification?,
|
) { icon -> result = Icon.createWithBitmap(icon) }
|
||||||
(result as Icon).loadDrawable(context)
|
}
|
||||||
) { icon -> result = Icon.createWithBitmap(icon) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (NotificationHeaderViewWrapperInjectorClass.hasClass)
|
NotificationHeaderViewWrapperClass.hook {
|
||||||
NotificationHeaderViewWrapperInjectorClass.hook {
|
/** 修复下拉通知图标自动设置回 APP 图标的方法 */
|
||||||
/** 修复下拉通知图标自动设置回 APP 图标的方法 */
|
injectMember {
|
||||||
injectMember {
|
if (hasHandleHeaderViews)
|
||||||
var isUseLegacy = false
|
method { name = "handleHeaderViews" }
|
||||||
|
else method { name = "resolveHeaderViews" }
|
||||||
|
afterHook {
|
||||||
|
/** 获取小图标 */
|
||||||
|
val iconImageView =
|
||||||
|
NotificationHeaderViewWrapperClass.clazz
|
||||||
|
.field { name = "mIcon" }.of<ImageView>(instance) ?: return@afterHook
|
||||||
|
|
||||||
|
/** 通知是否展开 */
|
||||||
|
var isExpanded = false
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从父类中得到 mRow 变量 - [ExpandableNotificationRowClass]
|
||||||
|
* 获取其中的得到通知方法
|
||||||
|
*/
|
||||||
|
val expandedNf = ExpandableNotificationRowClass.clazz
|
||||||
|
.method { name = "getEntry" }
|
||||||
|
.get(NotificationViewWrapperClass.clazz.field {
|
||||||
|
name = "mRow"
|
||||||
|
}.get(instance).self?.also {
|
||||||
|
isExpanded = ExpandableNotificationRowClass.clazz.method {
|
||||||
|
name = "isExpanded"
|
||||||
|
returnType = BooleanType
|
||||||
|
}.get(it).invoke<Boolean>() == true
|
||||||
|
}).call()?.let {
|
||||||
|
it.javaClass.method {
|
||||||
|
name = "getSbn"
|
||||||
|
}.get(it).invoke<StatusBarNotification>()
|
||||||
|
} ?: ExpandableNotificationRowClass.clazz
|
||||||
|
.method { name = "getStatusBarNotification" }
|
||||||
|
.get(NotificationViewWrapperClass.clazz.field { name = "mRow" }.get(instance).self)
|
||||||
|
.invoke<StatusBarNotification>()
|
||||||
|
|
||||||
|
/** 获取优先级 */
|
||||||
|
val importance =
|
||||||
|
(iconImageView.context.getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager?)
|
||||||
|
?.getNotificationChannel(expandedNf?.notification?.channelId)?.importance ?: 0
|
||||||
|
/** 非最小化优先级的通知全部设置为展开状态 */
|
||||||
|
if (importance != 1) isExpanded = true
|
||||||
|
/** 执行 Hook */
|
||||||
|
hookNotifyIconOnSet(iconImageView.context, expandedNf, iconImageView, isExpanded)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/** 干掉下拉通知图标自动设置回 APP 图标的方法 */
|
||||||
|
NotificationHeaderViewWrapperInjectorClass.hook {
|
||||||
|
injectMember {
|
||||||
|
method {
|
||||||
|
name = "setAppIcon"
|
||||||
|
param(ContextClass, ImageViewClass, ExpandedNotificationClass.clazz)
|
||||||
|
}.remedys {
|
||||||
method {
|
method {
|
||||||
name = "setAppIcon"
|
name = "setAppIcon"
|
||||||
param(ContextClass, ImageViewClass, ExpandedNotificationClass.clazz)
|
param(ImageViewClass, ExpandedNotificationClass.clazz)
|
||||||
}.remedys {
|
|
||||||
method {
|
|
||||||
name = "setAppIcon"
|
|
||||||
param(ImageViewClass, ExpandedNotificationClass.clazz)
|
|
||||||
}.onFind { isUseLegacy = true }
|
|
||||||
}
|
|
||||||
replaceUnit {
|
|
||||||
if (isUseLegacy)
|
|
||||||
hookNotifyIconOnSet(
|
|
||||||
context = globalContext ?: error("GlobalContext got null"),
|
|
||||||
args[1] as? StatusBarNotification?,
|
|
||||||
args[0] as ImageView
|
|
||||||
)
|
|
||||||
else
|
|
||||||
hookNotifyIconOnSet(
|
|
||||||
context = args[0] as? Context ?: globalContext ?: error("GlobalContext got null"),
|
|
||||||
args[2] as? StatusBarNotification?,
|
|
||||||
args[1] as ImageView
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/** 干掉下拉通知图标自动设置回 APP 图标的方法 - Android 12 */
|
intercept()
|
||||||
if (isUpperOfAndroidS)
|
}.ignoredHookingFailure()
|
||||||
injectMember {
|
injectMember {
|
||||||
method {
|
method {
|
||||||
name = "resetIconBgAndPaddings"
|
name = "resetIconBgAndPaddings"
|
||||||
param(ImageViewClass, ExpandedNotificationClass.clazz)
|
param(ImageViewClass, ExpandedNotificationClass.clazz)
|
||||||
}
|
|
||||||
intercept()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
NotificationHeaderViewWrapperClass.hook {
|
|
||||||
/** 之前的版本解决方案 */
|
|
||||||
injectMember {
|
|
||||||
method { name = "handleHeaderViews" }
|
|
||||||
afterHook {
|
|
||||||
/** 对于之前没有通知图标色彩判断功能的版本判断是 MIUI 样式就停止 Hook */
|
|
||||||
if (!hasIgnoreStatusBarIconColor && isShowMiuiStyle) return@afterHook
|
|
||||||
|
|
||||||
/** 获取小图标 */
|
|
||||||
val iconImageView =
|
|
||||||
NotificationHeaderViewWrapperClass.clazz
|
|
||||||
.field { name = "mIcon" }.of<ImageView>(instance) ?: return@afterHook
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从父类中得到 mRow 变量 - [ExpandableNotificationRowClass]
|
|
||||||
* 获取其中的得到通知方法
|
|
||||||
*/
|
|
||||||
val expandedNf =
|
|
||||||
ExpandableNotificationRowClass.clazz
|
|
||||||
.method { name = "getStatusBarNotification" }
|
|
||||||
.get(NotificationViewWrapperClass.clazz.field { name = "mRow" }.get(instance).self)
|
|
||||||
.invoke<StatusBarNotification>()
|
|
||||||
/** 执行 Hook */
|
|
||||||
hookNotifyIconOnSet(iconImageView.context, expandedNf, iconImageView)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
intercept()
|
||||||
|
}.ignoredHookingFailure()
|
||||||
|
}.ignoredHookClassNotFoundFailure()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -24,8 +24,7 @@
|
|||||||
|
|
||||||
package com.fankes.miui.notify.ui
|
package com.fankes.miui.notify.ui
|
||||||
|
|
||||||
import android.content.Intent
|
import android.app.ProgressDialog
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@@ -35,19 +34,26 @@ import android.widget.ListView
|
|||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.constraintlayout.utils.widget.ImageFilterView
|
import androidx.constraintlayout.utils.widget.ImageFilterView
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.core.widget.doOnTextChanged
|
||||||
import com.fankes.miui.notify.R
|
import com.fankes.miui.notify.R
|
||||||
|
import com.fankes.miui.notify.bean.IconDataBean
|
||||||
|
import com.fankes.miui.notify.hook.HookConst.SOURCE_SYNC_WAY
|
||||||
|
import com.fankes.miui.notify.hook.HookConst.SOURCE_SYNC_WAY_CUSTOM_URL
|
||||||
|
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.hook.factory.isAppNotifyHookAllOf
|
import com.fankes.miui.notify.hook.factory.isAppNotifyHookAllOf
|
||||||
import com.fankes.miui.notify.hook.factory.isAppNotifyHookOf
|
import com.fankes.miui.notify.hook.factory.isAppNotifyHookOf
|
||||||
import com.fankes.miui.notify.hook.factory.putAppNotifyHookAllOf
|
import com.fankes.miui.notify.hook.factory.putAppNotifyHookAllOf
|
||||||
import com.fankes.miui.notify.hook.factory.putAppNotifyHookOf
|
import com.fankes.miui.notify.hook.factory.putAppNotifyHookOf
|
||||||
import com.fankes.miui.notify.params.IconPackParams
|
import com.fankes.miui.notify.params.IconPackParams
|
||||||
import com.fankes.miui.notify.ui.base.BaseActivity
|
import com.fankes.miui.notify.ui.base.BaseActivity
|
||||||
import com.fankes.miui.notify.utils.SystemUITool
|
import com.fankes.miui.notify.utils.*
|
||||||
import com.fankes.miui.notify.utils.showDialog
|
|
||||||
import com.fankes.miui.notify.utils.snake
|
|
||||||
import com.fankes.miui.notify.utils.toast
|
|
||||||
import com.fankes.miui.notify.view.MaterialSwitch
|
import com.fankes.miui.notify.view.MaterialSwitch
|
||||||
|
import com.google.android.material.radiobutton.MaterialRadioButton
|
||||||
import com.google.android.material.textfield.TextInputEditText
|
import com.google.android.material.textfield.TextInputEditText
|
||||||
|
import com.highcapable.yukihookapi.hook.factory.modulePrefs
|
||||||
|
import com.highcapable.yukihookapi.hook.xposed.YukiHookModuleStatus
|
||||||
|
|
||||||
class ConfigureActivity : BaseActivity() {
|
class ConfigureActivity : BaseActivity() {
|
||||||
|
|
||||||
@@ -60,9 +66,22 @@ class ConfigureActivity : BaseActivity() {
|
|||||||
/** 回调滚动事件改变 */
|
/** 回调滚动事件改变 */
|
||||||
private var onScrollEvent: ((Boolean) -> Unit)? = null
|
private var onScrollEvent: ((Boolean) -> Unit)? = null
|
||||||
|
|
||||||
|
/** 全部的通知优化图标数据 */
|
||||||
|
private var iconAllDatas = ArrayList<IconDataBean>()
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_config)
|
setContentView(R.layout.activity_config)
|
||||||
|
/** 检查激活状态 */
|
||||||
|
if (!YukiHookModuleStatus.isActive()) {
|
||||||
|
showDialog {
|
||||||
|
title = "模块没有激活"
|
||||||
|
msg = "模块没有激活,你无法使用这里的功能,请先激活模块。"
|
||||||
|
confirmButton(text = "我知道了") { finish() }
|
||||||
|
noCancelable()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
/** 返回按钮点击事件 */
|
/** 返回按钮点击事件 */
|
||||||
findViewById<View>(R.id.title_back_icon).setOnClickListener { onBackPressed() }
|
findViewById<View>(R.id.title_back_icon).setOnClickListener { onBackPressed() }
|
||||||
/** 刷新适配器结果相关 */
|
/** 刷新适配器结果相关 */
|
||||||
@@ -94,7 +113,6 @@ class ConfigureActivity : BaseActivity() {
|
|||||||
confirmButton {
|
confirmButton {
|
||||||
if (editText.text.toString().isNotBlank()) {
|
if (editText.text.toString().isNotBlank()) {
|
||||||
filterText = editText.text.toString().trim()
|
filterText = editText.text.toString().trim()
|
||||||
onChanged?.invoke()
|
|
||||||
refreshAdapterResult()
|
refreshAdapterResult()
|
||||||
} else {
|
} else {
|
||||||
toast(msg = "条件不能为空")
|
toast(msg = "条件不能为空")
|
||||||
@@ -105,11 +123,12 @@ class ConfigureActivity : BaseActivity() {
|
|||||||
if (filterText.isNotBlank())
|
if (filterText.isNotBlank())
|
||||||
neutralButton(text = "清除条件") {
|
neutralButton(text = "清除条件") {
|
||||||
filterText = ""
|
filterText = ""
|
||||||
onChanged?.invoke()
|
|
||||||
refreshAdapterResult()
|
refreshAdapterResult()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/** 设置同步列表按钮点击事件 */
|
||||||
|
findViewById<View>(R.id.config_title_sync).setOnClickListener { onStartRefresh() }
|
||||||
/** 设置列表元素和 Adapter */
|
/** 设置列表元素和 Adapter */
|
||||||
findViewById<ListView>(R.id.config_list_view).apply {
|
findViewById<ListView>(R.id.config_list_view).apply {
|
||||||
adapter = object : BaseAdapter() {
|
adapter = object : BaseAdapter() {
|
||||||
@@ -174,30 +193,226 @@ class ConfigureActivity : BaseActivity() {
|
|||||||
lateinit var switchOpen: MaterialSwitch
|
lateinit var switchOpen: MaterialSwitch
|
||||||
lateinit var switchAll: MaterialSwitch
|
lateinit var switchAll: MaterialSwitch
|
||||||
}
|
}
|
||||||
}.apply { onChanged = { notifyDataSetChanged() } }
|
}.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) } }
|
onScrollEvent = { post { setSelection(if (it) iconDatas.lastIndex else 0) } }
|
||||||
}
|
}
|
||||||
/** 设置点击事件 */
|
/** 设置点击事件 */
|
||||||
findViewById<View>(R.id.config_cbr_button).setOnClickListener {
|
findViewById<View>(R.id.config_cbr_button).setOnClickListener {
|
||||||
runCatching {
|
openBrowser(url = "https://github.com/fankes/AndroidNotifyIconAdapt/blob/main/CONTRIBUTING.md")
|
||||||
startActivity(Intent().apply {
|
}
|
||||||
action = "android.intent.action.VIEW"
|
/** 装载数据 */
|
||||||
data = Uri.parse("https://github.com/fankes/MIUINativeNotifyIcon")
|
mockLocalData()
|
||||||
/** 防止顶栈一样重叠在自己的 APP 中 */
|
/** 更新数据 */
|
||||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
onStartRefresh()
|
||||||
})
|
}
|
||||||
}.onFailure {
|
|
||||||
toast(msg = "无法启动系统默认浏览器")
|
/** 装载或刷新本地数据 */
|
||||||
|
private fun mockLocalData() {
|
||||||
|
iconAllDatas = IconPackParams(context = this).iconDatas
|
||||||
|
refreshAdapterResult()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 首次进入或更新数据 */
|
||||||
|
private fun onStartRefresh() =
|
||||||
|
showDialog {
|
||||||
|
title = "同步列表"
|
||||||
|
var sourceType = modulePrefs.getInt(SOURCE_SYNC_WAY, TYPE_SOURCE_SYNC_WAY_1)
|
||||||
|
var customUrl = modulePrefs.getString(SOURCE_SYNC_WAY_CUSTOM_URL)
|
||||||
|
addView(R.layout.dia_source_from).apply {
|
||||||
|
val radio1 = findViewById<MaterialRadioButton>(R.id.dia_sf_rd1)
|
||||||
|
val radio2 = findViewById<MaterialRadioButton>(R.id.dia_sf_rd2)
|
||||||
|
val radio3 = findViewById<MaterialRadioButton>(R.id.dia_sf_rd3)
|
||||||
|
val edLin = findViewById<View>(R.id.dia_sf_text_lin)
|
||||||
|
findViewById<TextInputEditText>(R.id.dia_sf_text).apply {
|
||||||
|
if (customUrl.isNotBlank()) {
|
||||||
|
setText(customUrl)
|
||||||
|
setSelection(customUrl.length)
|
||||||
|
}
|
||||||
|
doOnTextChanged { text, _, _, _ ->
|
||||||
|
customUrl = text.toString()
|
||||||
|
modulePrefs.putString(SOURCE_SYNC_WAY_CUSTOM_URL, text.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
edLin.isVisible = sourceType == TYPE_SOURCE_SYNC_WAY_3
|
||||||
|
radio1.isChecked = sourceType == TYPE_SOURCE_SYNC_WAY_1
|
||||||
|
radio2.isChecked = sourceType == TYPE_SOURCE_SYNC_WAY_2
|
||||||
|
radio3.isChecked = sourceType == TYPE_SOURCE_SYNC_WAY_3
|
||||||
|
radio1.setOnClickListener {
|
||||||
|
radio2.isChecked = false
|
||||||
|
radio3.isChecked = false
|
||||||
|
edLin.isVisible = false
|
||||||
|
sourceType = TYPE_SOURCE_SYNC_WAY_1
|
||||||
|
modulePrefs.putInt(SOURCE_SYNC_WAY, TYPE_SOURCE_SYNC_WAY_1)
|
||||||
|
}
|
||||||
|
radio2.setOnClickListener {
|
||||||
|
radio1.isChecked = false
|
||||||
|
radio3.isChecked = false
|
||||||
|
edLin.isVisible = false
|
||||||
|
sourceType = TYPE_SOURCE_SYNC_WAY_2
|
||||||
|
modulePrefs.putInt(SOURCE_SYNC_WAY, TYPE_SOURCE_SYNC_WAY_2)
|
||||||
|
}
|
||||||
|
radio3.setOnClickListener {
|
||||||
|
radio1.isChecked = false
|
||||||
|
radio2.isChecked = false
|
||||||
|
edLin.isVisible = true
|
||||||
|
sourceType = TYPE_SOURCE_SYNC_WAY_3
|
||||||
|
modulePrefs.putInt(SOURCE_SYNC_WAY, TYPE_SOURCE_SYNC_WAY_3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
confirmButton {
|
||||||
|
when (sourceType) {
|
||||||
|
TYPE_SOURCE_SYNC_WAY_1 -> onRefreshing(url = "https://raw.fastgit.org/fankes/AndroidNotifyIconAdapt/main")
|
||||||
|
TYPE_SOURCE_SYNC_WAY_2 -> onRefreshing(url = "https://raw.githubusercontent.com/fankes/AndroidNotifyIconAdapt/main")
|
||||||
|
TYPE_SOURCE_SYNC_WAY_3 ->
|
||||||
|
if (customUrl.isNotBlank())
|
||||||
|
if (customUrl.startsWith("http://") || customUrl.startsWith("https://"))
|
||||||
|
onRefreshingCustom(customUrl)
|
||||||
|
else snake(msg = "同步地址不是一个合法的 URL")
|
||||||
|
else snake(msg = "同步地址不能为空")
|
||||||
|
else -> snake(msg = "同步类型错误")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cancelButton()
|
||||||
|
neutralButton(text = "自定义规则") {
|
||||||
|
showDialog {
|
||||||
|
title = "自定义规则"
|
||||||
|
var editText: TextInputEditText
|
||||||
|
addView(R.layout.dia_source_from_string).apply {
|
||||||
|
editText = findViewById<TextInputEditText>(R.id.dia_sfs_input_edit).apply {
|
||||||
|
requestFocus()
|
||||||
|
invalidate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
confirmButton {
|
||||||
|
IconPackParams(context = this@ConfigureActivity).also { params ->
|
||||||
|
when {
|
||||||
|
editText.text.toString().isNotBlank() && params.isNotVaildJson(editText.text.toString()) ->
|
||||||
|
snake(msg = "不是有效的 JSON 数据")
|
||||||
|
editText.text.toString().isNotBlank() -> {
|
||||||
|
params.save(editText.text.toString())
|
||||||
|
filterText = ""
|
||||||
|
mockLocalData()
|
||||||
|
SystemUITool.showNeedUpdateApplySnake(context = this@ConfigureActivity)
|
||||||
|
}
|
||||||
|
else -> snake(msg = "规则数组内容为空")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cancelButton()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始更新数据
|
||||||
|
* @param url
|
||||||
|
*/
|
||||||
|
private fun onRefreshing(url: String) = ClientRequestTool.checkingInternetConnect(context = this) {
|
||||||
|
ProgressDialog(this).apply {
|
||||||
|
setDefaultStyle(context = this@ConfigureActivity)
|
||||||
|
setCancelable(false)
|
||||||
|
setTitle("同步中")
|
||||||
|
setMessage("正在同步 OS 数据")
|
||||||
|
show()
|
||||||
|
}.also {
|
||||||
|
ClientRequestTool.wait(
|
||||||
|
context = this,
|
||||||
|
url = "$url/OS/MIUI/NotifyIconsSupportConfig.json"
|
||||||
|
) { isDone1, ctOS ->
|
||||||
|
it.setMessage("正在同步 APP 数据")
|
||||||
|
ClientRequestTool.wait(
|
||||||
|
context = this,
|
||||||
|
url = "$url/APP/NotifyIconsSupportConfig.json"
|
||||||
|
) { isDone2, ctAPP ->
|
||||||
|
it.cancel()
|
||||||
|
IconPackParams(context = this).also { params ->
|
||||||
|
if (isDone1 && isDone2) params.splicingJsonArray(ctOS, ctAPP).also {
|
||||||
|
when {
|
||||||
|
params.isHackString(it) -> snake(msg = "请求需要验证,请尝试魔法上网或关闭魔法")
|
||||||
|
params.isNotVaildJson(it) -> snake(msg = "在线规则发生问题,请稍后重试")
|
||||||
|
params.isCompareDifferent(it) -> {
|
||||||
|
params.save(it)
|
||||||
|
filterText = ""
|
||||||
|
mockLocalData()
|
||||||
|
SystemUITool.showNeedUpdateApplySnake(context = this)
|
||||||
|
}
|
||||||
|
else -> snake(msg = "列表数据已是最新")
|
||||||
|
}
|
||||||
|
} else showDialog {
|
||||||
|
title = "连接失败"
|
||||||
|
msg = "连接失败,错误如下:\n${if (!isDone1) ctOS else ctAPP}"
|
||||||
|
confirmButton(text = "解决方案") {
|
||||||
|
openBrowser(url = "https://www.baidu.com/s?wd=github%2Braw%2B%E6%97%A0%E6%B3%95%E8%AE%BF%E9%97%AE")
|
||||||
|
}
|
||||||
|
cancelButton()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始更新数据
|
||||||
|
* @param url
|
||||||
|
*/
|
||||||
|
private fun onRefreshingCustom(url: String) = ClientRequestTool.checkingInternetConnect(context = this) {
|
||||||
|
ProgressDialog(this).apply {
|
||||||
|
setDefaultStyle(context = this@ConfigureActivity)
|
||||||
|
setCancelable(false)
|
||||||
|
setTitle("同步中")
|
||||||
|
setMessage("正在通过自定义地址同步数据")
|
||||||
|
show()
|
||||||
|
}.also {
|
||||||
|
ClientRequestTool.wait(
|
||||||
|
context = this,
|
||||||
|
url = url
|
||||||
|
) { isDone, content ->
|
||||||
|
it.cancel()
|
||||||
|
IconPackParams(context = this).also { params ->
|
||||||
|
if (isDone)
|
||||||
|
when {
|
||||||
|
params.isHackString(content) -> snake(msg = "请求需要验证,请尝试魔法上网或关闭魔法")
|
||||||
|
params.isNotVaildJson(content) -> snake(msg = "目标地址不是有效的 JSON 数据")
|
||||||
|
params.isCompareDifferent(content) -> {
|
||||||
|
params.save(content)
|
||||||
|
filterText = ""
|
||||||
|
mockLocalData()
|
||||||
|
SystemUITool.showNeedUpdateApplySnake(context = this)
|
||||||
|
}
|
||||||
|
else -> snake(msg = "列表数据已是最新")
|
||||||
|
}
|
||||||
|
else showDialog {
|
||||||
|
title = "连接失败"
|
||||||
|
msg = "连接失败,错误如下:\n$content"
|
||||||
|
confirmButton(text = "我知道了")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 刷新适配器结果相关 */
|
/** 刷新适配器结果相关 */
|
||||||
private fun refreshAdapterResult() {
|
private fun refreshAdapterResult() {
|
||||||
|
onChanged?.invoke()
|
||||||
findViewById<TextView>(R.id.config_title_count_text).text =
|
findViewById<TextView>(R.id.config_title_count_text).text =
|
||||||
if (filterText.isBlank()) "已适配 ${iconDatas.size} 个 APP 的通知图标"
|
if (filterText.isBlank()) "已适配 ${iconDatas.size} 个 APP 的通知图标"
|
||||||
else "“${filterText}” 匹配到 ${iconDatas.size} 个结果"
|
else "“${filterText}” 匹配到 ${iconDatas.size} 个结果"
|
||||||
findViewById<View>(R.id.config_list_no_data_view).isVisible = iconDatas.isEmpty()
|
findViewById<TextView>(R.id.config_list_no_data_view).apply {
|
||||||
|
text = if (iconAllDatas.isEmpty()) "噫,竟然什么都没有~\n请点击右上角同步按钮获取云端数据" else "噫,竟然什么都没找到~"
|
||||||
|
isVisible = iconDatas.isEmpty()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -205,8 +420,8 @@ class ConfigureActivity : BaseActivity() {
|
|||||||
* @return [Array]
|
* @return [Array]
|
||||||
*/
|
*/
|
||||||
private val iconDatas
|
private val iconDatas
|
||||||
get() = if (filterText.isBlank()) IconPackParams.iconDatas
|
get() = if (filterText.isBlank()) iconAllDatas
|
||||||
else IconPackParams.iconDatas.filter {
|
else iconAllDatas.filter {
|
||||||
it.appName.lowercase().contains(filterText.lowercase()) || it.packageName.lowercase().contains(filterText.lowercase())
|
it.appName.lowercase().contains(filterText.lowercase()) || it.packageName.lowercase().contains(filterText.lowercase())
|
||||||
}.toTypedArray()
|
}
|
||||||
}
|
}
|
||||||
|
@@ -27,7 +27,6 @@ package com.fankes.miui.notify.ui
|
|||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
@@ -62,8 +61,8 @@ class MainActivity : BaseActivity() {
|
|||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_main)
|
setContentView(R.layout.activity_main)
|
||||||
/** 设置文本 */
|
/** 设置文本 */
|
||||||
findViewById<TextView>(R.id.main_text_version).text = "当前版本:$moduleVersion"
|
findViewById<TextView>(R.id.main_text_version).text = "模块版本:$moduleVersion"
|
||||||
findViewById<TextView>(R.id.main_text_miui_version).text = "MIUI 版本:$miuiFullVersion"
|
findViewById<TextView>(R.id.main_text_miui_version).text = "系统版本:$miuiFullVersion"
|
||||||
when {
|
when {
|
||||||
/** 判断是否为 MIUI 系统 */
|
/** 判断是否为 MIUI 系统 */
|
||||||
isNotMIUI ->
|
isNotMIUI ->
|
||||||
@@ -93,11 +92,7 @@ class MainActivity : BaseActivity() {
|
|||||||
noCancelable()
|
noCancelable()
|
||||||
}
|
}
|
||||||
/** 判断是否 Hook */
|
/** 判断是否 Hook */
|
||||||
YukiHookModuleStatus.isActive() -> {
|
YukiHookModuleStatus.isActive() -> {}
|
||||||
findViewById<LinearLayout>(R.id.main_lin_status).setBackgroundResource(R.drawable.bg_green_round)
|
|
||||||
findViewById<ImageFilterView>(R.id.main_img_status).setImageResource(R.mipmap.ic_success)
|
|
||||||
findViewById<TextView>(R.id.main_text_status).text = "模块已激活"
|
|
||||||
}
|
|
||||||
else ->
|
else ->
|
||||||
showDialog {
|
showDialog {
|
||||||
title = "模块没有激活"
|
title = "模块没有激活"
|
||||||
@@ -181,43 +176,64 @@ class MainActivity : BaseActivity() {
|
|||||||
findViewById<View>(R.id.title_restart_icon).setOnClickListener { SystemUITool.restartSystemUI(context = this) }
|
findViewById<View>(R.id.title_restart_icon).setOnClickListener { SystemUITool.restartSystemUI(context = this) }
|
||||||
/** 恰饭! */
|
/** 恰饭! */
|
||||||
findViewById<View>(R.id.link_with_follow_me).setOnClickListener {
|
findViewById<View>(R.id.link_with_follow_me).setOnClickListener {
|
||||||
runCatching {
|
openBrowser(url = "https://www.coolapk.com/u/876977", packageName = "com.coolapk.market")
|
||||||
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
|
|
||||||
})
|
|
||||||
}.onFailure {
|
|
||||||
toast(msg = "你可能没有安装酷安")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/** 项目地址点击事件 */
|
/** 项目地址点击事件 */
|
||||||
findViewById<View>(R.id.link_with_project_address).setOnClickListener {
|
findViewById<View>(R.id.link_with_project_address).setOnClickListener {
|
||||||
runCatching {
|
openBrowser(url = "https://github.com/fankes/MIUINativeNotifyIcon")
|
||||||
startActivity(Intent().apply {
|
|
||||||
action = "android.intent.action.VIEW"
|
|
||||||
data = Uri.parse("https://github.com/fankes/MIUINativeNotifyIcon")
|
|
||||||
/** 防止顶栈一样重叠在自己的 APP 中 */
|
|
||||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
|
||||||
})
|
|
||||||
}.onFailure {
|
|
||||||
toast(msg = "无法启动系统默认浏览器")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 刷新模块状态 */
|
||||||
|
private fun refreshModuleStatus() {
|
||||||
|
findViewById<LinearLayout>(R.id.main_lin_status).setBackgroundResource(
|
||||||
|
when {
|
||||||
|
YukiHookModuleStatus.isActive() && isMiuiNotifyStyle -> R.drawable.bg_yellow_round
|
||||||
|
YukiHookModuleStatus.isActive() -> R.drawable.bg_green_round
|
||||||
|
else -> R.drawable.bg_dark_round
|
||||||
|
}
|
||||||
|
)
|
||||||
|
findViewById<ImageFilterView>(R.id.main_img_status).setImageResource(
|
||||||
|
when {
|
||||||
|
YukiHookModuleStatus.isActive() && !isMiuiNotifyStyle -> R.mipmap.ic_success
|
||||||
|
else -> R.mipmap.ic_warn
|
||||||
|
}
|
||||||
|
)
|
||||||
|
findViewById<TextView>(R.id.main_text_status).text =
|
||||||
|
when {
|
||||||
|
YukiHookModuleStatus.isActive() && isMiuiNotifyStyle -> "模块已激活,但未在工作"
|
||||||
|
YukiHookModuleStatus.isActive() -> "模块已激活"
|
||||||
|
else -> "模块未激活"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
/** MIUI 12 的版本特殊 - 所以给出提示 */
|
/** 刷新模块状态 */
|
||||||
if (!isWarnDialogShowing && YukiHookModuleStatus.isActive() && miuiVersion == "12" && isMiuiNotifyStyle)
|
refreshModuleStatus()
|
||||||
|
/** 经典样式启用后给出警告 */
|
||||||
|
if (!isWarnDialogShowing && YukiHookModuleStatus.isActive() && isMiuiNotifyStyle)
|
||||||
showDialog {
|
showDialog {
|
||||||
isWarnDialogShowing = true
|
isWarnDialogShowing = true
|
||||||
title = "经典通知栏样式已启用"
|
title = "经典通知栏样式已启用"
|
||||||
msg = "在 MIUI 12 中启用了经典通知栏样式后状态栏图标将不再做原生处理,模块停止工作," +
|
msg = "当你启用了经典通知栏样式后,为防止 MIUI 自身不规范 APP 图标被破坏,状态栏图标将不再做原生处理。\n\n" +
|
||||||
"这取决于系统设置,你应当在 设置>通知管理>通知显示设置 中将样式设置为“原生样式”。"
|
"若要使用原生样式,请前往 设置>通知管理>通知显示设置 中将样式设置为“原生样式”,新版本为 设置>通知与控制中心>通知显示设置。"
|
||||||
confirmButton(text = "我知道了") { isWarnDialogShowing = false }
|
confirmButton(text = "去设置") {
|
||||||
|
runCatching {
|
||||||
|
startActivity(Intent().apply {
|
||||||
|
component = ComponentName(
|
||||||
|
"com.miui.notification",
|
||||||
|
"miui.notification.management.activity.NotificationDisplaySettingsActivity"
|
||||||
|
)
|
||||||
|
/** 防止顶栈一样重叠在自己的 APP 中 */
|
||||||
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
|
})
|
||||||
|
}.onFailure {
|
||||||
|
toast(msg = "启动失败,请手动调整设置")
|
||||||
|
}
|
||||||
|
isWarnDialogShowing = false
|
||||||
|
}
|
||||||
|
cancelButton { isWarnDialogShowing = false }
|
||||||
noCancelable()
|
noCancelable()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
* 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", "DEPRECATION")
|
||||||
|
|
||||||
|
package com.fankes.miui.notify.utils
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.app.ProgressDialog
|
||||||
|
import android.content.Intent
|
||||||
|
import android.net.Uri
|
||||||
|
import android.provider.Settings
|
||||||
|
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 ClientRequestTool {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查网络连接情况
|
||||||
|
* @param context 实例
|
||||||
|
* @param it 已连接回调
|
||||||
|
*/
|
||||||
|
fun checkingInternetConnect(context: Activity, it: () -> Unit) =
|
||||||
|
ProgressDialog(context).apply {
|
||||||
|
setDefaultStyle(context)
|
||||||
|
setCancelable(false)
|
||||||
|
setTitle("准备中")
|
||||||
|
setMessage("正在检查网络连接情况")
|
||||||
|
}.apply {
|
||||||
|
wait(context, url = "https://www.baidu.com") { isDone, _ ->
|
||||||
|
cancel()
|
||||||
|
if (isDone) it() else
|
||||||
|
context.showDialog {
|
||||||
|
title = "网络不可用"
|
||||||
|
msg = "无法连接到互联网,请检查你当前的设备是否可以上网,且没有在手机管家中禁用本模块的联网权限。"
|
||||||
|
confirmButton(text = "检查设置") {
|
||||||
|
runCatching {
|
||||||
|
context.startActivity(Intent().apply {
|
||||||
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
|
action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
|
||||||
|
data = Uri.fromParts("package", context.packageName, null)
|
||||||
|
})
|
||||||
|
}.onFailure { context.snake(msg = "启动应用信息页面失败") }
|
||||||
|
}
|
||||||
|
cancelButton()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.show()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送 GET 请求内容并等待
|
||||||
|
* @param context 实例
|
||||||
|
* @param url 请求地址
|
||||||
|
* @param it 回调 - ([Boolean] 是否成功,[String] 成功的内容或失败消息)
|
||||||
|
*/
|
||||||
|
fun wait(context: Activity, url: String, it: (Boolean, String) -> Unit) = runCatching {
|
||||||
|
OkHttpClient().newBuilder().apply {
|
||||||
|
SSLSocketClient.sSLSocketFactory?.let { sslSocketFactory(it, SSLSocketClient.trustManager) }
|
||||||
|
hostnameVerifier(SSLSocketClient.hostnameVerifier)
|
||||||
|
}.build().newCall(
|
||||||
|
Request.Builder()
|
||||||
|
.url(url)
|
||||||
|
.get()
|
||||||
|
.build()
|
||||||
|
).enqueue(object : Callback {
|
||||||
|
override fun onFailure(call: Call, e: IOException) {
|
||||||
|
context.runOnUiThread { it(false, e.toString()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResponse(call: Call, response: Response) {
|
||||||
|
val bodyString = response.body?.string() ?: ""
|
||||||
|
context.runOnUiThread { it(true, bodyString) }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}.onFailure { it(false, "URL 无效") }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动信任 SSL 证书
|
||||||
|
*
|
||||||
|
* 放行全部加密 SSL 请求
|
||||||
|
*/
|
||||||
|
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>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -26,8 +26,6 @@ package com.fankes.miui.notify.utils
|
|||||||
|
|
||||||
import android.app.AlertDialog
|
import android.app.AlertDialog
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Color
|
|
||||||
import android.graphics.drawable.GradientDrawable
|
|
||||||
import android.util.DisplayMetrics
|
import android.util.DisplayMetrics
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@@ -109,14 +107,7 @@ class DialogBuilder(private val context: Context) {
|
|||||||
internal fun show() = instance?.create()?.apply {
|
internal fun show() = instance?.create()?.apply {
|
||||||
val dm = DisplayMetrics()
|
val dm = DisplayMetrics()
|
||||||
(context.getSystemService(Context.WINDOW_SERVICE) as WindowManager).defaultDisplay.getMetrics(dm)
|
(context.getSystemService(Context.WINDOW_SERVICE) as WindowManager).defaultDisplay.getMetrics(dm)
|
||||||
customLayoutView?.let { setView(it.apply { minimumWidth = round(dm.widthPixels / 1.3).toInt() }) }
|
customLayoutView?.let { setView(it.apply { minimumWidth = round(x = dm.widthPixels / 1.3).toInt() }) }
|
||||||
window?.setBackgroundDrawable(GradientDrawable(
|
setDefaultStyle(context = this@DialogBuilder.context)
|
||||||
GradientDrawable.Orientation.TOP_BOTTOM,
|
|
||||||
intArrayOf(Color.WHITE, Color.WHITE)
|
|
||||||
).apply {
|
|
||||||
shape = GradientDrawable.RECTANGLE
|
|
||||||
gradientType = GradientDrawable.LINEAR_GRADIENT
|
|
||||||
cornerRadius = 15.dp(this@DialogBuilder.context)
|
|
||||||
})
|
|
||||||
}?.show()
|
}?.show()
|
||||||
}
|
}
|
@@ -58,4 +58,13 @@ object SystemUITool {
|
|||||||
if (YukiHookModuleStatus.isActive())
|
if (YukiHookModuleStatus.isActive())
|
||||||
context.snake(msg = "设置需要重启系统界面才能生效", actionText = "立即重启") { restartSystemUI(context) }
|
context.snake(msg = "设置需要重启系统界面才能生效", actionText = "立即重启") { restartSystemUI(context) }
|
||||||
else context.snake(msg = "模块没有激活,更改不会生效")
|
else context.snake(msg = "模块没有激活,更改不会生效")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示更新数据后需要重启系统界面的 [Snackbar]
|
||||||
|
* @param context 实例
|
||||||
|
*/
|
||||||
|
fun showNeedUpdateApplySnake(context: Context) =
|
||||||
|
if (YukiHookModuleStatus.isActive())
|
||||||
|
context.snake(msg = "数据已更新,请重启系统界面使更改生效", actionText = "立即重启") { restartSystemUI(context) }
|
||||||
|
else context.snake(msg = "模块没有激活,更改不会生效")
|
||||||
}
|
}
|
@@ -25,12 +25,19 @@
|
|||||||
package com.fankes.miui.notify.utils
|
package com.fankes.miui.notify.utils
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
import android.app.AlertDialog
|
||||||
|
import android.content.ClipData
|
||||||
|
import android.content.ClipboardManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
import android.content.pm.PackageInfo
|
import android.content.pm.PackageInfo
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.graphics.*
|
import android.graphics.Bitmap
|
||||||
import android.graphics.Bitmap.createBitmap
|
import android.graphics.BitmapFactory
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.drawable.GradientDrawable
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import android.util.Base64
|
import android.util.Base64
|
||||||
@@ -43,6 +50,7 @@ import com.highcapable.yukihookapi.hook.factory.method
|
|||||||
import com.highcapable.yukihookapi.hook.log.loggerE
|
import com.highcapable.yukihookapi.hook.log.loggerE
|
||||||
import com.highcapable.yukihookapi.hook.type.java.StringType
|
import com.highcapable.yukihookapi.hook.type.java.StringType
|
||||||
import com.topjohnwu.superuser.Shell
|
import com.topjohnwu.superuser.Shell
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 系统深色模式是否开启
|
* 系统深色模式是否开启
|
||||||
@@ -143,8 +151,35 @@ val miuiVersion
|
|||||||
* @return [String]
|
* @return [String]
|
||||||
*/
|
*/
|
||||||
val miuiFullVersion
|
val miuiFullVersion
|
||||||
get() = if (isMIUI) (miuiVersion + " " + findPropString(key = "ro.system.build.version.incremental"))
|
get() = if (isMIUI) findPropString(key = "ro.system.build.version.incremental").let {
|
||||||
else "不是 MIUI 系统"
|
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 系统"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 得到安装包信息
|
* 得到安装包信息
|
||||||
@@ -190,6 +225,17 @@ val Number.dp get() = (toFloat() * appContext.resources.displayMetrics.density).
|
|||||||
*/
|
*/
|
||||||
fun Number.dp(context: Context) = toFloat() * context.resources.displayMetrics.density
|
fun Number.dp(context: Context) = toFloat() * context.resources.displayMetrics.density
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base64 加密
|
||||||
|
* @return [String]
|
||||||
|
*/
|
||||||
|
val Bitmap.base64
|
||||||
|
get() = safeOfNothing {
|
||||||
|
val baos = ByteArrayOutputStream()
|
||||||
|
compress(Bitmap.CompressFormat.PNG, 100, baos)
|
||||||
|
Base64.encodeToString(baos.toByteArray(), Base64.DEFAULT)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base64 加密
|
* Base64 加密
|
||||||
* @return [String]
|
* @return [String]
|
||||||
@@ -215,23 +261,19 @@ val ByteArray.bitmap: Bitmap get() = BitmapFactory.decodeByteArray(this, 0, size
|
|||||||
val String.bitmap: Bitmap get() = unbase64.bitmap
|
val String.bitmap: Bitmap get() = unbase64.bitmap
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 圆角图片
|
* 设置对话框默认风格
|
||||||
* @param radius 圆角度
|
* @param context 使用的实例
|
||||||
* @return [Bitmap] 圆角后的位图 - 失败会返回处理之前的位图
|
|
||||||
*/
|
*/
|
||||||
fun Bitmap.round(radius: Float): Bitmap =
|
fun AlertDialog.setDefaultStyle(context: Context) =
|
||||||
createBitmap(width, height, Bitmap.Config.ARGB_8888).also { out ->
|
window?.setBackgroundDrawable(
|
||||||
Canvas(out).also { canvas ->
|
GradientDrawable(
|
||||||
Paint().also { paint ->
|
GradientDrawable.Orientation.TOP_BOTTOM,
|
||||||
paint.isAntiAlias = true
|
intArrayOf(Color.WHITE, Color.WHITE)
|
||||||
canvas.drawARGB(0, 0, 0, 0)
|
).apply {
|
||||||
paint.color = Color.WHITE
|
shape = GradientDrawable.RECTANGLE
|
||||||
canvas.drawRoundRect(RectF(Rect(0, 0, width, height)), radius, radius, paint)
|
gradientType = GradientDrawable.LINEAR_GRADIENT
|
||||||
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN)
|
cornerRadius = 15.dp(context)
|
||||||
canvas.drawBitmap(this, Rect(0, 0, width, height), Rect(0, 0, width, height), paint)
|
})
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取系统 Prop 值
|
* 获取系统 Prop 值
|
||||||
@@ -277,6 +319,39 @@ fun Context.snake(msg: String, actionText: String = "", it: () -> Unit = {}) =
|
|||||||
setAction(actionText) { it() }
|
setAction(actionText) { it() }
|
||||||
}.show()
|
}.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 = "启动系统浏览器失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复制到剪贴板
|
||||||
|
* @param content 要复制的文本
|
||||||
|
*/
|
||||||
|
fun Context.copyToClipboard(content: String) = runCatching {
|
||||||
|
(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 it 回调 - 如果异常为空
|
* @param it 回调 - 如果异常为空
|
||||||
|
6
app/src/main/res/drawable/bg_yellow_round.xml
Executable file
6
app/src/main/res/drawable/bg_yellow_round.xml
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="#FF9800" />
|
||||||
|
<corners android:radius="15dp" />
|
||||||
|
</shape>
|
@@ -52,7 +52,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:text="..."
|
android:text="适配列表正在等待装载"
|
||||||
android:textColor="@color/colorTextDark"
|
android:textColor="@color/colorTextDark"
|
||||||
android:textSize="12sp" />
|
android:textSize="12sp" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
@@ -61,7 +61,7 @@
|
|||||||
android:id="@+id/config_title_up"
|
android:id="@+id/config_title_up"
|
||||||
android:layout_width="22dp"
|
android:layout_width="22dp"
|
||||||
android:layout_height="22dp"
|
android:layout_height="22dp"
|
||||||
android:layout_marginEnd="10dp"
|
android:layout_marginEnd="5dp"
|
||||||
android:src="@mipmap/ic_page_top"
|
android:src="@mipmap/ic_page_top"
|
||||||
android:tint="@color/colorTextGray"
|
android:tint="@color/colorTextGray"
|
||||||
android:tooltipText="滚动到顶部" />
|
android:tooltipText="滚动到顶部" />
|
||||||
@@ -70,7 +70,7 @@
|
|||||||
android:id="@+id/config_title_down"
|
android:id="@+id/config_title_down"
|
||||||
android:layout_width="22dp"
|
android:layout_width="22dp"
|
||||||
android:layout_height="22dp"
|
android:layout_height="22dp"
|
||||||
android:layout_marginEnd="17dp"
|
android:layout_marginEnd="15dp"
|
||||||
android:src="@mipmap/ic_page_bottom"
|
android:src="@mipmap/ic_page_bottom"
|
||||||
android:tint="@color/colorTextGray"
|
android:tint="@color/colorTextGray"
|
||||||
android:tooltipText="滚动到底部" />
|
android:tooltipText="滚动到底部" />
|
||||||
@@ -83,6 +83,15 @@
|
|||||||
android:src="@mipmap/ic_filter"
|
android:src="@mipmap/ic_filter"
|
||||||
android:tint="@color/colorTextGray"
|
android:tint="@color/colorTextGray"
|
||||||
android:tooltipText="按条件过滤" />
|
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>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
@@ -126,7 +135,9 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:text="噫,竟然什么都没找到~"
|
android:gravity="center"
|
||||||
|
android:lineSpacingExtra="6dp"
|
||||||
|
android:text="没有数据"
|
||||||
android:textColor="@color/colorTextDark"
|
android:textColor="@color/colorTextDark"
|
||||||
android:textSize="17sp"
|
android:textSize="17sp"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
@@ -138,7 +149,7 @@
|
|||||||
android:divider="@color/trans"
|
android:divider="@color/trans"
|
||||||
android:dividerHeight="15dp"
|
android:dividerHeight="15dp"
|
||||||
android:fadingEdgeLength="10dp"
|
android:fadingEdgeLength="10dp"
|
||||||
android:listSelector="@null"
|
android:listSelector="@color/trans"
|
||||||
android:padding="15dp"
|
android:padding="15dp"
|
||||||
android:requiresFadingEdge="vertical"
|
android:requiresFadingEdge="vertical"
|
||||||
android:scrollbars="none" />
|
android:scrollbars="none" />
|
||||||
|
@@ -76,7 +76,7 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="5dp"
|
android:layout_marginBottom="5dp"
|
||||||
android:text="模块未激活"
|
android:text="模块状态未知"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
android:textSize="18sp" />
|
android:textSize="18sp" />
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="5dp"
|
android:layout_marginBottom="5dp"
|
||||||
android:alpha="0.8"
|
android:alpha="0.8"
|
||||||
android:text="当前版本:%1"
|
android:text="模块版本:%1"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
android:textSize="13sp" />
|
android:textSize="13sp" />
|
||||||
|
|
||||||
@@ -95,7 +95,7 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:alpha="0.8"
|
android:alpha="0.8"
|
||||||
android:text="MIUI 版本:%1"
|
android:text="系统版本:%1"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
android:textSize="13sp" />
|
android:textSize="13sp" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
@@ -280,6 +280,18 @@
|
|||||||
android:textColor="@color/colorTextGray"
|
android:textColor="@color/colorTextGray"
|
||||||
android:textSize="15sp" />
|
android:textSize="15sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="5dp"
|
||||||
|
android:layout_marginRight="5dp"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:alpha="0.6"
|
||||||
|
android:lineSpacingExtra="6dp"
|
||||||
|
android:text="首次安装请打开名单列表从云端更新数据,后期适配的内容也请手动打开名单列表重新拉取数据以检查更新,数据更新后重启系统界面即可生效。"
|
||||||
|
android:textColor="@color/colorTextDark"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="@drawable/bg_permotion_round"
|
android:background="@drawable/bg_permotion_round"
|
||||||
android:baselineAligned="false"
|
android:baselineAligned="false"
|
||||||
|
android:descendantFocusability="blocksDescendants"
|
||||||
android:gravity="center|start"
|
android:gravity="center|start"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:padding="15dp"
|
android:padding="15dp"
|
||||||
|
54
app/src/main/res/layout/dia_source_from.xml
Normal file
54
app/src/main/res/layout/dia_source_from.xml
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingLeft="15dp"
|
||||||
|
android:paddingTop="15dp"
|
||||||
|
android:paddingRight="15dp"
|
||||||
|
tools:ignore="HardcodedText">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="8.5dp"
|
||||||
|
android:layout_marginRight="8.5dp"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:lineSpacingExtra="6dp"
|
||||||
|
android:text="在线规则将不定期更新,建议定期同步列表以适配更多 APP,若无法同步请自行寻找解决方法或魔法上网。"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||||
|
android:id="@+id/dia_sf_rd1"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="从 FastGit 获取" />
|
||||||
|
|
||||||
|
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||||
|
android:id="@+id/dia_sf_rd2"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="从 Github Raw 获取" />
|
||||||
|
|
||||||
|
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||||
|
android:id="@+id/dia_sf_rd3"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="从自定义地址获取" />
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/dia_sf_text_lin"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
|
android:id="@+id/dia_sf_text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:hint="请输入在线地址 URL"
|
||||||
|
android:singleLine="true" />
|
||||||
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
</LinearLayout>
|
25
app/src/main/res/layout/dia_source_from_string.xml
Normal file
25
app/src/main/res/layout/dia_source_from_string.xml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?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_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>
|
BIN
app/src/main/res/mipmap-xxhdpi/ic_sync.png
Normal file
BIN
app/src/main/res/mipmap-xxhdpi/ic_sync.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.0 KiB |
@@ -2,16 +2,13 @@ package com.fankes.miui.notify
|
|||||||
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
import org.junit.Assert.*
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Example local unit test, which will execute on the development machine (host).
|
* Example local unit test, which will execute on the development machine (host).
|
||||||
*
|
*
|
||||||
* See [testing documentation](http://d.android.com/tools/testing).
|
* See [testing documentation](http://d.android.com/tools/testing).
|
||||||
*/
|
*/
|
||||||
class ExampleUnitTest {
|
class ExampleUnitTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun addition_isCorrect() {
|
fun main() = println("Hello world")
|
||||||
assertEquals(4, 2 + 2)
|
|
||||||
}
|
|
||||||
}
|
}
|
@@ -1,12 +1,12 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id 'com.android.application' version '7.1.1' apply false
|
id 'com.android.application' version '7.1.2' apply false
|
||||||
id 'com.android.library' version '7.1.1' apply false
|
id 'com.android.library' version '7.1.2' apply false
|
||||||
id 'org.jetbrains.kotlin.android' version '1.6.10' apply false
|
id 'org.jetbrains.kotlin.android' version '1.6.10' apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
appVersionName = "1.7"
|
appVersionName = "1.9"
|
||||||
appVersionCode = 15
|
appVersionCode = 21
|
||||||
}
|
}
|
||||||
|
|
||||||
task clean(type: Delete) {
|
task clean(type: Delete) {
|
||||||
|
Reference in New Issue
Block a user