mirror of
https://github.com/fankes/MIUINativeNotifyIcon.git
synced 2025-09-06 02:35:32 +08:00
Compare commits
36 Commits
Author | SHA1 | Date | |
---|---|---|---|
90dda0aa52 | |||
4699eb137e | |||
ef47eef989 | |||
7a5df6457f | |||
3d977998c1 | |||
014e073af6 | |||
0be6b9c910 | |||
3816aab335 | |||
3b77a1cd82 | |||
5c5fae4ef6 | |||
ea665fdc30 | |||
740a250a59 | |||
f433da040c | |||
00bf1acdb8 | |||
099886b0b2 | |||
4109a25b5d | |||
db93f8d48e | |||
e6cff940a7 | |||
3f7ea97812 | |||
8f8810e92a | |||
e65624c044 | |||
eabac2bd2d | |||
bde952c72c | |||
|
3e362591b6 | ||
|
ea29c089f6 | ||
cff1eb1958 | |||
83c98b2ad3 | |||
0d7f323232 | |||
0d63b0a14d | |||
6684d7f376 | |||
89321af1ce | |||
d7a9f1e413 | |||
edf199d9a6 | |||
8d6a05e02c | |||
c7d9b2661b | |||
d0a32e08d9 |
2
.idea/gradle.xml
generated
2
.idea/gradle.xml
generated
@@ -7,13 +7,13 @@
|
||||
<option name="testRunner" value="GRADLE" />
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="gradleJvm" value="Embedded JDK" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/app" />
|
||||
</set>
|
||||
</option>
|
||||
<option name="resolveModulePerSourceSet" value="false" />
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
|
14
.idea/misc.xml
generated
14
.idea/misc.xml
generated
@@ -7,19 +7,27 @@
|
||||
<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_green_round.xml" value="0.255" />
|
||||
<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/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_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/adapter_config.xml" value="0.4375" />
|
||||
<entry key="app/src/main/res/layout/activity_main.xml" value="0.3448275862068966" />
|
||||
<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">
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
<br/><br/>
|
||||
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/app/src/main/ic_launcher-playstore.png" width = "100" height = "100"/>
|
||||
<br/>
|
||||
@@ -12,7 +12,7 @@ Fix the native notification bar icon function abandoned by the MIUI development
|
||||
# 开始使用
|
||||
|
||||
点击下载最新版本
|
||||
<a href='https://github.com/fankes/MIUINativeNotifyIcon/releases'></a>
|
||||
<a href='https://github.com/fankes/MIUINativeNotifyIcon/releases'></a>
|
||||
<br/><br/>
|
||||
⚠️ 适配说明<br/>
|
||||
|
||||
@@ -20,7 +20,7 @@ Fix the native notification bar icon function abandoned by the MIUI development
|
||||
- 请确保你使用的是 MIUI 官方版本,任何第三方官改包发生的问题,开发者没有义务去解决和修复,请自求多福
|
||||
- 目前最低支持基于 Android 9 版本的 MIUI 12 或 MIUI 12.5(最低建议)
|
||||
- 建议最低从 MIUI 12.5 `2021-5-18` 开发版以后开始使用模块,之前的版本可能或多或少存在 MIUI 自身 BUG 不生效、黑白块的问题
|
||||
- 请始终保持最新版本的 LSPosed,旧版本可能会出现 Hook 不生效的问题
|
||||
- 请始终保持最新版本的 LSPosed,旧版本可能会出现 Hook 不生效的问题,若最新版本依然不生效请在作用域中长按“系统界面”(“系统 UI”)选择重新优化
|
||||
|
||||
# 请勿用于非法用途
|
||||
|
||||
@@ -33,7 +33,7 @@ Fix the native notification bar icon function abandoned by the MIUI development
|
||||
|
||||
此项目是 `AndroidNotifyIconAdapt` 项目的一部分,详情请参考下方。<br/>
|
||||
|
||||
- [Android 通知图标规范适配](https://github.com/fankes/AndroidNotifyIconAdapt)
|
||||
- [Android 通知图标规范适配计划](https://github.com/fankes/AndroidNotifyIconAdapt)
|
||||
|
||||
# 历史背景
|
||||
|
||||
|
@@ -63,13 +63,11 @@ tasks.whenTaskAdded {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly 'de.robv.android.xposed:api:82'
|
||||
implementation 'com.highcapable.yukihookapi:api:1.0.4'
|
||||
ksp 'com.highcapable.yukihookapi:ksp-xposed:1.0.4'
|
||||
implementation "com.github.topjohnwu.libsu:core:3.1.2"
|
||||
implementation 'androidx.annotation:annotation:1.3.0'
|
||||
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1'
|
||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
|
||||
compileOnly 'de.robv.android.xposed:api:82'
|
||||
implementation 'com.highcapable.yukihookapi:api:1.0.2'
|
||||
ksp 'com.highcapable.yukihookapi:ksp-xposed:1.0.2'
|
||||
implementation 'com.geyifeng.immersionbar:immersionbar:3.2.0'
|
||||
implementation 'com.geyifeng.immersionbar:immersionbar-ktx:3.2.0'
|
||||
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
|
||||
|
@@ -20,7 +20,7 @@
|
||||
android:value="true" />
|
||||
<meta-data
|
||||
android:name="xposeddescription"
|
||||
android:value="MIUI 原生通知图标,修复 12.5、13 后期被破坏的彩色图标。\n开发者:酷安 @星夜不荟" />
|
||||
android:value="为金凡教我做事的 MIUI 修复 12.5、13 后期被破坏的彩色图标。\n开发者:酷安 @星夜不荟" />
|
||||
<meta-data
|
||||
android:name="xposedminversion"
|
||||
android:value="93" />
|
||||
|
@@ -36,15 +36,10 @@ class MNNApplication : Application() {
|
||||
|
||||
/** 调用全局静态实例 */
|
||||
val appContext get() = context ?: error("App is death")
|
||||
|
||||
/** 自身 APP 是否已启动 */
|
||||
var isMineStarted = false
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
/** 设置状态 */
|
||||
isMineStarted = true
|
||||
/** 设置静态实例 */
|
||||
context = this
|
||||
/** 跟随系统夜间模式 */
|
||||
|
@@ -23,7 +23,7 @@
|
||||
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
|
||||
|
||||
/**
|
||||
@@ -47,4 +47,13 @@ data class IconDataBean(
|
||||
) : 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" +
|
||||
" }"
|
||||
}
|
@@ -32,7 +32,16 @@ object HookConst {
|
||||
const val ENABLE_COLOR_ICON_HOOK = "_color_icon_hook"
|
||||
const val ENABLE_COLOR_ICON_COMPAT = "_color_icon_compat"
|
||||
const val ENABLE_NOTIFY_ICON_FIX = "_notify_icon_fix"
|
||||
const val ENABLE_HOOK_STATUS_ICON_COUNT = "_enable_hook_status_icon_count"
|
||||
const val NOTIFY_ICON_DATAS = "_notify_icon_datas"
|
||||
const val HOOK_STATUS_ICON_COUNT = "_hook_status_icon_count"
|
||||
|
||||
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"
|
||||
}
|
@@ -22,6 +22,7 @@
|
||||
*/
|
||||
package com.fankes.miui.notify.hook
|
||||
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Color
|
||||
@@ -31,21 +32,25 @@ import android.graphics.drawable.Icon
|
||||
import android.os.Build
|
||||
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 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_HOOK
|
||||
import com.fankes.miui.notify.hook.HookConst.ENABLE_HOOK_STATUS_ICON_COUNT
|
||||
import com.fankes.miui.notify.hook.HookConst.ENABLE_MODULE
|
||||
import com.fankes.miui.notify.hook.HookConst.ENABLE_MODULE_LOG
|
||||
import com.fankes.miui.notify.hook.HookConst.ENABLE_NOTIFY_ICON_FIX
|
||||
import com.fankes.miui.notify.hook.HookConst.HOOK_STATUS_ICON_COUNT
|
||||
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.*
|
||||
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.highcapable.yukihookapi.annotation.xposed.InjectYukiHookWithXposed
|
||||
import com.highcapable.yukihookapi.hook.bean.VariousClass
|
||||
import com.highcapable.yukihookapi.hook.factory.*
|
||||
@@ -55,6 +60,7 @@ import com.highcapable.yukihookapi.hook.param.PackageParam
|
||||
import com.highcapable.yukihookapi.hook.type.android.ContextClass
|
||||
import com.highcapable.yukihookapi.hook.type.android.DrawableClass
|
||||
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.xposed.proxy.YukiHookXposedInitProxy
|
||||
|
||||
@@ -73,6 +79,12 @@ class HookEntry : YukiHookXposedInitProxy {
|
||||
/** 原生存在的类 */
|
||||
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 val ExpandableNotificationRowClass = VariousClass(
|
||||
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.row.ExpandableNotificationRow",
|
||||
@@ -107,6 +119,13 @@ class HookEntry : YukiHookXposedInitProxy {
|
||||
/** 缓存的通知优化图标数组 */
|
||||
private var iconDatas = ArrayList<IconDataBean>()
|
||||
|
||||
/** 是否显示通知图标 - 跟随 Hook 保存 */
|
||||
private var isShowNotificationIcons = true
|
||||
|
||||
/** 是否有最大图标设置功能 */
|
||||
private val PackageParam.hasMaxStaticIcons
|
||||
get() = safeOfFalse { NotificationIconContainerClass.clazz.hasField(name = "MAX_STATIC_ICONS") }
|
||||
|
||||
/**
|
||||
* - 这个是修复彩色图标的关键核心代码判断
|
||||
*
|
||||
@@ -128,17 +147,6 @@ class HookEntry : YukiHookXposedInitProxy {
|
||||
}
|
||||
} else BitmapCompatTool.isGrayscaleDrawable(drawable)
|
||||
|
||||
/**
|
||||
* 是否为新版本 MIUI 方案
|
||||
*
|
||||
* 拥有状态栏图标颜色检查功能
|
||||
* @return [Boolean]
|
||||
*/
|
||||
private val PackageParam.hasIgnoreStatusBarIconColor
|
||||
get() = safeOfFalse {
|
||||
NotificationUtilClass.clazz.hasMethod(name = "ignoreStatusBarIconColor", ExpandedNotificationClass.clazz)
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为旧版本 MIUI 方案
|
||||
*
|
||||
@@ -259,11 +267,31 @@ class HookEntry : YukiHookXposedInitProxy {
|
||||
*/
|
||||
private val PackageParam.globalContext
|
||||
get() = safeOfNull {
|
||||
if (SystemUIApplicationClass.clazz.hasMethod(name = "getContext"))
|
||||
SystemUIApplicationClass.clazz.method { name = "getContext" }.get().invoke<Context>()
|
||||
else null
|
||||
SystemUIApplicationClass.clazz.method { name = "getContext" }.ignoredError().get().invoke<Context>()
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动适配状态栏、通知栏自定义小图标
|
||||
* @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 状态栏小图标
|
||||
*
|
||||
@@ -278,38 +306,27 @@ class HookEntry : YukiHookXposedInitProxy {
|
||||
expandedNf: StatusBarNotification?,
|
||||
iconDrawable: Drawable?,
|
||||
it: (Bitmap) -> Unit
|
||||
) = safeRun(msg = "GetSmallIconOnSet") {
|
||||
if (iconDrawable == null) return@safeRun
|
||||
) = runSafe(msg = "GetSmallIconOnSet") {
|
||||
if (iconDrawable == null) return@runSafe
|
||||
/** 如果没开启修复 APP 的彩色图标 */
|
||||
if (!prefs.getBoolean(ENABLE_COLOR_ICON_HOOK, default = true)) return@safeRun
|
||||
if (!prefs.getBoolean(ENABLE_COLOR_ICON_HOOK, default = true)) return@runSafe
|
||||
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
|
||||
expandedNf?.also { notifyInstance ->
|
||||
/** 判断是 MIUI 样式就停止 Hook */
|
||||
if (context.isMiuiNotifyStyle) {
|
||||
it(notifyInstance.findAppIcon(context).toBitmap())
|
||||
return@safeRun
|
||||
return@runSafe
|
||||
}
|
||||
/** 判断是否不是灰度图标 */
|
||||
val isNotGrayscaleIcon = notifyInstance.isXmsf || !isGrayscaleIcon(context, iconDrawable)
|
||||
|
||||
/** 目标彩色通知 APP 图标 */
|
||||
var customIcon: Bitmap? = null
|
||||
if (prefs.getBoolean(ENABLE_NOTIFY_ICON_FIX, default = true))
|
||||
run {
|
||||
if (iconDatas.isNotEmpty())
|
||||
iconDatas.forEach {
|
||||
if (notifyInstance.opPkgName == it.packageName && isAppNotifyHookOf(it)) {
|
||||
if (isNotGrayscaleIcon || isAppNotifyHookAllOf(it))
|
||||
customIcon = it.iconBitmap
|
||||
return@run
|
||||
}
|
||||
}
|
||||
}
|
||||
val customIcon = compatCustomIcon(!isNotGrayscaleIcon, notifyInstance.opPkgName).first
|
||||
/** 打印日志 */
|
||||
printLogcat(tag = "StatusIcon", context, notifyInstance, isCustom = customIcon != null, !isNotGrayscaleIcon)
|
||||
when {
|
||||
/** 处理自定义通知图标优化 */
|
||||
customIcon != null -> it(customIcon!!)
|
||||
customIcon != null -> it(customIcon)
|
||||
/** 若不是灰度图标自动处理为圆角 */
|
||||
isNotGrayscaleIcon -> it(notifyInstance.compatNotifyIcon(context, iconDrawable).toBitmap())
|
||||
}
|
||||
@@ -323,118 +340,112 @@ class HookEntry : YukiHookXposedInitProxy {
|
||||
* @param context 实例
|
||||
* @param expandedNf 通知实例
|
||||
* @param iconImageView 通知图标实例
|
||||
* @param isExpanded 通知是否展开 - 可做最小化通知处理
|
||||
*/
|
||||
private fun PackageParam.hookNotifyIconOnSet(context: Context, expandedNf: StatusBarNotification?, iconImageView: ImageView) =
|
||||
safeRun(msg = "AutoSetAppIconOnSet") {
|
||||
/** 判断是 MIUI 样式就停止 Hook */
|
||||
if (context.isMiuiNotifyStyle) return@safeRun
|
||||
/** 如果没开启修复 APP 的彩色图标 */
|
||||
if (!prefs.getBoolean(ENABLE_COLOR_ICON_HOOK, default = true)) return@safeRun
|
||||
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
|
||||
expandedNf?.let { notifyInstance ->
|
||||
/** 是否开启修复 APP 的彩色图标 */
|
||||
val isNotifyIconFix = prefs.getBoolean(ENABLE_NOTIFY_ICON_FIX, default = true)
|
||||
private fun PackageParam.hookNotifyIconOnSet(
|
||||
context: Context,
|
||||
expandedNf: StatusBarNotification?,
|
||||
iconImageView: ImageView,
|
||||
isExpanded: Boolean
|
||||
) = runSafe(msg = "AutoSetAppIconOnSet") {
|
||||
/** 判断是 MIUI 样式就停止 Hook */
|
||||
if (context.isMiuiNotifyStyle) return@runSafe
|
||||
/** 如果没开启修复 APP 的彩色图标 */
|
||||
if (!prefs.getBoolean(ENABLE_COLOR_ICON_HOOK, default = true)) return@runSafe
|
||||
/** 获取通知对象 - 由于 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 {
|
||||
when {
|
||||
isUpperOfAndroidS -> newStyle
|
||||
it == 0 -> oldStyle
|
||||
else -> it
|
||||
}
|
||||
/** 通知图标适配颜色 */
|
||||
val supportColor = iconColor.let {
|
||||
when {
|
||||
isUpperOfAndroidS -> newStyle
|
||||
it == 0 || !isExpanded -> oldStyle
|
||||
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
|
||||
|
||||
if (isNotifyIconFix) run {
|
||||
if (iconDatas.isNotEmpty())
|
||||
iconDatas.forEach {
|
||||
if (notifyInstance.opPkgName == it.packageName && isAppNotifyHookOf(it)) {
|
||||
if (!isGrayscaleIcon || isAppNotifyHookAllOf(it)) {
|
||||
customIcon = it.iconBitmap
|
||||
customIconColor = it.iconColor
|
||||
return@run
|
||||
}
|
||||
}
|
||||
}
|
||||
/** 自定义默认小图标颜色 */
|
||||
var customIconColor: Int
|
||||
compatCustomIcon(isGrayscaleIcon, notifyInstance.opPkgName).also {
|
||||
customIcon = it.first
|
||||
customIconColor = if (isUpperOfAndroidS || isExpanded) it.second else 0
|
||||
}
|
||||
/** 打印日志 */
|
||||
printLogcat(tag = "NotifyIcon", context, notifyInstance, isCustom = customIcon != null, isGrayscaleIcon)
|
||||
/** 处理自定义通知图标优化 */
|
||||
if (customIcon != null)
|
||||
iconImageView.apply {
|
||||
/** 设置自定义小图标 */
|
||||
setImageBitmap(customIcon)
|
||||
/** 上色 */
|
||||
setColorFilter(if (isUpperOfAndroidS || customIconColor == 0) supportColor else customIconColor)
|
||||
/** Android 12 设置图标外圈颜色 */
|
||||
if (isUpperOfAndroidS && customIconColor != 0)
|
||||
background = DrawableBuilder().rounded().solidColor(customIconColor).build()
|
||||
}
|
||||
/** 打印日志 */
|
||||
printLogcat(tag = "NotifyIcon", context, notifyInstance, isCustom = customIcon != null, isGrayscaleIcon)
|
||||
/** 处理自定义通知图标优化 */
|
||||
if (customIcon != null)
|
||||
iconImageView.apply {
|
||||
/** 设置自定义小图标 */
|
||||
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)
|
||||
)
|
||||
}
|
||||
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
|
||||
}
|
||||
/** 清除原生的背景边距设置 */
|
||||
if (isUpperOfAndroidS) setPadding(0, 0, 0, 0)
|
||||
/** 清除原生的主题色背景圆圈颜色 */
|
||||
if (isUpperOfAndroidS) background = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook 通知栏小图标颜色
|
||||
* 判断状态栏小图标颜色以及反射的核心方法
|
||||
*
|
||||
* 区分系统版本 - 由于每个系统版本的方法不一样这里单独拿出来进行 Hook
|
||||
* @param context 实例
|
||||
* @param expandedNf 状态栏实例
|
||||
* @return [Boolean] 是否忽略通知图标颜色
|
||||
*/
|
||||
private fun PackageParam.hookIgnoreStatusBarIconColor(context: Context, expandedNf: StatusBarNotification?) =
|
||||
private fun PackageParam.hasIgnoreStatusBarIconColor(context: Context, expandedNf: StatusBarNotification?) =
|
||||
if (!context.isMiuiNotifyStyle)
|
||||
if (prefs.getBoolean(ENABLE_COLOR_ICON_HOOK, default = true)) safeOfFalse {
|
||||
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
|
||||
@@ -446,32 +457,31 @@ class HookEntry : YukiHookXposedInitProxy {
|
||||
val isNotGrayscaleIcon = notifyInstance.isXmsf || !isGrayscaleIcon(context, iconDrawable)
|
||||
|
||||
/** 获取目标修复彩色图标的 APP */
|
||||
var isTargetFixApp = false
|
||||
/** 如果开启了自定义通知图标优化 */
|
||||
if (prefs.getBoolean(ENABLE_NOTIFY_ICON_FIX, default = true))
|
||||
run {
|
||||
if (iconDatas.isNotEmpty())
|
||||
iconDatas.forEach {
|
||||
if (notifyInstance.opPkgName == it.packageName && isAppNotifyHookOf(it)) {
|
||||
if (isNotGrayscaleIcon || isAppNotifyHookAllOf(it)) isTargetFixApp = true
|
||||
return@run
|
||||
}
|
||||
}
|
||||
}
|
||||
val isTargetFixApp = compatCustomIcon(!isNotGrayscaleIcon, notifyInstance.opPkgName).first != null
|
||||
/**
|
||||
* 只要不是灰度就返回彩色图标
|
||||
* 否则不对颜色进行反色处理防止一些系统图标出现异常
|
||||
*/
|
||||
if (isTargetFixApp) false else isNotGrayscaleIcon
|
||||
} ?: true
|
||||
} else false
|
||||
else true
|
||||
(if (isTargetFixApp) false else isNotGrayscaleIcon).also {
|
||||
printLogcat(tag = "IconColor", context, expandedNf, isTargetFixApp, !isNotGrayscaleIcon)
|
||||
}
|
||||
} ?: true.also { printLogcat(tag = "IconColor", context, expandedNf = null, isCustom = false, isGrayscale = false) }
|
||||
} else false.also { printLogcat(tag = "IconColor", context, expandedNf, isCustom = false, isGrayscale = true) }
|
||||
else true.also { printLogcat(tag = "IconColor", context, expandedNf, isCustom = false, isGrayscale = false) }
|
||||
|
||||
override fun onHook() = encase {
|
||||
configs {
|
||||
debugTag = "MIUINativeNotifyIcon"
|
||||
isDebug = false
|
||||
}
|
||||
override fun onHook() {
|
||||
runConfig()
|
||||
runHook()
|
||||
}
|
||||
|
||||
/** 配置 Hook */
|
||||
private fun runConfig() = configs {
|
||||
debugTag = "MIUINativeNotifyIcon"
|
||||
isDebug = false
|
||||
}
|
||||
|
||||
/** 开始 Hook */
|
||||
private fun runHook() = encase {
|
||||
loadApp(SYSTEMUI_PACKAGE_NAME) {
|
||||
when {
|
||||
/** 不是 MIUI 系统停止 Hook */
|
||||
@@ -500,19 +510,6 @@ class HookEntry : YukiHookXposedInitProxy {
|
||||
*/
|
||||
replaceAny { globalContext?.isMiuiNotifyStyle ?: isShowMiuiStyle }
|
||||
}
|
||||
if (hasIgnoreStatusBarIconColor)
|
||||
injectMember {
|
||||
method {
|
||||
name = "ignoreStatusBarIconColor"
|
||||
param(ExpandedNotificationClass.clazz)
|
||||
}
|
||||
replaceAny {
|
||||
hookIgnoreStatusBarIconColor(
|
||||
context = globalContext ?: error("GlobalContext got null"),
|
||||
expandedNf = args[0] as? StatusBarNotification?
|
||||
)
|
||||
}
|
||||
}
|
||||
/** 强制回写系统的状态栏图标样式为原生 */
|
||||
injectMember {
|
||||
var isUseLegacy = false
|
||||
@@ -530,7 +527,7 @@ class HookEntry : YukiHookXposedInitProxy {
|
||||
}.onFind { isUseLegacy = true }
|
||||
}
|
||||
afterHook {
|
||||
(globalContext ?: args[0] as Context).also { context ->
|
||||
(globalContext ?: firstArgs as Context).also { context ->
|
||||
hookSmallIconOnSet(
|
||||
context = context,
|
||||
args[if (isUseLegacy) 1 else 0] as? StatusBarNotification?,
|
||||
@@ -540,6 +537,58 @@ class HookEntry : YukiHookXposedInitProxy {
|
||||
}
|
||||
}
|
||||
}
|
||||
StatusBarIconViewClass.hook {
|
||||
/** Hook 状态栏图标的颜色 */
|
||||
injectMember {
|
||||
method { name = "updateIconColor" }
|
||||
afterHook {
|
||||
instance<ImageView>().also {
|
||||
if (hasIgnoreStatusBarIconColor(it.context, field { name = "mNotification" }
|
||||
.of<StatusBarNotification>(instance))) it.colorFilter = null
|
||||
/** 防止图标不是纯黑的问题 */
|
||||
else it.setColorFilter(
|
||||
field { name = "mCurrentSetColor" }.of<Int>(instance)
|
||||
?.let { color -> if (color == -419430401) color else Color.BLACK } ?: 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasMaxStaticIcons)
|
||||
NotificationIconContainerClass.hook {
|
||||
injectMember {
|
||||
method { name = "calculateIconTranslations" }
|
||||
afterHook {
|
||||
/** 修复最新开发版状态栏图标只能显示一个的问题 */
|
||||
instance<ViewGroup>().layoutParams.width = 9999
|
||||
}
|
||||
}
|
||||
injectMember {
|
||||
method { name = "updateState" }
|
||||
beforeHook {
|
||||
/** 解除状态栏通知图标个数限制 */
|
||||
if (isShowNotificationIcons && prefs.getBoolean(ENABLE_HOOK_STATUS_ICON_COUNT, default = true))
|
||||
field { name = "MAX_STATIC_ICONS" }
|
||||
.get(instance).set(prefs.getInt(HOOK_STATUS_ICON_COUNT, default = 5)
|
||||
.let { if (it in 0..100) it else 5 })
|
||||
}
|
||||
}
|
||||
/** 旧版方法 - 新版不存在 */
|
||||
injectMember {
|
||||
method {
|
||||
name = "setMaxStaticIcons"
|
||||
param(IntType)
|
||||
beforeHook { isShowNotificationIcons = firstArgs as Int > 0 }
|
||||
}
|
||||
}.ignoredHookingFailure()
|
||||
/** 新版方法 - 旧版不存在 */
|
||||
injectMember {
|
||||
method {
|
||||
name = "miuiShowNotificationIcons"
|
||||
param(BooleanType)
|
||||
}
|
||||
beforeHook { isShowNotificationIcons = firstArgs as Boolean }
|
||||
}.ignoredHookingFailure()
|
||||
}
|
||||
NotificationHeaderViewWrapperClass.hook {
|
||||
/** 修复下拉通知图标自动设置回 APP 图标的方法 */
|
||||
injectMember {
|
||||
@@ -552,6 +601,9 @@ class HookEntry : YukiHookXposedInitProxy {
|
||||
NotificationHeaderViewWrapperClass.clazz
|
||||
.field { name = "mIcon" }.of<ImageView>(instance) ?: return@afterHook
|
||||
|
||||
/** 通知是否展开 */
|
||||
var isExpanded = false
|
||||
|
||||
/**
|
||||
* 从父类中得到 mRow 变量 - [ExpandableNotificationRowClass]
|
||||
* 获取其中的得到通知方法
|
||||
@@ -560,7 +612,12 @@ class HookEntry : YukiHookXposedInitProxy {
|
||||
.method { name = "getEntry" }
|
||||
.get(NotificationViewWrapperClass.clazz.field {
|
||||
name = "mRow"
|
||||
}.get(instance).self).call()?.let {
|
||||
}.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>()
|
||||
@@ -568,8 +625,15 @@ class HookEntry : YukiHookXposedInitProxy {
|
||||
.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)
|
||||
hookNotifyIconOnSet(iconImageView.context, expandedNf, iconImageView, isExpanded)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -586,15 +650,15 @@ class HookEntry : YukiHookXposedInitProxy {
|
||||
}
|
||||
}
|
||||
intercept()
|
||||
}.ignoredAllFailure()
|
||||
}.ignoredHookingFailure()
|
||||
injectMember {
|
||||
method {
|
||||
name = "resetIconBgAndPaddings"
|
||||
param(ImageViewClass, ExpandedNotificationClass.clazz)
|
||||
}
|
||||
intercept()
|
||||
}.ignoredAllFailure()
|
||||
}
|
||||
}.ignoredHookingFailure()
|
||||
}.ignoredHookClassNotFoundFailure()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -20,15 +20,15 @@
|
||||
*
|
||||
* 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.hook.HookConst.NOTIFY_ICON_DATAS
|
||||
import com.fankes.miui.notify.utils.bitmap
|
||||
import com.fankes.miui.notify.utils.safeOf
|
||||
import com.fankes.miui.notify.utils.safeOfNan
|
||||
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
|
||||
@@ -47,7 +47,7 @@ class IconPackParams(private val context: Context? = null, private val param: Pa
|
||||
* 已存储的 JSON 数据
|
||||
* @return [String]
|
||||
*/
|
||||
private val storageDataJson get() = (context?.modulePrefs ?: param?.prefs)?.getString(NOTIFY_ICON_DATAS)
|
||||
internal val storageDataJson get() = (context?.modulePrefs ?: param?.prefs)?.getString(NOTIFY_ICON_DATAS)
|
||||
|
||||
/**
|
||||
* 获取图标数据
|
||||
@@ -56,27 +56,35 @@ class IconPackParams(private val context: Context? = null, private val param: Pa
|
||||
val iconDatas
|
||||
get() = ArrayList<IconDataBean>().apply {
|
||||
storageDataJson?.also {
|
||||
if (it.isNotBlank())
|
||||
if (it.isNotBlank()) runCatching {
|
||||
JSONArray(it).also { array ->
|
||||
for (i in 0 until array.length()) runCatching {
|
||||
(array.get(i) as JSONObject).apply {
|
||||
add(
|
||||
IconDataBean(
|
||||
appName = getString("appName"),
|
||||
packageName = getString("packageName"),
|
||||
isEnabled = getBoolean("isEnabled"),
|
||||
isEnabledAll = getBoolean("isEnabledAll"),
|
||||
iconBitmap = getString("iconBitmap").bitmap,
|
||||
iconColor = safeOfNan { Color.parseColor(getString("iconColor")) },
|
||||
contributorName = getString("contributorName")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
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(
|
||||
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
|
||||
@@ -87,6 +95,34 @@ class IconPackParams(private val context: Context? = null, private val param: Pa
|
||||
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
|
||||
|
@@ -25,8 +25,6 @@
|
||||
package com.fankes.miui.notify.ui
|
||||
|
||||
import android.app.ProgressDialog
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
@@ -36,17 +34,27 @@ import android.widget.ListView
|
||||
import android.widget.TextView
|
||||
import androidx.constraintlayout.utils.widget.ImageFilterView
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
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.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.base.BaseActivity
|
||||
import com.fankes.miui.notify.utils.*
|
||||
import com.fankes.miui.notify.utils.factory.*
|
||||
import com.fankes.miui.notify.utils.tool.ClientRequestTool
|
||||
import com.fankes.miui.notify.utils.tool.SystemUITool
|
||||
import com.fankes.miui.notify.view.MaterialSwitch
|
||||
import com.google.android.material.radiobutton.MaterialRadioButton
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import com.highcapable.yukihookapi.hook.factory.modulePrefs
|
||||
import com.highcapable.yukihookapi.hook.xposed.YukiHookModuleStatus
|
||||
|
||||
class ConfigureActivity : BaseActivity() {
|
||||
@@ -187,21 +195,23 @@ class ConfigureActivity : BaseActivity() {
|
||||
lateinit var switchOpen: 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) } }
|
||||
}
|
||||
/** 设置点击事件 */
|
||||
findViewById<View>(R.id.config_cbr_button).setOnClickListener {
|
||||
runCatching {
|
||||
startActivity(Intent().apply {
|
||||
action = "android.intent.action.VIEW"
|
||||
data = Uri.parse("https://github.com/fankes/AndroidNotifyIconAdapt/blob/main/CONTRIBUTING.md")
|
||||
/** 防止顶栈一样重叠在自己的 APP 中 */
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
})
|
||||
}.onFailure {
|
||||
toast(msg = "无法启动系统默认浏览器")
|
||||
}
|
||||
openBrowser(url = "https://github.com/fankes/AndroidNotifyIconAdapt/blob/main/CONTRIBUTING.md")
|
||||
}
|
||||
/** 装载数据 */
|
||||
mockLocalData()
|
||||
@@ -218,16 +228,119 @@ class ConfigureActivity : BaseActivity() {
|
||||
/** 首次进入或更新数据 */
|
||||
private fun onStartRefresh() =
|
||||
showDialog {
|
||||
title = if (iconAllDatas.isNotEmpty()) "同步列表" else "初始化"
|
||||
msg = (if (iconAllDatas.isNotEmpty()) "建议定期从云端拉取数据以获得最新的通知图标优化名单适配数据。\n\n"
|
||||
else "首次装载需要从云端下载最新适配数据,后续可继续前往这里检查更新。\n\n") +
|
||||
"通过从 Github 同步最新数据,无法连接可能需要魔法上网。"
|
||||
confirmButton(text = "开始同步") { onRefreshing() }
|
||||
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()
|
||||
}
|
||||
}
|
||||
IconPackParams(context = this@ConfigureActivity).also { params ->
|
||||
confirmButton(text = "合并") {
|
||||
editText.text.toString().also { jsonString ->
|
||||
when {
|
||||
jsonString.isNotBlank() && params.isNotVaildJson(jsonString) -> snake(msg = "不是有效的 JSON 数据")
|
||||
jsonString.isNotBlank() -> {
|
||||
params.save(
|
||||
params.splicingJsonArray(
|
||||
dataJson1 = params.storageDataJson ?: "[]",
|
||||
dataJson2 = jsonString.takeIf { params.isJsonArray(it) } ?: "[$jsonString]"
|
||||
)
|
||||
)
|
||||
filterText = ""
|
||||
mockLocalData()
|
||||
SystemUITool.showNeedUpdateApplySnake(context = this@ConfigureActivity)
|
||||
}
|
||||
else -> snake(msg = "请输入有效内容")
|
||||
}
|
||||
}
|
||||
}
|
||||
cancelButton(text = "覆盖") {
|
||||
editText.text.toString().also { jsonString ->
|
||||
when {
|
||||
jsonString.isNotBlank() && params.isNotVaildJson(jsonString) -> snake(msg = "不是有效的 JSON 数据")
|
||||
jsonString.isNotBlank() -> {
|
||||
params.save(dataJson = jsonString.takeIf { params.isJsonArray(it) } ?: "[$jsonString]")
|
||||
filterText = ""
|
||||
mockLocalData()
|
||||
SystemUITool.showNeedUpdateApplySnake(context = this@ConfigureActivity)
|
||||
}
|
||||
else -> snake(msg = "请输入有效内容")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
neutralButton(text = "取消")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 开始更新数据 */
|
||||
private fun onRefreshing() {
|
||||
/**
|
||||
* 开始更新数据
|
||||
* @param url
|
||||
*/
|
||||
private fun onRefreshing(url: String) = ClientRequestTool.checkingInternetConnect(context = this) {
|
||||
ProgressDialog(this).apply {
|
||||
setDefaultStyle(context = this@ConfigureActivity)
|
||||
setCancelable(false)
|
||||
@@ -237,28 +350,75 @@ class ConfigureActivity : BaseActivity() {
|
||||
}.also {
|
||||
ClientRequestTool.wait(
|
||||
context = this,
|
||||
url = "https://raw.githubusercontent.com/fankes/AndroidNotifyIconAdapt/main/OS/MIUI/NotifyIconsSupportConfig.json"
|
||||
url = "$url/OS/MIUI/NotifyIconsSupportConfig.json"
|
||||
) { isDone1, ctOS ->
|
||||
it.setMessage("正在同步 APP 数据")
|
||||
ClientRequestTool.wait(
|
||||
context = this,
|
||||
url = "https://raw.githubusercontent.com/fankes/AndroidNotifyIconAdapt/main/APP/NotifyIconsSupportConfig.json"
|
||||
url = "$url/APP/NotifyIconsSupportConfig.json"
|
||||
) { isDone2, ctAPP ->
|
||||
it.cancel()
|
||||
IconPackParams(context = this).also { params ->
|
||||
if (isDone1 && isDone2) params.splicingJsonArray(ctOS, ctAPP).also {
|
||||
if (params.isCompareDifferent(it)) {
|
||||
params.save(it)
|
||||
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${if (!isDone1) ctOS else ctAPP}"
|
||||
confirmButton(text = "我知道了")
|
||||
}
|
||||
else -> snake(msg = "列表数据已是最新")
|
||||
}
|
||||
else showDialog {
|
||||
title = "连接失败"
|
||||
msg = "连接失败,错误如下:\n$content"
|
||||
confirmButton(text = "我知道了")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -286,4 +446,4 @@ class ConfigureActivity : BaseActivity() {
|
||||
else iconAllDatas.filter {
|
||||
it.appName.lowercase().contains(filterText.lowercase()) || it.packageName.lowercase().contains(filterText.lowercase())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -27,24 +27,28 @@ 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 androidx.appcompat.widget.SwitchCompat
|
||||
import androidx.constraintlayout.utils.widget.ImageFilterView
|
||||
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.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_HIDE_ICON
|
||||
import com.fankes.miui.notify.hook.HookConst.ENABLE_HOOK_STATUS_ICON_COUNT
|
||||
import com.fankes.miui.notify.hook.HookConst.ENABLE_MODULE
|
||||
import com.fankes.miui.notify.hook.HookConst.ENABLE_MODULE_LOG
|
||||
import com.fankes.miui.notify.hook.HookConst.ENABLE_NOTIFY_ICON_FIX
|
||||
import com.fankes.miui.notify.hook.HookConst.HOOK_STATUS_ICON_COUNT
|
||||
import com.fankes.miui.notify.ui.base.BaseActivity
|
||||
import com.fankes.miui.notify.utils.*
|
||||
import com.fankes.miui.notify.utils.factory.*
|
||||
import com.fankes.miui.notify.utils.tool.SystemUITool
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import com.highcapable.yukihookapi.hook.factory.modulePrefs
|
||||
import com.highcapable.yukihookapi.hook.xposed.YukiHookModuleStatus
|
||||
|
||||
@@ -62,8 +66,8 @@ class MainActivity : BaseActivity() {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
/** 设置文本 */
|
||||
findViewById<TextView>(R.id.main_text_version).text = "当前版本:$moduleVersion"
|
||||
findViewById<TextView>(R.id.main_text_miui_version).text = "MIUI 版本:$miuiFullVersion"
|
||||
findViewById<TextView>(R.id.main_text_version).text = "模块版本:$moduleVersion"
|
||||
findViewById<TextView>(R.id.main_text_miui_version).text = "系统版本:$miuiFullVersion"
|
||||
when {
|
||||
/** 判断是否为 MIUI 系统 */
|
||||
isNotMIUI ->
|
||||
@@ -108,6 +112,10 @@ class MainActivity : BaseActivity() {
|
||||
/** 初始化 View */
|
||||
val moduleEnableSwitch = findViewById<SwitchCompat>(R.id.module_enable_switch)
|
||||
val moduleEnableLogSwitch = findViewById<SwitchCompat>(R.id.module_enable_log_switch)
|
||||
val statusIconCountItem = findViewById<View>(R.id.config_item_s_count_hook)
|
||||
val statusIconCountChildItem = findViewById<View>(R.id.config_item_s_count_child_hook)
|
||||
val statusIconCountSwitch = findViewById<SwitchCompat>(R.id.config_status_icon_count_switch)
|
||||
val statusIconCountText = findViewById<TextView>(R.id.config_status_icon_count_text)
|
||||
val colorIconHookItem = findViewById<View>(R.id.config_item_color_hook)
|
||||
val notifyIconConfigItem = findViewById<View>(R.id.config_item_notify)
|
||||
val hideIconInLauncherSwitch = findViewById<SwitchCompat>(R.id.hide_icon_in_launcher_switch)
|
||||
@@ -116,25 +124,31 @@ class MainActivity : BaseActivity() {
|
||||
val colorIconCompatText = findViewById<View>(R.id.color_icon_compat_text)
|
||||
val notifyIconFixSwitch = findViewById<SwitchCompat>(R.id.notify_icon_fix_switch)
|
||||
val notifyIconFixButton = findViewById<View>(R.id.config_notify_app_button)
|
||||
|
||||
/** 获取 Sp 存储的信息 */
|
||||
var statusBarIconCount = modulePrefs.getInt(HOOK_STATUS_ICON_COUNT, default = 5)
|
||||
colorIconHookItem.isVisible = modulePrefs.getBoolean(ENABLE_MODULE, default = true)
|
||||
statusIconCountItem.isVisible = modulePrefs.getBoolean(ENABLE_MODULE, default = true)
|
||||
colorIconCompatSwitch.isVisible = modulePrefs.getBoolean(ENABLE_COLOR_ICON_HOOK, default = true)
|
||||
colorIconCompatText.isVisible = modulePrefs.getBoolean(ENABLE_COLOR_ICON_HOOK, default = true)
|
||||
notifyIconConfigItem.isVisible = modulePrefs.getBoolean(ENABLE_MODULE, default = true) &&
|
||||
modulePrefs.getBoolean(ENABLE_COLOR_ICON_HOOK, default = true)
|
||||
moduleEnableLogSwitch.isVisible = modulePrefs.getBoolean(ENABLE_MODULE, default = true)
|
||||
notifyIconFixButton.isVisible = modulePrefs.getBoolean(ENABLE_NOTIFY_ICON_FIX, default = true)
|
||||
statusIconCountSwitch.isChecked = modulePrefs.getBoolean(ENABLE_HOOK_STATUS_ICON_COUNT, default = true)
|
||||
statusIconCountChildItem.isVisible = modulePrefs.getBoolean(ENABLE_HOOK_STATUS_ICON_COUNT, default = true)
|
||||
moduleEnableSwitch.isChecked = modulePrefs.getBoolean(ENABLE_MODULE, default = true)
|
||||
moduleEnableLogSwitch.isChecked = modulePrefs.getBoolean(ENABLE_MODULE_LOG, default = false)
|
||||
hideIconInLauncherSwitch.isChecked = modulePrefs.getBoolean(ENABLE_HIDE_ICON)
|
||||
colorIconHookSwitch.isChecked = modulePrefs.getBoolean(ENABLE_COLOR_ICON_HOOK, default = true)
|
||||
colorIconCompatSwitch.isChecked = modulePrefs.getBoolean(ENABLE_COLOR_ICON_COMPAT)
|
||||
notifyIconFixSwitch.isChecked = modulePrefs.getBoolean(ENABLE_NOTIFY_ICON_FIX, default = true)
|
||||
statusIconCountText.text = statusBarIconCount.toString()
|
||||
moduleEnableSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
if (!btn.isPressed) return@setOnCheckedChangeListener
|
||||
modulePrefs.putBoolean(ENABLE_MODULE, b)
|
||||
moduleEnableLogSwitch.isVisible = b
|
||||
colorIconHookItem.isVisible = b
|
||||
statusIconCountItem.isVisible = b
|
||||
notifyIconConfigItem.isVisible = b && colorIconHookSwitch.isChecked
|
||||
SystemUITool.showNeedRestartSnake(context = this)
|
||||
}
|
||||
@@ -152,6 +166,12 @@ class MainActivity : BaseActivity() {
|
||||
PackageManager.DONT_KILL_APP
|
||||
)
|
||||
}
|
||||
statusIconCountSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
if (!btn.isPressed) return@setOnCheckedChangeListener
|
||||
modulePrefs.putBoolean(ENABLE_HOOK_STATUS_ICON_COUNT, b)
|
||||
statusIconCountChildItem.isVisible = b
|
||||
SystemUITool.showNeedRestartSnake(context = this)
|
||||
}
|
||||
colorIconHookSwitch.setOnCheckedChangeListener { btn, b ->
|
||||
if (!btn.isPressed) return@setOnCheckedChangeListener
|
||||
modulePrefs.putBoolean(ENABLE_COLOR_ICON_HOOK, b)
|
||||
@@ -173,34 +193,46 @@ class MainActivity : BaseActivity() {
|
||||
}
|
||||
/** 通知图标优化名单按钮点击事件 */
|
||||
notifyIconFixButton.setOnClickListener { startActivity(Intent(this, ConfigureActivity::class.java)) }
|
||||
/** 重启按钮点击事件 */
|
||||
findViewById<View>(R.id.title_restart_icon).setOnClickListener { SystemUITool.restartSystemUI(context = this) }
|
||||
/** 恰饭! */
|
||||
findViewById<View>(R.id.link_with_follow_me).setOnClickListener {
|
||||
runCatching {
|
||||
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.config_warn_s_count_dis_tip).isGone = miuiVersionCode > 12.5
|
||||
/** 修改状态栏通知图标个数按钮点击事件 */
|
||||
findViewById<View>(R.id.config_status_icon_count_button).setOnClickListener {
|
||||
showDialog {
|
||||
title = "设置最多显示的图标个数"
|
||||
var editText: TextInputEditText
|
||||
addView(R.layout.dia_status_icon_count).apply {
|
||||
editText = findViewById<TextInputEditText>(R.id.dia_status_icon_count_input_edit).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.putInt(HOOK_STATUS_ICON_COUNT, statusBarIconCount)
|
||||
statusIconCountText.text = statusBarIconCount.toString()
|
||||
SystemUITool.showNeedRestartSnake(context = this@MainActivity)
|
||||
}.onFailure { snake(msg = "数值格式无效") }
|
||||
else -> snake(msg = "请输入有效数值")
|
||||
}
|
||||
}
|
||||
cancelButton()
|
||||
}
|
||||
}
|
||||
/** 项目地址点击事件 */
|
||||
findViewById<View>(R.id.link_with_project_address).setOnClickListener {
|
||||
runCatching {
|
||||
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 = "无法启动系统默认浏览器")
|
||||
}
|
||||
/** 重启按钮点击事件 */
|
||||
findViewById<View>(R.id.title_restart_icon).setOnClickListener { SystemUITool.restartSystemUI(context = this) }
|
||||
/** 项目地址按钮点击事件 */
|
||||
findViewById<View>(R.id.title_github_icon).setOnClickListener {
|
||||
openBrowser(url = "https://github.com/fankes/MIUINativeNotifyIcon")
|
||||
}
|
||||
/** 恰饭! */
|
||||
findViewById<View>(R.id.link_with_follow_me).setOnClickListener {
|
||||
openBrowser(url = "https://www.coolapk.com/u/876977", packageName = "com.coolapk.market")
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -25,7 +25,7 @@ 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.utils.isNotSystemInDarkMode
|
||||
import com.fankes.miui.notify.utils.factory.isNotSystemInDarkMode
|
||||
import com.gyf.immersionbar.ktx.immersionBar
|
||||
|
||||
abstract class BaseActivity : AppCompatActivity() {
|
||||
|
@@ -22,7 +22,7 @@
|
||||
*/
|
||||
@file:Suppress("unused", "DEPRECATION")
|
||||
|
||||
package com.fankes.miui.notify.utils
|
||||
package com.fankes.miui.notify.utils.factory
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.content.Context
|
@@ -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.runSafe(msg: String = "", block: () -> Unit) {
|
||||
runCatching(block).onFailure { if (msg.isNotBlank()) loggerE(msg = msg, e = it) }
|
||||
}
|
@@ -22,11 +22,14 @@
|
||||
*/
|
||||
@file:Suppress("DEPRECATION", "PrivateApi", "unused", "ObsoleteSdkInt")
|
||||
|
||||
package com.fankes.miui.notify.utils
|
||||
package com.fankes.miui.notify.utils.factory
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.AlertDialog
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.Configuration
|
||||
@@ -34,6 +37,7 @@ import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.provider.Settings
|
||||
import android.util.Base64
|
||||
@@ -43,9 +47,9 @@ 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.log.loggerE
|
||||
import com.highcapable.yukihookapi.hook.type.java.StringType
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
/**
|
||||
* 系统深色模式是否开启
|
||||
@@ -125,29 +129,61 @@ inline val isNotSupportMiuiVersion get() = !isSupportMiuiVersion
|
||||
* @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"
|
||||
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 miuiFullVersion
|
||||
get() = if (isMIUI) (miuiVersion + " " + findPropString(key = "ro.system.build.version.incremental"))
|
||||
else "不是 MIUI 系统"
|
||||
get() = if (isMIUI) findPropString(key = "ro.system.build.version.incremental").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 系统"
|
||||
|
||||
/**
|
||||
* 得到安装包信息
|
||||
@@ -180,18 +216,23 @@ val Context.versionName get() = packageInfo.versionName ?: ""
|
||||
*/
|
||||
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
|
||||
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 加密
|
||||
@@ -277,98 +318,33 @@ fun Context.snake(msg: String, actionText: String = "", it: () -> Unit = {}) =
|
||||
}.show()
|
||||
|
||||
/**
|
||||
* 忽略异常返回值
|
||||
* @param it 回调 - 如果异常为空
|
||||
* @return [T] 发生异常时返回设定值否则返回正常值
|
||||
* 启动系统浏览器
|
||||
* @param url 网址
|
||||
* @param packageName 指定包名 - 可不填
|
||||
*/
|
||||
inline fun <T> safeOfNull(it: () -> T): T? = safeOf(null, it)
|
||||
|
||||
/**
|
||||
* 忽略异常返回值
|
||||
* @param it 回调 - 如果异常为 false
|
||||
* @return [Boolean] 发生异常时返回设定值否则返回正常值
|
||||
*/
|
||||
inline fun safeOfFalse(it: () -> Boolean) = safeOf(default = false, it)
|
||||
|
||||
/**
|
||||
* 忽略异常返回值
|
||||
* @param it 回调 - 如果异常为 true
|
||||
* @return [Boolean] 发生异常时返回设定值否则返回正常值
|
||||
*/
|
||||
inline fun safeOfTrue(it: () -> Boolean) = safeOf(default = true, it)
|
||||
|
||||
/**
|
||||
* 忽略异常返回值
|
||||
* @param it 回调 - 如果异常为 false
|
||||
* @return [String] 发生异常时返回设定值否则返回正常值
|
||||
*/
|
||||
inline fun safeOfNothing(it: () -> String) = safeOf(default = "", it)
|
||||
|
||||
/**
|
||||
* 忽略异常返回值
|
||||
* @param it 回调 - 如果异常为 false
|
||||
* @return [Int] 发生异常时返回设定值否则返回正常值
|
||||
*/
|
||||
inline fun safeOfNan(it: () -> Int) = safeOf(default = 0, it)
|
||||
|
||||
/**
|
||||
* 忽略异常返回值
|
||||
* @param default 异常返回值
|
||||
* @param it 正常回调值
|
||||
* @return [T] 发生异常时返回设定值否则返回正常值
|
||||
*/
|
||||
inline fun <T> safeOf(default: T, it: () -> T): T {
|
||||
return try {
|
||||
it()
|
||||
} catch (t: NullPointerException) {
|
||||
default
|
||||
} catch (t: UnsatisfiedLinkError) {
|
||||
default
|
||||
} catch (t: UnsupportedOperationException) {
|
||||
default
|
||||
} catch (t: ClassNotFoundException) {
|
||||
default
|
||||
} catch (t: IllegalStateException) {
|
||||
default
|
||||
} catch (t: NoSuchMethodError) {
|
||||
default
|
||||
} catch (t: NoSuchFieldError) {
|
||||
default
|
||||
} catch (t: Error) {
|
||||
default
|
||||
} catch (t: Exception) {
|
||||
default
|
||||
} catch (t: Throwable) {
|
||||
default
|
||||
}
|
||||
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 msg 出错输出的消息 - 默认为空
|
||||
* @param it 正常回调
|
||||
* 复制到剪贴板
|
||||
* @param content 要复制的文本
|
||||
*/
|
||||
inline fun safeRun(msg: String = "", it: () -> Unit) {
|
||||
try {
|
||||
it()
|
||||
} catch (e: NullPointerException) {
|
||||
if (msg.isNotBlank()) loggerE(msg = msg, e = e)
|
||||
} catch (e: UnsatisfiedLinkError) {
|
||||
if (msg.isNotBlank()) loggerE(msg = msg, e = e)
|
||||
} catch (e: UnsupportedOperationException) {
|
||||
if (msg.isNotBlank()) loggerE(msg = msg, e = e)
|
||||
} catch (e: ClassNotFoundException) {
|
||||
if (msg.isNotBlank()) loggerE(msg = msg, e = e)
|
||||
} catch (e: IllegalStateException) {
|
||||
if (msg.isNotBlank()) loggerE(msg = msg, e = e)
|
||||
} catch (e: NoSuchMethodError) {
|
||||
if (msg.isNotBlank()) loggerE(msg = msg, e = e)
|
||||
} catch (e: NoSuchFieldError) {
|
||||
if (msg.isNotBlank()) loggerE(msg = msg, e = e)
|
||||
} catch (e: Error) {
|
||||
if (msg.isNotBlank()) loggerE(msg = msg, e = e)
|
||||
} catch (e: Exception) {
|
||||
if (msg.isNotBlank()) loggerE(msg = msg, e = e)
|
||||
} catch (e: Throwable) {
|
||||
fun Context.copyToClipboard(content: String) = runSafe {
|
||||
(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 = "已复制")
|
||||
}
|
||||
}
|
||||
}
|
@@ -20,7 +20,7 @@
|
||||
*
|
||||
* This file is Created by fankes on 2022/2/19.
|
||||
*/
|
||||
package com.fankes.miui.notify.utils
|
||||
package com.fankes.miui.notify.utils.tool
|
||||
|
||||
import android.graphics.*
|
||||
import android.graphics.drawable.AnimationDrawable
|
||||
@@ -29,6 +29,7 @@ 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
|
||||
|
||||
/**
|
@@ -20,11 +20,19 @@
|
||||
*
|
||||
* This file is Created by fankes on 2022/2/25.
|
||||
*/
|
||||
@file:Suppress("TrustAllX509TrustManager", "CustomX509TrustManager")
|
||||
@file:Suppress("TrustAllX509TrustManager", "CustomX509TrustManager", "DEPRECATION")
|
||||
|
||||
package com.fankes.miui.notify.utils
|
||||
package com.fankes.miui.notify.utils.tool
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.ProgressDialog
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.provider.Settings
|
||||
import com.fankes.miui.notify.utils.factory.safeOfNull
|
||||
import com.fankes.miui.notify.utils.factory.setDefaultStyle
|
||||
import com.fankes.miui.notify.utils.factory.showDialog
|
||||
import com.fankes.miui.notify.utils.factory.snake
|
||||
import com.highcapable.yukihookapi.hook.log.loggerD
|
||||
import okhttp3.*
|
||||
import java.io.IOException
|
||||
@@ -37,13 +45,45 @@ 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) {
|
||||
fun wait(context: Activity, url: String, it: (Boolean, String) -> Unit) = runCatching {
|
||||
OkHttpClient().newBuilder().apply {
|
||||
SSLSocketClient.sSLSocketFactory?.let { sslSocketFactory(it, SSLSocketClient.trustManager) }
|
||||
hostnameVerifier(SSLSocketClient.hostnameVerifier)
|
||||
@@ -62,7 +102,7 @@ object ClientRequestTool {
|
||||
context.runOnUiThread { it(true, bodyString) }
|
||||
}
|
||||
})
|
||||
}
|
||||
}.onFailure { it(false, "URL 无效") }
|
||||
|
||||
/**
|
||||
* 自动信任 SSL 证书
|
@@ -20,9 +20,13 @@
|
||||
*
|
||||
* This file is Created by fankes on 2022/2/8.
|
||||
*/
|
||||
package com.fankes.miui.notify.utils
|
||||
package com.fankes.miui.notify.utils.tool
|
||||
|
||||
import android.content.Context
|
||||
import com.fankes.miui.notify.utils.factory.execShellSu
|
||||
import com.fankes.miui.notify.utils.factory.showDialog
|
||||
import com.fankes.miui.notify.utils.factory.snake
|
||||
import com.fankes.miui.notify.utils.factory.toast
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.highcapable.yukihookapi.hook.xposed.YukiHookModuleStatus
|
||||
|
@@ -29,8 +29,8 @@ 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
|
||||
import com.fankes.miui.notify.utils.factory.dp
|
||||
|
||||
class MaterialSwitch(context: Context, attrs: AttributeSet?) : SwitchCompat(context, attrs) {
|
||||
|
||||
@@ -48,16 +48,16 @@ class MaterialSwitch(context: Context, attrs: AttributeSet?) : SwitchCompat(cont
|
||||
.rectangle()
|
||||
.rounded()
|
||||
.solidColor(0xFF656565.toInt())
|
||||
.height(20.dp)
|
||||
.cornerRadius(15.dp)
|
||||
.height(20.dp(context).toInt())
|
||||
.cornerRadius(15.dp(context).toInt())
|
||||
.build()
|
||||
thumbDrawable = DrawableBuilder()
|
||||
.rectangle()
|
||||
.rounded()
|
||||
.solidColor(Color.WHITE)
|
||||
.size(20.dp, 20.dp)
|
||||
.cornerRadius(20.dp)
|
||||
.strokeWidth(2.dp)
|
||||
.size(20.dp(context).toInt(), 20.dp(context).toInt())
|
||||
.cornerRadius(20.dp(context).toInt())
|
||||
.strokeWidth(8.dp(context).toInt())
|
||||
.strokeColor(Color.TRANSPARENT)
|
||||
.build()
|
||||
trackTintList = toColors(
|
||||
|
9
app/src/main/res/drawable/ic_notify_icon.xml
Normal file
9
app/src/main/res/drawable/ic_notify_icon.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<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="#FF000000"
|
||||
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>
|
@@ -149,7 +149,7 @@
|
||||
android:divider="@color/trans"
|
||||
android:dividerHeight="15dp"
|
||||
android:fadingEdgeLength="10dp"
|
||||
android:listSelector="@null"
|
||||
android:listSelector="@color/trans"
|
||||
android:padding="15dp"
|
||||
android:requiresFadingEdge="vertical"
|
||||
android:scrollbars="none" />
|
||||
|
@@ -29,6 +29,17 @@
|
||||
android:textSize="25sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<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="15dp"
|
||||
android:alpha="0.85"
|
||||
android:src="@mipmap/ic_github"
|
||||
android:tint="@color/colorTextGray"
|
||||
android:tooltipText="项目地址" />
|
||||
|
||||
<androidx.constraintlayout.utils.widget.ImageFilterView
|
||||
android:id="@+id/title_restart_icon"
|
||||
style="?android:attr/selectableItemBackgroundBorderless"
|
||||
@@ -86,7 +97,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:alpha="0.8"
|
||||
android:text="当前版本:%1"
|
||||
android:text="模块版本:%1"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="13sp" />
|
||||
|
||||
@@ -95,7 +106,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:alpha="0.8"
|
||||
android:text="MIUI 版本:%1"
|
||||
android:text="系统版本:%1"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="13sp" />
|
||||
</LinearLayout>
|
||||
@@ -189,6 +200,117 @@
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/config_item_s_count_hook"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="15dp"
|
||||
android:layout_marginTop="10dp"
|
||||
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">
|
||||
|
||||
<com.fankes.miui.notify.view.MaterialSwitch
|
||||
android:id="@+id/config_status_icon_count_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="此选项默认开启,MIUI 默认最多只能显示 3 个图标,其余图标将变成省略号,你可以在下方自定义最多显示的图标个数,修改为 0 则只会显示省略号代表图标个数,为防止发生异常,最大限制 100 个,超出的图标可能会被信号或网速指示器遮挡。"
|
||||
android:textColor="@color/colorTextDark"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/config_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/config_item_s_count_child_hook"
|
||||
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/config_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/config_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/config_item_color_hook"
|
||||
android:layout_width="match_parent"
|
||||
@@ -399,7 +521,7 @@
|
||||
android:layout_marginBottom="10dp"
|
||||
android:alpha="0.8"
|
||||
android:lineSpacingExtra="6dp"
|
||||
android:text="Q.哪些是已知问题?\nA.以下是问题描述列表:\n(1) 动态小图标可能会在高版本系统中闪烁,这是 MIUI 自身就存在的问题,后期只能等官方修复。\n(2) 请始终保持最新版本的 LSPosed,旧版本可能会出现 Hook 不生效的问题。\n(3) 建议最低从 MIUI 12.5 “2021-5-18” 开发版以后开始使用,之前的版本可能或多或少存在 MIUI 自身 BUG 不生效、黑白块问题,若你的系统不存在原生图标问题不建议使用模块。"
|
||||
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" />
|
||||
|
||||
@@ -413,53 +535,6 @@
|
||||
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/bg_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/ic_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="本软件是免费开源项目,遵循 AGPL3.0 协议,你可以点击这里前往 Github 查看源码以及获取模块更新。"
|
||||
android:textColor="@color/colorTextDark"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
@@ -5,6 +5,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_permotion_round"
|
||||
android:baselineAligned="false"
|
||||
android:descendantFocusability="blocksDescendants"
|
||||
android:gravity="center|start"
|
||||
android:orientation="horizontal"
|
||||
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>
|
26
app/src/main/res/layout/dia_status_icon_count.xml
Normal file
26
app/src/main/res/layout/dia_status_icon_count.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="15dp"
|
||||
android:paddingTop="15dp"
|
||||
android:paddingRight="15dp"
|
||||
tools:ignore="HardcodedText">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/dia_status_icon_count_input_edit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:digits="0123456789"
|
||||
android:ellipsize="end"
|
||||
android:hint="请输入 0-100 之间的整数"
|
||||
android:inputType="number"
|
||||
android:singleLine="true" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
</LinearLayout>
|
BIN
app/src/main/res/mipmap-xxhdpi/ic_github.png
Normal file
BIN
app/src/main/res/mipmap-xxhdpi/ic_github.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.8 KiB |
@@ -1,12 +1,12 @@
|
||||
plugins {
|
||||
id 'com.android.application' version '7.1.1' apply false
|
||||
id 'com.android.library' version '7.1.1' apply false
|
||||
id 'com.android.application' version '7.1.2' apply false
|
||||
id 'com.android.library' version '7.1.2' apply false
|
||||
id 'org.jetbrains.kotlin.android' version '1.6.10' apply false
|
||||
}
|
||||
|
||||
ext {
|
||||
appVersionName = "1.85"
|
||||
appVersionCode = 18
|
||||
appVersionName = "2.15"
|
||||
appVersionCode = 25
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
|
Reference in New Issue
Block a user