35 Commits
1.7 ... 1.8

Author SHA1 Message Date
63512254da Update version to 1.8 2022-05-30 03:58:50 +08:00
69c5003af1 Changed contributing way 2022-05-30 03:46:30 +08:00
ac17f3ae55 Added notify icon in notify panel used app icon function 2022-05-30 03:24:40 +08:00
d469adc667 Added warn dialog when enable replace all notify icon 2022-05-30 02:34:39 +08:00
2bb2218145 Merge code 2022-05-30 02:09:45 +08:00
aae8a27fcc Merge to new way support receiver callback 2022-05-30 01:58:28 +08:00
3b31e2c255 Merge systemBar support with native 2022-05-30 00:52:03 +08:00
f111e7d53c Added YukiPromoteTool 2022-05-30 00:38:08 +08:00
327f2139b8 Update YukiHookAPI 2022-05-29 04:08:16 +08:00
adb1f174ad Update YukiHookAPI 2022-05-27 03:36:28 +08:00
373d5c6cb8 Merge code 2022-05-25 04:38:40 +08:00
aba5e3c23c Update YukiHookAPI 2022-05-25 04:27:01 +08:00
8a2f0aca83 Changed FunctionFactory.kt 2022-05-12 01:10:22 +08:00
a0a4d08612 Changed Xposed Scope 2022-05-11 21:52:55 +08:00
25747b2041 Update YukiHookAPI 2022-05-10 01:53:17 +08:00
8de1abf679 Update version to 1.77 2022-05-09 16:08:08 +08:00
b97de07843 Update misc 2022-05-09 16:01:41 +08:00
b497189549 修复媒体通知面板不能被透明的问题,新增媒体通知自动展开功能 2022-05-09 16:01:35 +08:00
1ca659dd6a Merge code 2022-05-09 15:00:08 +08:00
117b37b5cf Update version to 1.76 2022-05-09 01:20:51 +08:00
967186bd00 Update misc 2022-05-09 01:16:53 +08:00
eea7b6d897 更新文案 2022-05-09 01:16:46 +08:00
dd75a13970 尝试修复通知面板透明功能在 ColorOS 12 不生效的问题 2022-05-09 01:11:09 +08:00
66ed43f5ad Fix Activity destroy non-null unregister bug 2022-05-09 00:57:37 +08:00
399cfafd29 Make SystemUIHooker singleton 2022-05-08 15:08:05 +08:00
6ae1d3e726 Update YukiHookAPI 2022-05-06 15:09:25 +08:00
384e6b657e Update version to 1.75 2022-05-05 15:17:04 +08:00
08b7feeede 优化通知面板背景透明度功能设置界面,添加实验性文案说明 2022-05-05 15:11:23 +08:00
e7fc0bbcd0 默认关闭通知面板背景透明度功能 2022-05-05 15:10:58 +08:00
1f8022fd7c 修复通知面板折叠通知背景异常问题,优化二级通知的背景 2022-05-05 15:10:46 +08:00
Fankesyooni
b404543f47 Merge pull request #16 from NextAlone/master
fix: notification summary background
2022-05-05 12:34:40 +08:00
NextAlone
ad195d93ea fix: notification summary background 2022-05-05 05:19:49 +08:00
15e7490808 Update YukiHookAPI 2022-05-04 14:03:55 +08:00
7c906cd2a0 Update YukiHookAPI 2022-05-04 10:15:55 +08:00
0da5875d64 Update YukiHookAPI 2022-05-04 09:32:30 +08:00
21 changed files with 665 additions and 497 deletions

2
.idea/misc.xml generated
View File

@@ -11,7 +11,7 @@
<entry key="app/src/main/res/drawable/ic_notify_icon.xml" value="0.232" />
<entry key="app/src/main/res/drawable/ic_system_clock.xml" value="0.232" />
<entry key="app/src/main/res/layout/activity_config.xml" value="0.4375" />
<entry key="app/src/main/res/layout/activity_main.xml" value="0.31423220973782773" />
<entry key="app/src/main/res/layout/activity_main.xml" value="0.3060926669098869" />
<entry key="app/src/main/res/layout/adapter_config.xml" value="0.4375" />
<entry key="app/src/main/res/layout/dia_icon_filter.xml" value="0.4375" />
<entry key="app/src/main/res/layout/dia_source_from.xml" value="0.4375" />

View File

@@ -2,7 +2,7 @@
[![Blank](https://img.shields.io/badge/build-passing-brightgreen)](https://github.com/fankes/ColorOSNotifyIcon)
[![Blank](https://img.shields.io/badge/license-AGPL3.0-blue)](https://github.com/fankes/ColorOSNotifyIcon/blob/master/LICENSE)
[![Blank](https://img.shields.io/badge/version-v1.7-green)](https://github.com/fankes/ColorOSNotifyIcon/releases)
[![Blank](https://img.shields.io/badge/version-v1.8-green)](https://github.com/fankes/ColorOSNotifyIcon/releases)
[![Blank](https://img.shields.io/github/downloads/fankes/ColorOSNotifyIcon/total?label=Release)](https://github.com/fankes/ColorOSNotifyIcon/releases)
[![Blank](https://img.shields.io/github/downloads/Xposed-Modules-Repo/com.fankes.coloros.notify/total?label=LSPosed%20Repo&logo=Android&style=flat&labelColor=F48FB1&logoColor=ffffff)](https://github.com/Xposed-Modules-Repo/com.fankes.coloros.notify/releases)
[![Telegram](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/XiaofangInternet)

View File

@@ -50,36 +50,22 @@ android {
buildFeatures {
viewBinding true
}
}
/** 移除无效耗时 lint Task */
tasks.whenTaskAdded {
task -> if (task.name == "lintVitalRelease") task.enabled = false
}
/** 移除无效耗时 lint Task */
tasks.whenTaskAdded {
task -> if (task.name == "lintVitalAnalyzeRelease") task.enabled = false
}
/** 移除无效耗时 lint Task */
tasks.whenTaskAdded {
task -> if (task.name == "lintVitalReportRelease") task.enabled = false
lintOptions {
checkReleaseBuilds false
}
}
dependencies {
compileOnly 'de.robv.android.xposed:api:82'
implementation 'com.highcapable.yukihookapi:api:1.0.81'
ksp 'com.highcapable.yukihookapi:ksp-xposed:1.0.81'
implementation 'com.highcapable.yukihookapi:api:1.0.91'
ksp 'com.highcapable.yukihookapi:ksp-xposed:1.0.91'
implementation "com.github.topjohnwu.libsu:core:3.1.2"
implementation 'androidx.annotation:annotation:1.3.0'
implementation 'com.geyifeng.immersionbar:immersionbar:3.2.0'
implementation 'com.geyifeng.immersionbar:immersionbar-ktx:3.2.0'
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
implementation 'com.google.android.material:material:1.6.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'

View File

@@ -1,60 +0,0 @@
/*
* ColorOSNotifyIcon - Optimize notification icons for ColorOS and adapt to native notification icon specifications.
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
* https://github.com/fankes/ColorOSNotifyIcon
*
* This software is non-free but opensource software: you can redistribute it
* and/or modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
* <p>
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/3/24.
*/
@file:Suppress("MemberVisibilityCanBePrivate")
package com.fankes.coloros.notify.const
import com.fankes.coloros.notify.BuildConfig
/**
* 存储一些静态编译后的值
*/
object Const {
/** 当前模块的包名 */
const val MODULE_PACKAGE_NAME = BuildConfig.APPLICATION_ID
/** 当前模块的版本名称 */
const val MODULE_VERSION_NAME = BuildConfig.VERSION_NAME
/** 当前模块的版本号 */
const val MODULE_VERSION_CODE = BuildConfig.VERSION_CODE
/** 当前模块的版本校验 */
const val MODULE_VERSION_VERIFY = "${MODULE_VERSION_NAME}_${MODULE_VERSION_CODE}_202205040646"
/** 当前模块的版本校验标签 */
const val MODULE_VERSION_VERIFY_TAG = "module_version_verify"
/** 发送通讯广播号标签 - 模块激活状态 */
const val ACTION_MODULE_CHECKING_RECEIVER = "cnn_module_checking_action"
/** 接收通讯广播号标签 - 模块激活状态 */
const val ACTION_MODULE_HANDLER_RECEIVER = "cnn_module_handler_action"
/** 发送通讯广播号标签 - 通知系统界面刷新 */
const val ACTION_REMIND_CHECKING_RECEIVER = "cnn_remind_checking_action"
/** 接收通讯广播号标签 - 通知系统界面刷新 */
const val ACTION_REMIND_HANDLER_RECEIVER = "cnn_remind_handler_action"
}

View File

@@ -33,13 +33,15 @@ object DataConst {
val ENABLE_HIDE_ICON = PrefsData("_hide_icon", false)
val ENABLE_ANDROID12_STYLE = PrefsData("_notify_android12_style", isUpperOfAndroidS)
val ENABLE_NOTIFY_ICON_FIX = PrefsData("_notify_icon_fix", true)
val ENABLE_NOTIFY_ICON_FORCE_APP_ICON = PrefsData("_notify_icon_force_app_icon", false)
val ENABLE_NOTIFY_ICON_FIX_NOTIFY = PrefsData("_notify_icon_fix_notify", true)
val REMOVE_DEV_NOTIFY = PrefsData("_remove_dev_notify", true)
val REMOVE_CHANGECP_NOTIFY = PrefsData("_remove_charge_complete_notify", false)
val REMOVE_DNDALERT_NOTIFY = PrefsData("_remove_dndalert_notify", false)
val ENABLE_NOTIFY_ICON_FIX_AUTO = PrefsData("_enable_notify_icon_fix_auto", true)
val ENABLE_NOTIFY_PANEL_ALPHA = PrefsData("_enable_notify_panel_alpha", true)
val NOTIFY_PANEL_ALPHA = PrefsData("_notify_panel_alpha", 185)
val ENABLE_NOTIFY_PANEL_ALPHA = PrefsData("_enable_notify_panel_alpha", false)
val ENABLE_NOTIFY_MEDIA_PANEL_AUTO_EXP = PrefsData("_enable_notify_media_panel_auto_exp", false)
val NOTIFY_PANEL_ALPHA = PrefsData("_notify_panel_alpha_pst", 75)
val NOTIFY_ICON_DATAS = PrefsData("_notify_icon_datas", "")
val NOTIFY_ICON_FIX_AUTO_TIME = PrefsData("_notify_icon_fix_auto_time", "07:00")

View File

@@ -41,13 +41,15 @@ class HookEntry : IYukiHookXposedInit {
}
override fun onHook() = encase {
when {
/** 不是 ColorOS 系统停止 Hook */
isNotColorOS -> loggerW(msg = "Aborted Hook -> This System is not ColorOS")
/** Hook 被手动关闭停止 Hook */
prefs.get(DataConst.ENABLE_MODULE).not() -> loggerW(msg = "Aborted Hook -> Hook Closed")
/** 开始 Hook */
else -> loadApp(SYSTEMUI_PACKAGE_NAME, SystemUIHooker())
loadApp(SYSTEMUI_PACKAGE_NAME) {
when {
/** 不是 ColorOS 系统停止 Hook */
isNotColorOS -> loggerW(msg = "Aborted Hook -> This System is not ColorOS")
/** Hook 被手动关闭停止 Hook */
prefs.get(DataConst.ENABLE_MODULE).not() -> loggerW(msg = "Aborted Hook -> Hook Closed")
/** 开始 Hook */
else -> loadHooker(SystemUIHooker)
}
}
}
}

View File

@@ -20,13 +20,14 @@
*
* This file is Created by fankes on 2022/3/25.
*/
@file:Suppress("StaticFieldLeak")
package com.fankes.coloros.notify.hook.entity
import android.app.WallpaperManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.res.ColorStateList
import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.Outline
@@ -34,6 +35,7 @@ import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.Icon
import android.graphics.drawable.VectorDrawable
import android.os.SystemClock
import android.service.notification.StatusBarNotification
import android.util.ArrayMap
import android.view.View
@@ -43,7 +45,6 @@ import android.widget.ImageView
import androidx.core.graphics.drawable.toBitmap
import androidx.core.view.children
import com.fankes.coloros.notify.bean.IconDataBean
import com.fankes.coloros.notify.const.Const
import com.fankes.coloros.notify.data.DataConst
import com.fankes.coloros.notify.hook.HookConst.ANDROID_PACKAGE_NAME
import com.fankes.coloros.notify.hook.HookConst.SYSTEMUI_PACKAGE_NAME
@@ -53,6 +54,7 @@ import com.fankes.coloros.notify.param.IconPackParams
import com.fankes.coloros.notify.utils.drawable.drawabletoolbox.DrawableBuilder
import com.fankes.coloros.notify.utils.factory.*
import com.fankes.coloros.notify.utils.tool.IconAdaptationTool
import com.fankes.coloros.notify.utils.tool.SystemUITool
import com.highcapable.yukihookapi.hook.bean.VariousClass
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
import com.highcapable.yukihookapi.hook.factory.current
@@ -71,111 +73,123 @@ import com.highcapable.yukihookapi.hook.type.java.LongType
/**
* 系统界面核心 Hook 类
*/
class SystemUIHooker : YukiBaseHooker() {
object SystemUIHooker : YukiBaseHooker() {
companion object {
/** 原生存在的类 */
private const val ContrastColorUtilClass = "com.android.internal.util.ContrastColorUtil"
/** 原生存在的类 */
private const val ContrastColorUtilClass = "com.android.internal.util.ContrastColorUtil"
/** 原生存在的类 */
private const val NotificationUtilsClass = "$SYSTEMUI_PACKAGE_NAME.statusbar.notification.NotificationUtils"
/** 原生存在的类 */
private const val NotificationUtilsClass = "$SYSTEMUI_PACKAGE_NAME.statusbar.notification.NotificationUtils"
/** 原生存在的类 */
private const val NotificationEntryClass = "$SYSTEMUI_PACKAGE_NAME.statusbar.notification.collection.NotificationEntry"
/** 原生存在的类 */
private const val NotificationEntryClass = "$SYSTEMUI_PACKAGE_NAME.statusbar.notification.collection.NotificationEntry"
/** 原生存在的类 */
private const val StatusBarIconClass = "com.android.internal.statusbar.StatusBarIcon"
/** 原生存在的类 */
private const val StatusBarIconClass = "com.android.internal.statusbar.StatusBarIcon"
/** 原生存在的类 */
private const val StatusBarIconViewClass = "$SYSTEMUI_PACKAGE_NAME.statusbar.StatusBarIconView"
/** 原生存在的类 */
private const val StatusBarIconViewClass = "$SYSTEMUI_PACKAGE_NAME.statusbar.StatusBarIconView"
/** 原生存在的类 */
private const val IconBuilderClass = "$SYSTEMUI_PACKAGE_NAME.statusbar.notification.icon.IconBuilder"
/** 原生存在的类 */
private const val IconBuilderClass = "$SYSTEMUI_PACKAGE_NAME.statusbar.notification.icon.IconBuilder"
/** 原生存在的类 */
private const val IconManagerClass = "$SYSTEMUI_PACKAGE_NAME.statusbar.notification.icon.IconManager"
/** 原生存在的类 */
private const val IconManagerClass = "$SYSTEMUI_PACKAGE_NAME.statusbar.notification.icon.IconManager"
/** 原生存在的类 */
private const val PluginManagerImplClass = "$SYSTEMUI_PACKAGE_NAME.shared.plugins.PluginManagerImpl"
/** ColorOS 存在的类 - 旧版本不存在 */
private const val OplusContrastColorUtilClass = "com.oplusos.util.OplusContrastColorUtil"
/** 原生存在的类 */
private const val NotificationBackgroundViewClass = "$SYSTEMUI_PACKAGE_NAME.statusbar.notification.row.NotificationBackgroundView"
/** 原生存在的类 */
private const val PluginManagerImplClass = "$SYSTEMUI_PACKAGE_NAME.shared.plugins.PluginManagerImpl"
/** 原生存在的类 */
private const val PlayerViewHolderClass = "$SYSTEMUI_PACKAGE_NAME.media.PlayerViewHolder"
/** 原生存在的类 */
private const val NotificationBackgroundViewClass = "$SYSTEMUI_PACKAGE_NAME.statusbar.notification.row.NotificationBackgroundView"
/** 原生存在的类 */
private const val MediaDataClass = "$SYSTEMUI_PACKAGE_NAME.media.MediaData"
/** ColorOS 存在的类 - 旧版本不存在 */
private const val OplusNotificationBackgroundViewClass =
"com.oplusos.systemui.statusbar.notification.row.OplusNotificationBackgroundView"
/** ColorOS 存在的类 - 旧版本不存在 */
private const val OplusContrastColorUtilClass = "com.oplusos.util.OplusContrastColorUtil"
/** 根据多个版本存在不同的包名相同的类 */
private val OplusNotificationIconAreaControllerClass = VariousClass(
"com.oplusos.systemui.statusbar.phone.OplusNotificationIconAreaController",
"com.oplusos.systemui.statusbar.policy.OplusNotificationIconAreaController",
"com.coloros.systemui.statusbar.policy.ColorNotificationIconAreaController"
)
/** ColorOS 存在的类 - 旧版本不存在 */
private const val OplusNotificationBackgroundViewClass =
"com.oplusos.systemui.statusbar.notification.row.OplusNotificationBackgroundView"
/** 根据多个版本存在不同的包名相同的类 */
private val SystemPromptControllerClass = VariousClass(
"com.oplusos.systemui.statusbar.policy.SystemPromptController",
"com.coloros.systemui.statusbar.policy.ColorSystemPromptController"
)
/** ColorOS 存在的类 - 旧版本不存在 */
private const val OplusMediaControlPanelClass = "com.oplusos.systemui.media.OplusMediaControlPanel"
/** 根据多个版本存在不同的包名相同的类 */
private val RoundRectDrawableUtilClass = VariousClass(
"com.oplusos.systemui.notification.util.RoundRectDrawableUtil",
"com.coloros.systemui.notification.util.RoundRectDrawableUtil"
)
/** ColorOS 存在的类 - 旧版本不存在 */
private const val OplusMediaViewControllerClass = "com.oplusos.systemui.media.OplusMediaViewController"
/** 根据多个版本存在不同的包名相同的类 */
private val RoundRectDrawableUtil_CompanionClass = VariousClass(
"com.oplusos.systemui.notification.util.RoundRectDrawableUtil\$Companion",
"com.oplusos.systemui.notification.util.RoundRectDrawableUtil\$Companion"
)
/** ColorOS 存在的类 - 旧版本不存在 */
private const val BasePlayViewHolderClass = "com.oplusos.systemui.media.base.BasePlayViewHolder"
/** 根据多个版本存在不同的包名相同的类 */
private val DndAlertHelperClass = VariousClass(
"com.oplusos.systemui.notification.helper.DndAlertHelper",
"com.coloros.systemui.notification.helper.DndAlertHelper"
)
/** 根据多个版本存在不同的包名相同的类 */
private val OplusNotificationIconAreaControllerClass = VariousClass(
"com.oplusos.systemui.statusbar.phone.OplusNotificationIconAreaController",
"com.oplusos.systemui.statusbar.policy.OplusNotificationIconAreaController",
"com.coloros.systemui.statusbar.policy.ColorNotificationIconAreaController"
)
/** 根据多个版本存在不同的包名相同的类 */
private val OplusPowerNotificationWarningsClass = VariousClass(
"com.oplusos.systemui.notification.power.OplusPowerNotificationWarnings",
"com.coloros.systemui.notification.power.ColorosPowerNotificationWarnings"
)
/** 根据多个版本存在不同的包名相同的类 */
private val SystemPromptControllerClass = VariousClass(
"com.oplusos.systemui.statusbar.policy.SystemPromptController",
"com.coloros.systemui.statusbar.policy.ColorSystemPromptController"
)
/** 根据多个版本存在不同的包名相同的类 */
private val AbstractReceiverClass = VariousClass(
"com.oplusos.systemui.common.receiver.AbstractReceiver",
"com.coloros.systemui.common.receiver.AbstractReceiver"
)
/** 根据多个版本存在不同的包名相同的类 */
private val RoundRectDrawableUtilClass = VariousClass(
"com.oplusos.systemui.notification.util.RoundRectDrawableUtil",
"com.coloros.systemui.notification.util.RoundRectDrawableUtil"
)
/** 根据多个版本存在不同的包名相同的类 */
private val StatusBarNotificationPresenterClass = VariousClass(
"$SYSTEMUI_PACKAGE_NAME.statusbar.phone.StatusBarNotificationPresenter",
"$SYSTEMUI_PACKAGE_NAME.statusbar.phone.StatusBar"
)
/** 根据多个版本存在不同的包名相同的类 */
private val RoundRectDrawableUtil_CompanionClass = VariousClass(
"com.oplusos.systemui.notification.util.RoundRectDrawableUtil\$Companion",
"com.oplusos.systemui.notification.util.RoundRectDrawableUtil\$Companion"
)
/** 根据多个版本存在不同的包名相同的类 */
private val ExpandableNotificationRowClass = VariousClass(
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.row.ExpandableNotificationRow",
"$SYSTEMUI_PACKAGE_NAME.statusbar.ExpandableNotificationRow"
)
/** 根据多个版本存在不同的包名相同的类 */
private val DndAlertHelperClass = VariousClass(
"com.oplusos.systemui.notification.helper.DndAlertHelper",
"com.coloros.systemui.notification.helper.DndAlertHelper"
)
/** 根据多个版本存在不同的包名相同的类 */
private val NotificationViewWrapperClass = VariousClass(
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.row.wrapper.NotificationViewWrapper",
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.NotificationViewWrapper"
)
/** 根据多个版本存在不同的包名相同的类 */
private val OplusPowerNotificationWarningsClass = VariousClass(
"com.oplusos.systemui.notification.power.OplusPowerNotificationWarnings",
"com.coloros.systemui.notification.power.ColorosPowerNotificationWarnings"
)
/** 根据多个版本存在不同的包名相同的类 */
private val NotificationHeaderViewWrapperClass = VariousClass(
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.row.wrapper.NotificationHeaderViewWrapper",
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.NotificationHeaderViewWrapper"
)
}
/** 根据多个版本存在不同的包名相同的类 */
private val AbstractReceiverClass = VariousClass(
"com.oplusos.systemui.common.receiver.AbstractReceiver",
"com.coloros.systemui.common.receiver.AbstractReceiver"
)
/** 根据多个版本存在不同的包名相同的类 */
private val StatusBarNotificationPresenterClass = VariousClass(
"$SYSTEMUI_PACKAGE_NAME.statusbar.phone.StatusBarNotificationPresenter",
"$SYSTEMUI_PACKAGE_NAME.statusbar.phone.StatusBar"
)
/** 根据多个版本存在不同的包名相同的类 */
private val ExpandableNotificationRowClass = VariousClass(
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.row.ExpandableNotificationRow",
"$SYSTEMUI_PACKAGE_NAME.statusbar.ExpandableNotificationRow"
)
/** 根据多个版本存在不同的包名相同的类 */
private val NotificationViewWrapperClass = VariousClass(
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.row.wrapper.NotificationViewWrapper",
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.NotificationViewWrapper"
)
/** 根据多个版本存在不同的包名相同的类 */
private val NotificationHeaderViewWrapperClass = VariousClass(
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.row.wrapper.NotificationHeaderViewWrapper",
"$SYSTEMUI_PACKAGE_NAME.statusbar.notification.NotificationHeaderViewWrapper"
)
/** 缓存的彩色 APP 图标 */
private var appIcons = ArrayMap<String, Drawable>()
@@ -189,6 +203,9 @@ class SystemUIHooker : YukiBaseHooker() {
/** 状态栏通知图标数组 */
private var notificationIconInstances = ArrayList<View>()
/** 媒体通知 [View] */
private var notificationPlayerView: View? = null
/** 通知栏通知控制器 */
private var notificationPresenter: Any? = null
@@ -198,65 +215,6 @@ class SystemUIHooker : YukiBaseHooker() {
/** 是否已经使用过缓存刷新功能 */
private var isUsingCachingMethod = false
/** 是否已经注册广播 */
private var isRegisterReceiver = false
/** 用户解锁屏幕广播接收器 */
private val userPresentReceiver by lazy {
object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
/** 解锁后重新刷新状态栏图标防止系统重新设置它 */
if (isUsingCachingMethod) refreshStatusBarIcons()
}
}
}
/** 模块广播接收器 */
private val moduleCheckingReceiver by lazy {
object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
context?.sendBroadcast(Intent().apply {
action = Const.ACTION_MODULE_HANDLER_RECEIVER
putExtra("isRegular", true)
putExtra("isValied", intent?.isValiedModule)
})
}
}
}
/** 通知广播接收器 */
private val remindCheckingReceiver by lazy {
object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) = delayedRun(ms = 300) {
if (intent?.isValiedModule == true)
recachingPrefs(intent.getBooleanExtra("isRefreshCacheOnly", false))
context?.sendBroadcast(Intent().apply {
action = Const.ACTION_REMIND_HANDLER_RECEIVER
putExtra("isGrasp", true)
putExtra("isValied", intent?.isValiedModule)
})
}
}
}
/**
* 判断模块和宿主版本是否一致
* @return [Boolean]
*/
private val Intent.isValiedModule get() = getStringExtra(Const.MODULE_VERSION_VERIFY_TAG) == Const.MODULE_VERSION_VERIFY
/**
* 注册广播接收器
* @param context 实例
*/
private fun registerReceiver(context: Context) {
if (isRegisterReceiver) return
context.registerReceiver(userPresentReceiver, IntentFilter().apply { addAction(Intent.ACTION_USER_PRESENT) })
context.registerReceiver(moduleCheckingReceiver, IntentFilter().apply { addAction(Const.ACTION_MODULE_CHECKING_RECEIVER) })
context.registerReceiver(remindCheckingReceiver, IntentFilter().apply { addAction(Const.ACTION_REMIND_CHECKING_RECEIVER) })
isRegisterReceiver = true
}
/**
* 是否启用通知图标优化功能
* @param isHooking 是否判断启用通知功能 - 默认:是
@@ -366,6 +324,7 @@ class SystemUIHooker : YukiBaseHooker() {
emptyParam()
}.call()
}
modifyNotifyPanelAlpha(notificationPlayerView, isTint = true)
}
/**
@@ -469,6 +428,13 @@ class SystemUIHooker : YukiBaseHooker() {
) = runInSafe {
compatCustomIcon(isGrayscaleIcon, packageName).also { customPair ->
when {
prefs.get(DataConst.ENABLE_NOTIFY_ICON_FORCE_APP_ICON) && isEnableHookColorNotifyIcon(isHooking = false) ->
iconView.apply {
/** 重新设置图标 */
setImageDrawable(appIcons[packageName] ?: context.findAppIcon(packageName))
/** 设置默认样式 */
setDefaultNotifyIconViewStyle()
}
customPair.first != null || isGrayscaleIcon -> iconView.apply {
/** 设置不要裁切到边界 */
clipToOutline = false
@@ -508,23 +474,8 @@ class SystemUIHooker : YukiBaseHooker() {
else -> iconView.apply {
/** 重新设置图标 */
setImageDrawable(nf.compatPushingIcon(drawable))
/** 设置裁切到边界 */
clipToOutline = true
/** 设置一个圆角轮廓裁切 */
outlineProvider = object : ViewOutlineProvider() {
override fun getOutline(view: View, out: Outline) {
out.setRoundRect(
0, 0,
view.width, view.height, 3.dpFloat(context)
)
}
}
/** 清除图标间距 */
setPadding(0, 0, 0, 0)
/** 清除背景 */
background = null
/** 清除着色 */
colorFilter = null
/** 设置默认样式 */
setDefaultNotifyIconViewStyle()
}
}
/** 打印日志 */
@@ -534,12 +485,60 @@ class SystemUIHooker : YukiBaseHooker() {
/**
* 设置通知面板背景透明度
* @param view 背景 View 实例
* @param drawable 背景实例
* @param isTint 是否着色 [view]
*/
private fun modifyNotifyPanelAlpha(drawable: Drawable?) {
if (prefs.get(DataConst.ENABLE_NOTIFY_PANEL_ALPHA))
drawable?.alpha = prefs.get(DataConst.NOTIFY_PANEL_ALPHA)
else drawable?.alpha = 255
private fun modifyNotifyPanelAlpha(view: View?, drawable: Drawable? = null, isTint: Boolean = false) {
prefs.get(DataConst.ENABLE_NOTIFY_PANEL_ALPHA).also { isEnabled ->
val currentAlpha = prefs.get(DataConst.NOTIFY_PANEL_ALPHA)
val currendColor = if (view?.context?.isSystemInDarkMode == true) 0xFF404040.toInt() else 0xFFFAFAFA.toInt()
/** 设置通知面板背景透明度 */
when {
isEnabled.not() -> {
if (isTint) view?.backgroundTintList = ColorStateList.valueOf(currendColor)
else drawable?.setTint(currendColor)
}
isTint.not() && view?.parent?.parent?.javaClass?.name?.contains(other = "ChildrenContainer") == true -> drawable?.alpha = 0
else -> {
currendColor.colorAlphaOf(currentAlpha / 100f).also {
if (isTint) view?.backgroundTintList = ColorStateList.valueOf(it)
else drawable?.setTint(it)
}
}
}
/** 移除阴影效果 */
if (isEnabled) view?.elevation = 0f
}
}
/** 设置默认通知栏通知图标样式 */
private fun ImageView.setDefaultNotifyIconViewStyle() {
/** 设置裁切到边界 */
clipToOutline = true
/** 设置一个圆角轮廓裁切 */
outlineProvider = object : ViewOutlineProvider() {
override fun getOutline(view: View, out: Outline) {
out.setRoundRect(
0, 0,
view.width, view.height, 3.dpFloat(context)
)
}
}
/** 清除图标间距 */
setPadding(0, 0, 0, 0)
/** 清除背景 */
background = null
/** 清除着色 */
colorFilter = null
}
/** 注册 */
private fun register() {
/** 解锁后重新刷新状态栏图标防止系统重新设置它 */
onAppLifecycle { registerReceiver(Intent.ACTION_USER_PRESENT) { _, _ -> if (isUsingCachingMethod) refreshStatusBarIcons() } }
/** 刷新图标缓存 */
SystemUITool.Host.onRefreshSystemUI(param = this) { recachingPrefs(it) }
}
/** 缓存图标数据 */
@@ -556,17 +555,25 @@ class SystemUIHooker : YukiBaseHooker() {
/**
* 刷新缓存数据
* @param isRefreshCacheOnly 仅刷新缓存不刷新图标和通知改变 - 默认:否
* @return [Boolean] 是否成功
*/
private fun recachingPrefs(isRefreshCacheOnly: Boolean = false) {
isUsingCachingMethod = true
prefs.clearCache()
cachingIconDatas()
if (isRefreshCacheOnly) return
refreshStatusBarIcons()
refreshNotificationIcons()
private fun recachingPrefs(isRefreshCacheOnly: Boolean = false): Boolean {
/** 必要的延迟防止 Sp 存储不刷新 */
SystemClock.sleep(100)
/** 获取可读写状态 */
return prefs.isXSharePrefsReadable.also {
isUsingCachingMethod = true
prefs.clearCache()
cachingIconDatas()
if (isRefreshCacheOnly) return@also
refreshStatusBarIcons()
refreshNotificationIcons()
}
}
override fun onHook() {
/** 注册 */
register()
/** 缓存图标数据 */
cachingIconDatas()
/** 移除开发者警告通知 */
@@ -659,12 +666,8 @@ class SystemUIHooker : YukiBaseHooker() {
param(StatusBarNotificationClass)
}
afterHook {
if (args().first().any() != null) instance<ImageView>().also {
/** 注册壁纸颜色监听 */
registerWallpaperColorChanged(it)
/** 注册广播 */
registerReceiver(it.context)
}
/** 注册壁纸颜色监听 */
if (args().first().any() != null) instance<ImageView>().also { registerWallpaperColorChanged(it) }
}
}
}
@@ -703,8 +706,13 @@ class SystemUIHooker : YukiBaseHooker() {
method {
name = "drawRegionBlur"
paramCount = 2
}.remedys {
method {
name = "draw"
paramCount = 2
}
}
beforeHook { modifyNotifyPanelAlpha(args().last().cast<Drawable>()) }
beforeHook { modifyNotifyPanelAlpha(instance(), args().last().cast<Drawable>()) }
}
injectMember {
method {
@@ -712,7 +720,7 @@ class SystemUIHooker : YukiBaseHooker() {
paramCount = 2
superClass(isOnlySuperClass = true)
}
beforeHook { modifyNotifyPanelAlpha(args().last().cast<Drawable>()) }
beforeHook { modifyNotifyPanelAlpha(instance(), args().last().cast<Drawable>()) }
}
}.by { isOldNotificationBackground.not() }
/** 替换通知面板背景 - 旧版本 */
@@ -722,16 +730,70 @@ class SystemUIHooker : YukiBaseHooker() {
name = "draw"
paramCount = 2
}
beforeHook { modifyNotifyPanelAlpha(args().last().cast<Drawable>()) }
beforeHook { modifyNotifyPanelAlpha(instance(), args().last().cast<Drawable>()) }
}
injectMember {
method {
name = "drawCustom"
paramCount = 2
}
beforeHook { modifyNotifyPanelAlpha(args().last().cast<Drawable>()) }
beforeHook { modifyNotifyPanelAlpha(instance(), args().last().cast<Drawable>()) }
}
}.by { isOldNotificationBackground }
/** 替换通知面板背景 - 避免折叠展开通知二次修改通知面板背景 */
ExpandableNotificationRowClass.hook {
injectMember {
method {
name = "updateBackgroundForGroupState"
emptyParam()
}
beforeHook {
if (prefs.get(DataConst.ENABLE_NOTIFY_PANEL_ALPHA))
field { name = "mShowGroupBackgroundWhenExpanded" }.get(instance).setTrue()
}
}
}
/** 替换媒体通知面板背景 - 设置媒体通知自动展开 */
OplusMediaControlPanelClass.hook {
injectMember {
method {
name = "bind"
paramCount = 2
}
afterHook {
/** 得到当前实例 */
val holder = field {
name = "mViewHolder"
superClass(isOnlySuperClass = true)
}.get(instance).any()
/** 记录媒体通知 [View] */
notificationPlayerView = PlayerViewHolderClass.clazz.method {
name = "getPlayer"
emptyParam()
}.get(holder).invoke()
/** 设置背景着色 */
modifyNotifyPanelAlpha(notificationPlayerView, isTint = true)
/** 当前是否正在播放 */
val isPlaying = MediaDataClass.clazz.method {
name = "isPlaying"
emptyParam()
}.get(args().first().any()).boolean()
/** 当前通知是否展开 */
val isExpanded = OplusMediaViewControllerClass.clazz.method {
name = "getExpanded"
emptyParam()
}.get(field { name = "mOplusMediaViewController" }.get(instance).self).boolean()
/** 符合条件后执行 */
if (prefs.get(DataConst.ENABLE_NOTIFY_MEDIA_PANEL_AUTO_EXP).not() || isExpanded || isPlaying.not()) return@afterHook
/** 模拟手动展开通知 */
BasePlayViewHolderClass.clazz.method {
name = "getExpandButton"
emptyParam()
}.get(holder).invoke<View>()?.performClick()
}
}
}.ignoredHookClassNotFoundFailure()
/** 替换通知图标和样式 */
NotificationHeaderViewWrapperClass.hook {
injectMember {
@@ -805,8 +867,6 @@ class SystemUIHooker : YukiBaseHooker() {
}
afterHook {
args().first().cast<Context>()?.also {
/** 注册广播 */
registerReceiver(it)
/** 注册定时监听 */
if (isEnableHookColorNotifyIcon() && prefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX_AUTO))
IconAdaptationTool.prepareAutoUpdateIconRule(

View File

@@ -43,7 +43,7 @@ import com.fankes.coloros.notify.ui.activity.base.BaseActivity
import com.fankes.coloros.notify.utils.factory.*
import com.fankes.coloros.notify.utils.tool.IconRuleManagerTool
import com.fankes.coloros.notify.utils.tool.SystemUITool
import com.highcapable.yukihookapi.hook.factory.isXposedModuleActive
import com.highcapable.yukihookapi.YukiHookAPI
class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
@@ -61,7 +61,7 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
override fun onCreate() {
/** 检查激活状态 */
if (isXposedModuleActive.not()) {
if (YukiHookAPI.Status.isXposedModuleActive.not()) {
showDialog {
title = "模块没有激活"
msg = "模块没有激活,你无法使用这里的功能,请先激活模块。"
@@ -154,8 +154,19 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
holder.adpAppAllSwitch.isChecked = isAppNotifyHookAllOf(it)
holder.adpAppAllSwitch.setOnCheckedChangeListener { btn, b ->
if (btn.isPressed.not()) return@setOnCheckedChangeListener
putAppNotifyHookAllOf(it, b)
SystemUITool.refreshSystemUI(context = this@ConfigureActivity)
fun saveState() {
putAppNotifyHookAllOf(it, b)
SystemUITool.refreshSystemUI(context = this@ConfigureActivity)
}
if (b) showDialog {
title = "全部替换"
msg = "此功能仅针对严重不遵守规范的 APP 通知图标才需要开启例如APP 推送通知后无法识别出现的黑白块图标。\n\n" +
"此功能在一般情况下请保持关闭并跟随在线规则的配置,并不要随意改变此配置," +
"开启后 APP 的通知图标可能会被规则破坏,你确定还要开启吗?"
confirmButton { saveState() }
cancelButton { btn.isChecked = btn.isChecked.not() }
noCancelable()
} else saveState()
}
}
return cView!!
@@ -176,7 +187,13 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
}
/** 设置点击事件 */
binding.configCbrButton.setOnClickListener {
openBrowser(url = "https://github.com/fankes/AndroidNotifyIconAdapt/blob/main/CONTRIBUTING.md")
showDialog {
title = "感谢你的贡献"
msg = "通知图标优化名单需要大家的共同维护才能得以完善,请选择你的贡献方式。"
confirmButton(text = "贡献规则") { openBrowser(url = "https://github.com/fankes/AndroidNotifyIconAdapt/blob/main/CONTRIBUTING.md") }
cancelButton(text = "请求适配") { openBrowser(url = "https://github.com/fankes/ColorOSNotifyIcon/issues/new/choose") }
neutralButton(text = "暂时不用")
}
}
/** 装载数据 */
mockLocalData()

View File

@@ -38,9 +38,9 @@ import com.fankes.coloros.notify.ui.activity.base.BaseActivity
import com.fankes.coloros.notify.utils.factory.*
import com.fankes.coloros.notify.utils.tool.GithubReleaseTool
import com.fankes.coloros.notify.utils.tool.SystemUITool
import com.highcapable.yukihookapi.hook.factory.isXposedModuleActive
import com.fankes.coloros.notify.utils.tool.YukiPromoteTool
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.hook.factory.modulePrefs
import com.highcapable.yukihookapi.hook.xposed.YukiHookModuleStatus
class MainActivity : BaseActivity<ActivityMainBinding>() {
@@ -87,7 +87,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
noCancelable()
}
/** 判断是否 Hook */
isXposedModuleActive -> {
YukiHookAPI.Status.isXposedModuleActive -> {
if (IconPackParams(context = this).iconDatas.isEmpty() && modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX))
showDialog {
title = "配置通知图标优化名单"
@@ -105,6 +105,8 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
cancelButton()
noCancelable()
}
/** 推广、恰饭 */
YukiPromoteTool.promote(context = this)
}
else ->
showDialog {
@@ -122,25 +124,34 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
binding.a12StyleConfigItem.isVisible = modulePrefs.get(DataConst.ENABLE_MODULE)
binding.notifyIconConfigItem.isVisible = modulePrefs.get(DataConst.ENABLE_MODULE)
binding.notifyIconFixButton.isVisible = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX)
binding.notifyIconForceAppIconItem.isVisible = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX)
binding.notifyIconFixNotifyItem.isVisible = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX)
binding.notifyIconAutoSyncItem.isVisible = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX)
binding.notifyIconAutoSyncChildItem.isVisible = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX_AUTO)
binding.notifyPanelConfigSeekbar.isVisible = modulePrefs.get(DataConst.ENABLE_NOTIFY_PANEL_ALPHA)
binding.notifyPanelConfigText.isVisible = modulePrefs.get(DataConst.ENABLE_NOTIFY_PANEL_ALPHA)
binding.notifyPanelConfigTextPanel.isVisible = modulePrefs.get(DataConst.ENABLE_NOTIFY_PANEL_ALPHA)
binding.notifyPanelConfigWarnPanel.isVisible = modulePrefs.get(DataConst.ENABLE_NOTIFY_PANEL_ALPHA)
binding.devNotifyConfigSwitch.isChecked = modulePrefs.get(DataConst.REMOVE_DEV_NOTIFY)
binding.crcpNotifyConfigSwitch.isChecked = modulePrefs.get(DataConst.REMOVE_CHANGECP_NOTIFY)
binding.dndNotifyConfigSwitch.isChecked = modulePrefs.get(DataConst.REMOVE_DNDALERT_NOTIFY)
binding.a12StyleConfigSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_ANDROID12_STYLE)
binding.notifyMediaPanelAutoExpSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_NOTIFY_MEDIA_PANEL_AUTO_EXP)
binding.moduleEnableSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_MODULE)
binding.moduleEnableLogSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_MODULE_LOG)
binding.hideIconInLauncherSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_HIDE_ICON)
binding.notifyIconFixSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX)
binding.notifyIconForceAppIconSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FORCE_APP_ICON)
binding.notifyIconFixNotifySwitch.isChecked = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX_NOTIFY)
binding.notifyIconAutoSyncSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX_AUTO)
binding.notifyPanelConfigSwitch.isChecked = modulePrefs.get(DataConst.ENABLE_NOTIFY_PANEL_ALPHA)
binding.notifyPanelConfigSeekbar.progress = modulePrefs.get(DataConst.NOTIFY_PANEL_ALPHA)
binding.notifyPanelConfigText.text = "当前值 - ${modulePrefs.get(DataConst.NOTIFY_PANEL_ALPHA)}"
binding.notifyPanelConfigText.text = "${modulePrefs.get(DataConst.NOTIFY_PANEL_ALPHA)}%"
binding.notifyIconAutoSyncText.text = notifyIconAutoSyncTime
/** 媒体通知自动展开仅支持 12.1 - 旧版本适配过于复杂已放弃 */
if (colorOSNumberVersion != "V12.1") {
binding.notifyMediaPanelAutoExpSwitch.isVisible = false
binding.notifyMediaPanelAutoExpText.isVisible = false
}
binding.moduleEnableSwitch.setOnCheckedChangeListener { btn, b ->
if (btn.isPressed.not()) return@setOnCheckedChangeListener
modulePrefs.put(DataConst.ENABLE_MODULE, b)
@@ -168,10 +179,27 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
if (btn.isPressed.not()) return@setOnCheckedChangeListener
modulePrefs.put(DataConst.ENABLE_NOTIFY_ICON_FIX, b)
binding.notifyIconFixButton.isVisible = b
binding.notifyIconForceAppIconItem.isVisible = b
binding.notifyIconFixNotifyItem.isVisible = b
binding.notifyIconAutoSyncItem.isVisible = b
SystemUITool.refreshSystemUI(context = this)
}
binding.notifyIconForceAppIconSwitch.setOnCheckedChangeListener { btn, b ->
if (btn.isPressed.not()) return@setOnCheckedChangeListener
fun saveState() {
modulePrefs.put(DataConst.ENABLE_NOTIFY_ICON_FORCE_APP_ICON, b)
SystemUITool.refreshSystemUI(context = this)
}
if (b) showDialog {
title = "破坏性功能警告"
msg = "开启这个功能后,任何通知栏中的通知图标都会被强制替换为当前推送通知的 APP 的图标," +
"某些系统级别的 APP 通知图标可能会显示异常或发生图标丢失。\n\n" +
"此功能仅面向一些追求图标美观度的用户,我们不推荐开启这个功能,且发生任何 BUG 都不会去修复,仍然继续开启吗?"
confirmButton { saveState() }
cancelButton { btn.isChecked = btn.isChecked.not() }
noCancelable()
} else saveState()
}
binding.notifyIconFixNotifySwitch.setOnCheckedChangeListener { btn, b ->
if (btn.isPressed.not()) return@setOnCheckedChangeListener
modulePrefs.put(DataConst.ENABLE_NOTIFY_ICON_FIX_NOTIFY, b)
@@ -197,10 +225,16 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
modulePrefs.put(DataConst.ENABLE_ANDROID12_STYLE, b)
SystemUITool.refreshSystemUI(context = this)
}
binding.notifyMediaPanelAutoExpSwitch.setOnCheckedChangeListener { btn, b ->
if (btn.isPressed.not()) return@setOnCheckedChangeListener
modulePrefs.put(DataConst.ENABLE_NOTIFY_MEDIA_PANEL_AUTO_EXP, b)
SystemUITool.refreshSystemUI(context = this, isRefreshCacheOnly = true)
}
binding.notifyPanelConfigSwitch.setOnCheckedChangeListener { btn, b ->
if (btn.isPressed.not()) return@setOnCheckedChangeListener
modulePrefs.put(DataConst.ENABLE_NOTIFY_PANEL_ALPHA, b)
binding.notifyPanelConfigText.isVisible = b
binding.notifyPanelConfigTextPanel.isVisible = b
binding.notifyPanelConfigWarnPanel.isVisible = b
binding.notifyPanelConfigSeekbar.isVisible = b
SystemUITool.refreshSystemUI(context = this)
}
@@ -212,7 +246,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
}
binding.notifyPanelConfigSeekbar.setOnSeekBarChangeListener(object : OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
binding.notifyPanelConfigText.text = "当前值 - $progress"
binding.notifyPanelConfigText.text = "$progress%"
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
@@ -260,36 +294,36 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
private fun refreshModuleStatus() {
binding.mainLinStatus.setBackgroundResource(
when {
isXposedModuleActive && (isModuleRegular.not() || isModuleValied.not()) -> R.drawable.bg_yellow_round
isXposedModuleActive -> R.drawable.bg_green_round
YukiHookAPI.Status.isXposedModuleActive && (isModuleRegular.not() || isModuleValied.not()) -> R.drawable.bg_yellow_round
YukiHookAPI.Status.isXposedModuleActive -> R.drawable.bg_green_round
else -> R.drawable.bg_dark_round
}
)
binding.mainImgStatus.setImageResource(
when {
isXposedModuleActive -> R.mipmap.ic_success
YukiHookAPI.Status.isXposedModuleActive -> R.mipmap.ic_success
else -> R.mipmap.ic_warn
}
)
binding.mainTextStatus.text =
when {
isXposedModuleActive && isModuleRegular.not() && modulePrefs.get(DataConst.ENABLE_MODULE).not() -> "模块已停用"
isXposedModuleActive && isModuleRegular.not() -> "模块已激活,请重启系统界面"
isXposedModuleActive && isModuleValied.not() -> "模块已更新,请重启系统界面"
isXposedModuleActive -> "模块已激活"
YukiHookAPI.Status.isXposedModuleActive && isModuleRegular.not() && modulePrefs.get(DataConst.ENABLE_MODULE).not() -> "模块已停用"
YukiHookAPI.Status.isXposedModuleActive && isModuleRegular.not() -> "模块已激活,请重启系统界面"
YukiHookAPI.Status.isXposedModuleActive && isModuleValied.not() -> "模块已更新,请重启系统界面"
YukiHookAPI.Status.isXposedModuleActive -> "模块已激活"
else -> "模块未激活"
}
binding.mainTextApiWay.isVisible = isXposedModuleActive
binding.mainTextApiWay.text = "Activated by ${YukiHookModuleStatus.executorName} API ${YukiHookModuleStatus.executorVersion}"
binding.mainTextApiWay.isVisible = YukiHookAPI.Status.isXposedModuleActive
binding.mainTextApiWay.text = "Activated by ${YukiHookAPI.Status.executorName} API ${YukiHookAPI.Status.executorVersion}"
}
override fun onResume() {
super.onResume()
/** 刷新模块状态 */
refreshModuleStatus()
/** 发送广播检查模块激活状态 */
SystemUITool.checkingActivated(context = this) { isRegular, isValied ->
isModuleRegular = isRegular
/** 检查模块激活状态 */
SystemUITool.checkingActivated(context = this) { isValied ->
isModuleRegular = true
isModuleValied = isValied
refreshModuleStatus()
}

View File

@@ -48,8 +48,6 @@ class NotifyIconRuleUpdateActivity : Activity() {
finish()
return
}
/** 注册 */
SystemUITool.register(context = this)
/** 拉取云端数据 */
IconRuleManagerTool.sync(appContext) {
/** 刷新系统界面 */
@@ -60,10 +58,4 @@ class NotifyIconRuleUpdateActivity : Activity() {
/** 切换到后台 */
moveTaskToBack(true)
}
override fun onDestroy() {
super.onDestroy()
/** 解除注册 */
SystemUITool.unregister(context = this)
}
}

View File

@@ -26,11 +26,11 @@ package com.fankes.coloros.notify.ui.activity.base
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.res.ResourcesCompat
import androidx.core.view.ViewCompat
import androidx.viewbinding.ViewBinding
import com.fankes.coloros.notify.R
import com.fankes.coloros.notify.utils.factory.isNotSystemInDarkMode
import com.fankes.coloros.notify.utils.tool.SystemUITool
import com.gyf.immersionbar.ktx.immersionBar
import com.highcapable.yukihookapi.hook.factory.method
import com.highcapable.yukihookapi.hook.type.android.LayoutInflaterClass
import java.lang.reflect.ParameterizedType
@@ -61,26 +61,19 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
/** 隐藏系统的标题栏 */
supportActionBar?.hide()
/** 初始化沉浸状态栏 */
immersionBar {
statusBarColor(R.color.colorThemeBackground)
autoDarkModeEnable(true)
statusBarDarkFont(isNotSystemInDarkMode)
navigationBarColor(R.color.colorThemeBackground)
navigationBarDarkIcon(isNotSystemInDarkMode)
fitsSystemWindows(true)
ViewCompat.getWindowInsetsController(window.decorView)?.apply {
isAppearanceLightStatusBars = isNotSystemInDarkMode
isAppearanceLightNavigationBars = isNotSystemInDarkMode
}
ResourcesCompat.getColor(resources, R.color.colorThemeBackground, null).also {
window?.statusBarColor = it
window?.navigationBarColor = it
window?.navigationBarDividerColor = it
}
/** 注册 */
SystemUITool.register(context = this)
/** 装载子类 */
onCreate()
}
/** 回调 [onCreate] 方法 */
abstract fun onCreate()
override fun onDestroy() {
super.onDestroy()
/** 解除注册 */
SystemUITool.unregister(context = this)
}
}

View File

@@ -46,18 +46,18 @@ import com.highcapable.yukihookapi.hook.type.android.LayoutInflaterClass
/**
* 构造对话框
* @param isUseBlackTheme 是否使用深色主题
* @param it 对话框方法体
* @param initiate 对话框方法体
*/
fun Context.showDialog(isUseBlackTheme: Boolean = false, it: DialogBuilder.() -> Unit) =
DialogBuilder(this, isUseBlackTheme).apply(it).show()
fun Context.showDialog(isUseBlackTheme: Boolean = false, initiate: DialogBuilder.() -> Unit) =
DialogBuilder(context = this, isUseBlackTheme).apply(initiate).show()
/**
* 显示时间选择对话框
* @param timeSet 当前时间 - 不写将使用当前时间格式HH:mm
* @param it 回调 - 小时与分钟 HH:mm
* @param result 回调 - 小时与分钟 HH:mm
*/
fun Context.showTimePicker(timeSet: String = "", it: (String) -> Unit) =
TimePickerDialog(this, { _, h, m -> it("${h.autoZero}:${m.autoZero}") }, timeSet.hour, timeSet.minute, true).show()
fun Context.showTimePicker(timeSet: String = "", result: (String) -> Unit) =
TimePickerDialog(this, { _, h, m -> result("${h.autoZero}:${m.autoZero}") }, timeSet.hour, timeSet.minute, true).show()
/**
* 对话框构造器
@@ -150,34 +150,34 @@ class DialogBuilder(val context: Context, private val isUseBlackTheme: Boolean)
/**
* 设置对话框确定按钮
* @param text 按钮文本内容
* @param it 点击事件
* @param callback 点击事件
*/
fun confirmButton(text: String = "确定", it: () -> Unit = {}) {
fun confirmButton(text: String = "确定", callback: () -> Unit = {}) {
if (isUsingAndroidX)
runInSafe { instanceAndroidX?.setPositiveButton(text) { _, _ -> it() } }
else runInSafe { instanceAndroid?.setPositiveButton(text) { _, _ -> it() } }
runInSafe { instanceAndroidX?.setPositiveButton(text) { _, _ -> callback() } }
else runInSafe { instanceAndroid?.setPositiveButton(text) { _, _ -> callback() } }
}
/**
* 设置对话框取消按钮
* @param text 按钮文本内容
* @param it 点击事件
* @param callback 点击事件
*/
fun cancelButton(text: String = "取消", it: () -> Unit = {}) {
fun cancelButton(text: String = "取消", callback: () -> Unit = {}) {
if (isUsingAndroidX)
runInSafe { instanceAndroidX?.setNegativeButton(text) { _, _ -> it() } }
else runInSafe { instanceAndroid?.setNegativeButton(text) { _, _ -> it() } }
runInSafe { instanceAndroidX?.setNegativeButton(text) { _, _ -> callback() } }
else runInSafe { instanceAndroid?.setNegativeButton(text) { _, _ -> callback() } }
}
/**
* 设置对话框第三个按钮
* @param text 按钮文本内容
* @param it 点击事件
* @param callback 点击事件
*/
fun neutralButton(text: String = "更多", it: () -> Unit = {}) {
fun neutralButton(text: String = "更多", callback: () -> Unit = {}) {
if (isUsingAndroidX)
runInSafe { instanceAndroidX?.setNeutralButton(text) { _, _ -> it() } }
else runInSafe { instanceAndroid?.setNeutralButton(text) { _, _ -> it() } }
runInSafe { instanceAndroidX?.setNeutralButton(text) { _, _ -> callback() } }
else runInSafe { instanceAndroid?.setNeutralButton(text) { _, _ -> callback() } }
}
/** 取消对话框 */

View File

@@ -138,14 +138,20 @@ val colorOSFullVersion get() = "${if (isRealmeUI) "RealmeUI " else ""}$colorOSVe
* 获取 ColorOS 版本
* @return [String]
*/
val colorOSVersion
val colorOSVersion get() = "$colorOSNumberVersion ${Build.DISPLAY}"
/**
* 获取 ColorOS 数字版本
* @return [String]
*/
val colorOSNumberVersion
get() = safeOf(default = "无法获取") {
(classOf(name = "com.oplus.os.OplusBuild").let {
it.field { name = "VERSIONS" }.ignoredError().get().array<String>().takeIf { e -> e.isNotEmpty() }
?.get(it.method { name = "getOplusOSVERSION" }.ignoredError().get().int() - 1)
} ?: findPropString(
key = "ro.system.build.fingerprint", default = "无法获取"
).split("ssi:")[1].split("/")[0].trim()) + " ${Build.DISPLAY}"
).split("ssi:")[1].split("/")[0].trim())
}
/**
@@ -280,6 +286,13 @@ val Int.isWhite
(0.2126 * r + 0.7152 * g + 0.0722 * b) >= 128
}
/**
* 调整颜色透明度
* @param value 透明度
* @return [Int] 调整后的颜色
*/
fun Int.colorAlphaOf(value: Float) = safeOfNan { (255.coerceAtMost(0.coerceAtLeast((value * 255).toInt())) shl 24) + (0x00ffffff and this) }
/**
* Base64 加密
* @return [String]
@@ -357,27 +370,23 @@ fun toast(msg: String) = Toast.makeText(appContext, msg, Toast.LENGTH_SHORT).sho
*
* [T] 为指定的 [Activity]
*/
inline fun <reified T : Activity> Context.navigate() = runInSafe { startActivity(Intent(this, T::class.java)) }
/**
* 跳转到指定页面
*
* [T] 为指定的 [Activity]
*/
inline fun <reified T : Activity> Service.navigate() =
runInSafe { startActivity(Intent(this, T::class.java).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK }) }
inline fun <reified T : Activity> Context.navigate() = runInSafe {
startActivity(Intent(if (this is Service) applicationContext else this, T::class.java).apply {
if (this@navigate !is Activity) flags = Intent.FLAG_ACTIVITY_NEW_TASK
})
}
/**
* 弹出 [Snackbar]
* @param msg 提示内容
* @param actionText 按钮文本 - 不写默认取消按钮
* @param it 按钮事件回调
* @param callback 按钮事件回调
*/
fun Context.snake(msg: String, actionText: String = "", it: () -> Unit = {}) =
fun Context.snake(msg: String, actionText: String = "", callback: () -> Unit = {}) =
Snackbar.make((this as Activity).findViewById(android.R.id.content), msg, Snackbar.LENGTH_LONG).apply {
if (actionText.isBlank()) return@apply
setActionTextColor(if (isSystemInDarkMode) Color.BLACK else Color.WHITE)
setAction(actionText) { it() }
setAction(actionText) { callback() }
}.show()
/**

View File

@@ -45,9 +45,9 @@ object GithubReleaseTool {
* 获取最新版本信息
* @param context 实例
* @param version 当前版本
* @param it 成功后回调 - ([String] 最新版本,[Function] 更新对话框方法体)
* @param result 成功后回调 - ([String] 最新版本,[Function] 更新对话框方法体)
*/
fun checkingForUpdate(context: Context, version: String, it: (String, () -> Unit) -> Unit) = checkingInternetConnect(context) {
fun checkingForUpdate(context: Context, version: String, result: (String, () -> Unit) -> Unit) = checkingInternetConnect(context) {
OkHttpClient().newBuilder().build().newCall(
Request.Builder()
.url("https://api.github.com/repos/$REPO_AUTHOR/$REPO_NAME/releases/latest")
@@ -73,7 +73,7 @@ object GithubReleaseTool {
}
if (name != version) (context as? Activity?)?.runOnUiThread {
showUpdate()
it(name) { showUpdate() }
result(name) { showUpdate() }
}
}
}
@@ -84,9 +84,9 @@ object GithubReleaseTool {
/**
* 检查网络连接情况
* @param context 实例
* @param it 已连接回调
* @param result 已连接回调
*/
private fun checkingInternetConnect(context: Context, it: () -> Unit) = runInSafe {
private fun checkingInternetConnect(context: Context, result: () -> Unit) = runInSafe {
if (isNetWorkSuccess)
OkHttpClient().newBuilder().build().newCall(
Request.Builder()
@@ -107,7 +107,7 @@ object GithubReleaseTool {
}
override fun onResponse(call: Call, response: Response) = runInSafe {
(context as? Activity?)?.runOnUiThread { runInSafe { it() } }
(context as? Activity?)?.runOnUiThread { runInSafe { result() } }
}
})
}

View File

@@ -33,7 +33,7 @@ import android.graphics.Bitmap
import android.graphics.drawable.Icon
import android.os.Build
import androidx.core.graphics.drawable.toBitmap
import com.fankes.coloros.notify.const.Const
import com.fankes.coloros.notify.BuildConfig
import com.fankes.coloros.notify.hook.HookEntry
import com.fankes.coloros.notify.utils.factory.*
@@ -44,6 +44,9 @@ import com.fankes.coloros.notify.utils.factory.*
*/
object IconAdaptationTool {
/** 当前模块的包名 */
private const val MODULE_PACKAGE_NAME = BuildConfig.APPLICATION_ID
/** 推送通知的渠道名称 */
private const val NOTIFY_CHANNEL = "notifyRuleSupportId"
@@ -137,8 +140,8 @@ object IconAdaptationTool {
context, packageName.hashCode(),
Intent().apply {
component = ComponentName(
Const.MODULE_PACKAGE_NAME,
"${Const.MODULE_PACKAGE_NAME}.ui.activity.ConfigureActivity"
MODULE_PACKAGE_NAME,
"${MODULE_PACKAGE_NAME}.ui.activity.ConfigureActivity"
)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}.apply {
@@ -177,8 +180,8 @@ object IconAdaptationTool {
context.startActivity(
Intent().apply {
component = ComponentName(
Const.MODULE_PACKAGE_NAME,
"${Const.MODULE_PACKAGE_NAME}.ui.activity.auto.NotifyIconRuleUpdateActivity"
MODULE_PACKAGE_NAME,
"${MODULE_PACKAGE_NAME}.ui.activity.auto.NotifyIconRuleUpdateActivity"
)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}

View File

@@ -75,9 +75,9 @@ object IconRuleManagerTool {
/**
* 从在线地址手动同步规则
* @param context 实例
* @param it 成功后回调
* @param callback 成功后回调
*/
fun syncByHand(context: Context, it: () -> Unit) =
fun syncByHand(context: Context, callback: () -> Unit) =
context.showDialog {
title = "同步列表"
var sourceType = context.modulePrefs.get(DataConst.SOURCE_SYNC_WAY)
@@ -116,7 +116,7 @@ object IconRuleManagerTool {
confirmButton {
context.modulePrefs.put(DataConst.SOURCE_SYNC_WAY, sourceType)
context.modulePrefs.put(DataConst.SOURCE_SYNC_WAY_CUSTOM_URL, customUrl)
sync(context, sourceType, customUrl, it)
sync(context, sourceType, customUrl, callback)
}
cancelButton()
neutralButton(text = "自定义规则") {
@@ -139,7 +139,7 @@ object IconRuleManagerTool {
)
)
notifyRefresh(context)
it()
callback()
}
else -> context.snake(msg = "请输入有效内容")
}
@@ -152,7 +152,7 @@ object IconRuleManagerTool {
jsonString.isNotBlank() -> {
params.save(dataJson = jsonString.takeIf { params.isJsonArray(it) } ?: "[$jsonString]")
notifyRefresh(context)
it()
callback()
}
else -> context.snake(msg = "请输入有效内容")
}
@@ -169,23 +169,23 @@ object IconRuleManagerTool {
* @param context 实例
* @param sourceType 同步地址类型 - 默认自动获取已存储的键值
* @param customUrl 自定义同步地址 - 默认自动获取已存储的键值
* @param it 成功后回调
* @param callback 成功后回调
*/
fun sync(
context: Context,
sourceType: Int = context.modulePrefs.get(DataConst.SOURCE_SYNC_WAY),
customUrl: String = context.modulePrefs.get(DataConst.SOURCE_SYNC_WAY_CUSTOM_URL),
it: () -> Unit
callback: () -> Unit
) {
when (sourceType) {
TYPE_SOURCE_SYNC_WAY_1 ->
onRefreshing(context, url = "https://raw.fastgit.org/fankes/AndroidNotifyIconAdapt/main", it)
onRefreshing(context, url = "https://raw.fastgit.org/fankes/AndroidNotifyIconAdapt/main", callback)
TYPE_SOURCE_SYNC_WAY_2 ->
onRefreshing(context, url = "https://raw.githubusercontent.com/fankes/AndroidNotifyIconAdapt/main", it)
onRefreshing(context, url = "https://raw.githubusercontent.com/fankes/AndroidNotifyIconAdapt/main", callback)
TYPE_SOURCE_SYNC_WAY_3 ->
if (customUrl.isNotBlank())
if (customUrl.startsWith("http://") || customUrl.startsWith("https://"))
onRefreshingCustom(context, customUrl, it)
onRefreshingCustom(context, customUrl, callback)
else context.snakeOrNotify(title = "同步失败", msg = "同步地址不是一个合法的 URL")
else context.snakeOrNotify(title = "同步失败", msg = "同步地址不能为空")
else -> context.snakeOrNotify(title = "同步异常", msg = "同步类型错误")
@@ -196,14 +196,14 @@ object IconRuleManagerTool {
* 开始更新数据
* @param context 实例
* @param url
* @param it 成功后回调
* @param callback 成功后回调
*/
private fun onRefreshing(context: Context, url: String, it: () -> Unit) = checkingInternetConnect(context) {
fun doParse(callback: (Boolean) -> Unit = {}) {
private fun onRefreshing(context: Context, url: String, callback: () -> Unit) = checkingInternetConnect(context) {
fun doParse(result: (Boolean) -> Unit = {}) {
wait(context, url = "$url/OS/$OS_TAG/NotifyIconsSupportConfig.json") { isDone1, ctOS ->
callback(true)
result(true)
wait(context, url = "$url/APP/NotifyIconsSupportConfig.json") { isDone2, ctAPP ->
callback(false)
result(false)
IconPackParams(context).also { params ->
when {
isDone1 && isDone2 -> params.splicingJsonArray(ctOS, ctAPP).also {
@@ -216,7 +216,7 @@ object IconRuleManagerTool {
params.save(it)
pushNotify(context, title = "同步完成", msg = "已更新通知图标优化名单,点击查看")
notifyRefresh(context)
it()
callback()
}
else -> (if (context is AppCompatActivity) context.snake(msg = "列表数据已是最新"))
}
@@ -225,7 +225,7 @@ object IconRuleManagerTool {
context.showDialog {
title = "连接失败"
msg = "连接失败,错误如下:\n${if (isDone1.not()) ctOS else ctAPP}"
confirmButton(text = "再试一次") { syncByHand(context, it) }
confirmButton(text = "再试一次") { syncByHand(context, callback) }
cancelButton()
}
else -> pushNotify(context, title = "同步地址不可用", msg = if (isDone1.not()) ctOS else ctAPP)
@@ -248,12 +248,12 @@ object IconRuleManagerTool {
* 开始更新数据
* @param context 实例
* @param url
* @param it 成功后回调
* @param callback 成功后回调
*/
private fun onRefreshingCustom(context: Context, url: String, it: () -> Unit) = checkingInternetConnect(context) {
fun doParse(callback: () -> Unit = {}) {
private fun onRefreshingCustom(context: Context, url: String, callback: () -> Unit) = checkingInternetConnect(context) {
fun doParse(result: () -> Unit = {}) {
wait(context, url) { isDone, content ->
callback()
result()
IconPackParams(context).also { params ->
when {
isDone -> when {
@@ -265,7 +265,7 @@ object IconRuleManagerTool {
params.save(content)
pushNotify(context, title = "同步完成", msg = "已更新通知图标优化名单,点击查看")
notifyRefresh(context)
it()
callback()
}
else -> (if (context is AppCompatActivity) context.snake(msg = "列表数据已是最新"))
}
@@ -293,16 +293,16 @@ object IconRuleManagerTool {
/**
* 检查网络连接情况
* @param context 实例
* @param it 已连接回调
* @param callback 已连接回调
*/
private fun checkingInternetConnect(context: Context, it: () -> Unit) =
private fun checkingInternetConnect(context: Context, callback: () -> Unit) =
if (context is AppCompatActivity) context.showDialog {
title = "准备中"
progressContent = "正在检查网络连接情况"
noCancelable()
baseCheckingInternetConnect(context) { isDone ->
cancel()
if (isDone) it() else
if (isDone) callback() else
context.showDialog {
title = "网络不可用"
msg = "无法连接到互联网,请检查你当前的设备是否可以上网,且没有在手机管家中禁用本模块的联网权限。"
@@ -319,24 +319,24 @@ object IconRuleManagerTool {
}
}
} else baseCheckingInternetConnect(context) { isDone ->
if (isDone) it() else pushNotify(context, title = "网络不可用", msg = "无法连接到互联网,无法更新通知图标规则")
if (isDone) callback() else pushNotify(context, title = "网络不可用", msg = "无法连接到互联网,无法更新通知图标规则")
}
/**
* 检查网络连接情况
* @param context 实例
* @param it 已连接回调
* @param result 已连接回调
*/
private fun baseCheckingInternetConnect(context: Context, it: (Boolean) -> Unit) =
wait(context, url = "https://www.baidu.com") { isDone, _ -> it(isDone) }
private fun baseCheckingInternetConnect(context: Context, result: (Boolean) -> Unit) =
wait(context, url = "https://www.baidu.com") { isDone, _ -> result(isDone) }
/**
* 发送 GET 请求内容并等待
* @param context 实例
* @param url 请求地址
* @param it 回调 - ([Boolean] 是否成功,[String] 成功的内容或失败消息)
* @param result 回调 - ([Boolean] 是否成功,[String] 成功的内容或失败消息)
*/
private fun wait(context: Context, url: String, it: (Boolean, String) -> Unit) = runCatching {
private fun wait(context: Context, url: String, result: (Boolean, String) -> Unit) = runCatching {
OkHttpClient().newBuilder().apply {
SSLSocketClient.sSLSocketFactory?.let { sslSocketFactory(it, SSLSocketClient.trustManager) }
hostnameVerifier(SSLSocketClient.hostnameVerifier)
@@ -347,15 +347,15 @@ object IconRuleManagerTool {
.build()
).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
(context as? Activity?)?.runOnUiThread { it(false, e.toString()) } ?: it(false, e.toString())
(context as? Activity?)?.runOnUiThread { result(false, e.toString()) } ?: result(false, e.toString())
}
override fun onResponse(call: Call, response: Response) {
val bodyString = response.body?.string() ?: ""
(context as? Activity?)?.runOnUiThread { it(true, bodyString) } ?: it(true, bodyString)
(context as? Activity?)?.runOnUiThread { result(true, bodyString) } ?: result(true, bodyString)
}
})
}.onFailure { it(false, "URL 无效") }
}.onFailure { result(false, "URL 无效") }
/**
* 推送通知图标更新通知

View File

@@ -22,59 +22,44 @@
*/
package com.fankes.coloros.notify.utils.tool
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import com.fankes.coloros.notify.const.Const
import com.fankes.coloros.notify.hook.HookConst.SYSTEMUI_PACKAGE_NAME
import com.fankes.coloros.notify.utils.factory.*
import com.google.android.material.snackbar.Snackbar
import com.highcapable.yukihookapi.hook.factory.isXposedModuleActive
import com.highcapable.yukihookapi.hook.xposed.application.ModuleApplication.Companion.appContext
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.hook.factory.dataChannel
import com.highcapable.yukihookapi.hook.param.PackageParam
import com.highcapable.yukihookapi.hook.xposed.channel.data.ChannelData
/**
* 系统界面工具
*/
object SystemUITool {
/** 宿主广播回调 */
private var moduleHandlerCallback: ((Boolean, Boolean) -> Unit)? = null
/** 通知广播回调 */
private var remindHandlerCallback: ((Boolean, Boolean) -> Unit)? = null
private val CALL_HOST_REFRESH_CACHING = ChannelData("call_host_refresh_caching", false)
private val CALL_MODULE_REFRESH_RESULT = ChannelData("call_module_refresh_result", false)
/**
* 注册广播
* @param context 实例
* 宿主注册监听
*/
fun register(context: Context) {
/** 注册广播检查模块激活状态 */
context.registerReceiver(moduleHandlerReceiver, IntentFilter().apply { addAction(Const.ACTION_MODULE_HANDLER_RECEIVER) })
/** 注册广播通知系统界面改变 */
context.registerReceiver(remindHandlerReceiver, IntentFilter().apply { addAction(Const.ACTION_REMIND_HANDLER_RECEIVER) })
}
object Host {
/**
* 取消注册广播
* @param context 实例
*/
fun unregister(context: Context) {
context.unregisterReceiver(moduleHandlerReceiver)
context.unregisterReceiver(remindHandlerReceiver)
/**
* 监听系统界面刷新改变
* @param param 实例
* @param result 回调 - ([Boolean] 是否成功)
*/
fun onRefreshSystemUI(param: PackageParam, result: (Boolean) -> Boolean) {
param.dataChannel.with { wait(CALL_HOST_REFRESH_CACHING) { put(CALL_MODULE_REFRESH_RESULT, result(it)) } }
}
}
/**
* 检查模块是否激活
* @param context 实例
* @param it 成功后回调 - ([Boolean] 是否激活,[Boolean] 是否有效)
* @param result 成功后回调
*/
fun checkingActivated(context: Context, it: (Boolean, Boolean) -> Unit) {
moduleHandlerCallback = it
context.sendBroadcast(Intent().apply {
action = Const.ACTION_MODULE_CHECKING_RECEIVER
putExtra(Const.MODULE_VERSION_VERIFY_TAG, Const.MODULE_VERSION_VERIFY)
})
}
fun checkingActivated(context: Context, result: (Boolean) -> Unit) = context.dataChannel(SYSTEMUI_PACKAGE_NAME).checkingVersionEquals(result)
/**
* 重启系统界面
@@ -99,17 +84,10 @@ object SystemUITool {
* 刷新系统界面状态栏与通知图标
* @param context 实例
* @param isRefreshCacheOnly 仅刷新缓存不刷新图标和通知改变 - 默认:否
* @param it 成功后回调
* @param callback 成功后回调
*/
fun refreshSystemUI(context: Context? = null, isRefreshCacheOnly: Boolean = false, it: () -> Unit = {}) = runInSafe {
fun sendMessage() {
(context ?: appContext).sendBroadcast(Intent().apply {
action = Const.ACTION_REMIND_CHECKING_RECEIVER
putExtra("isRefreshCacheOnly", isRefreshCacheOnly)
putExtra(Const.MODULE_VERSION_VERIFY_TAG, Const.MODULE_VERSION_VERIFY)
})
}
if (isXposedModuleActive)
fun refreshSystemUI(context: Context? = null, isRefreshCacheOnly: Boolean = false, callback: () -> Unit = {}) = runInSafe {
if (YukiHookAPI.Status.isXposedModuleActive)
context?.showDialog {
title = "请稍后"
progressContent = "正在等待系统界面刷新"
@@ -118,23 +96,29 @@ object SystemUITool {
/** 设置等待延迟 */
delayedRun(ms = 5000) {
if (isWaited) return@delayedRun
remindHandlerCallback = null
cancel()
context.snake(msg = "预计响应超时,建议重启系统界面", actionText = "立即重启") { restartSystemUI(context) }
}
remindHandlerCallback = { isGrasp, isValied ->
remindHandlerCallback = null
cancel()
isWaited = true
checkingActivated(context) { isValied ->
when {
isGrasp && !isValied ->
isValied.not() -> {
cancel()
isWaited = true
context.snake(msg = "请重启系统界面以生效模块更新", actionText = "立即重启") { restartSystemUI(context) }
else -> it()
}
else -> context.dataChannel(SYSTEMUI_PACKAGE_NAME).with {
wait(CALL_MODULE_REFRESH_RESULT) {
cancel()
isWaited = true
callback()
if (it.not()) context.snake(msg = "刷新失败,建议重启系统界面", actionText = "立即重启") { restartSystemUI(context) }
}
put(CALL_HOST_REFRESH_CACHING, isRefreshCacheOnly)
}
}
}
sendMessage()
noCancelable()
} ?: sendMessage()
}
else context?.snake(msg = "模块没有激活,更改不会生效")
}
@@ -143,29 +127,7 @@ object SystemUITool {
* @param context 实例
*/
fun showNeedRestartSnake(context: Context) =
if (isXposedModuleActive)
if (YukiHookAPI.Status.isXposedModuleActive)
context.snake(msg = "设置需要重启系统界面才能生效", actionText = "立即重启") { restartSystemUI(context) }
else context.snake(msg = "模块没有激活,更改不会生效")
/** 宿主广播接收器 */
private val moduleHandlerReceiver by lazy {
object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val isRegular = intent?.getBooleanExtra("isRegular", false) ?: false
val isValied = intent?.getBooleanExtra("isValied", false) ?: false
moduleHandlerCallback?.invoke(isRegular, isValied)
}
}
}
/** 通知广播接收器 */
private val remindHandlerReceiver by lazy {
object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val isGrasp = intent?.getBooleanExtra("isGrasp", false) ?: false
val isValied = intent?.getBooleanExtra("isValied", false) ?: false
remindHandlerCallback?.invoke(isGrasp, isValied)
}
}
}
}

View File

@@ -0,0 +1,59 @@
/*
* ColorOSNotifyIcon - Optimize notification icons for ColorOS and adapt to native notification icon specifications.
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
* https://github.com/fankes/ColorOSNotifyIcon
*
* This software is non-free but opensource software: you can redistribute it
* and/or modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
* <p>
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/5/30.
*/
package com.fankes.coloros.notify.utils.tool
import android.content.Context
import com.fankes.coloros.notify.utils.factory.openBrowser
import com.fankes.coloros.notify.utils.factory.showDialog
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.hook.factory.modulePrefs
import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
/**
* [YukiHookAPI] 的自动推广工具类
*/
object YukiPromoteTool {
/** 推广已读存储键值 */
private val YUKI_PROMOTE_READED = PrefsData("yuki_promote_readed", false)
/**
* 显示推广对话框
* @param context 实例
*/
fun promote(context: Context) {
fun saveReaded() = context.modulePrefs.put(YUKI_PROMOTE_READED, value = true)
if (context.modulePrefs.get(YUKI_PROMOTE_READED).not())
context.showDialog {
title = "面向开发者的推广"
msg = "你想快速拥有一个自己的 Xposed 模块吗,你只需要拥有基础的 Android 开发经验以及使用 Kotlin 编程语言即可。\n\n" +
"快来体验 YukiHookAPI这是一个使用 Kotlin 重新构建的高效 Xposed Hook API助你的开发变得更轻松。"
confirmButton(text = "去看看") {
context.openBrowser(url = "https://github.com/fankes/YukiHookAPI")
saveReaded()
}
cancelButton(text = "我不是开发者") { saveReaded() }
noCancelable()
}
}
}

View File

@@ -421,6 +421,31 @@
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
<com.fankes.coloros.notify.ui.view.MaterialSwitch
android:id="@+id/notify_media_panel_auto_exp_switch"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginTop="5dp"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:text="启用媒体通知播放时自动展开"
android:textAllCaps="false"
android:textColor="@color/colorTextGray"
android:textSize="15sp" />
<TextView
android:id="@+id/notify_media_panel_auto_exp_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:alpha="0.6"
android:lineSpacingExtra="6dp"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:text="ColorOS 的媒体通知在播放的时候默认是折叠状态,开启后只要推送媒体通知以及恢复播放状态都会自动展开通知。"
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
<com.fankes.coloros.notify.ui.view.MaterialSwitch
android:id="@+id/notify_panel_config_switch"
android:layout_width="match_parent"
@@ -440,22 +465,45 @@
android:layout_marginLeft="5dp"
android:layout_marginTop="5dp"
android:layout_marginRight="5dp"
android:max="255"
android:min="0" />
android:max="100"
android:min="0"
android:progress="75" />
<TextView
android:id="@+id/notify_panel_config_text"
android:layout_width="wrap_content"
<LinearLayout
android:id="@+id/notify_panel_config_text_panel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:gravity="center"
android:maxWidth="100dp"
android:orientation="horizontal"
android:paddingTop="5dp"
android:paddingBottom="15dp"
android:singleLine="true"
android:text="当前值 - %1"
android:textColor="@color/colorTextGray"
android:textSize="14sp" />
android:paddingBottom="15dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:alpha="0.75"
android:ellipsize="end"
android:gravity="center"
android:maxWidth="100dp"
android:singleLine="true"
android:text="当前"
android:textColor="@color/colorTextGray"
android:textSize="13.5sp" />
<TextView
android:id="@+id/notify_panel_config_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:gravity="center"
android:maxWidth="100dp"
android:singleLine="true"
android:text="75%"
android:textColor="@color/colorTextGray"
android:textSize="15sp"
android:textStyle="bold" />
</LinearLayout>
<TextView
android:layout_width="match_parent"
@@ -465,9 +513,42 @@
android:lineSpacingExtra="6dp"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:text="开启自定义功能后你可以拖拽滑动条来调整通知面板的透明度0 为全透明,255 为不透明。"
android:text="开启自定义功能后你可以拖拽滑动条来调整通知面板的透明度0% 为全透明,100% 为不透明。"
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
<LinearLayout
android:id="@+id/notify_panel_config_warn_panel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:alpha="0.6"
android:lineSpacingExtra="6dp"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:text="此功能为实验性功能,后期不一定继续维护,且仅在 ColorOS 12.1 测试通过,不能保证可以在任何系统版本中生效,以及和各种通知栏主题模块配合使用,如有冲突请关闭此功能或禁用相关重复功能的主题模块。"
android:textColor="@color/colorTextDark"
android:textSize="12sp"
android:textStyle="bold" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:alpha="0.6"
android:lineSpacingExtra="6dp"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:text="已知问题:\n(1) 悬浮通知也会被透明,在透明度较低的时候下拉会有阴影光晕,松手释放后恢复正常,后期看需求再解决。\n(2) 媒体通知可能在低于 ColorOS 12.1 的系统上无法生效透明度,旧版本不再适配,该问题不会被修复。"
android:textColor="@color/colorTextDark"
android:textSize="12sp"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
<LinearLayout
@@ -558,6 +639,34 @@
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
<LinearLayout
android:id="@+id/notify_icon_force_app_icon_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:orientation="vertical">
<com.fankes.coloros.notify.ui.view.MaterialSwitch
android:id="@+id/notify_icon_force_app_icon_switch"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_marginBottom="5dp"
android:text="通知栏中的图标强制为 APP 图标"
android:textColor="@color/colorTextGray"
android:textSize="15sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:alpha="0.6"
android:lineSpacingExtra="6dp"
android:text="此选项默认关闭,开启后下拉通知栏中的通知图标将会被替换为 APP 自身图标,但是不会更改状态栏中的通知图标,这是一个破坏原生通知图标的行为,仅针对部分有需要的用户而添加,我们不推荐开启这个功能,请根据个人偏好进行选择是否需要开启。"
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/notify_icon_fix_notify_item"
android:layout_width="match_parent"

View File

@@ -1,12 +1,12 @@
plugins {
id 'com.android.application' version '7.1.3' apply false
id 'com.android.library' version '7.1.3' apply false
id 'com.android.application' version '7.2.0' apply false
id 'com.android.library' version '7.2.0' apply false
id 'org.jetbrains.kotlin.android' version '1.6.21' apply false
}
ext {
appVersionName = "1.7"
appVersionCode = 12
appVersionName = "1.8"
appVersionCode = 16
enableR8 = true
}

View File

@@ -1,6 +1,6 @@
#Sat Feb 26 13:04:39 CST 2022
#Wed May 25 04:24:55 CST 2022
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME