20 Commits
1.51 ... 1.6

Author SHA1 Message Date
b06ecaa5e0 Update version to 1.6 2022-04-14 03:20:22 +08:00
df5090faac 更换通知刷新方案,彻底解决系统界面卡死问题 2022-04-14 03:03:27 +08:00
ffb706864a Update YukiHookAPI 2022-04-13 05:03:30 +08:00
70eadb83e8 Merge code 2022-04-11 23:08:21 +08:00
6d7d7290e2 Update YukiHookAPI 2022-04-10 03:05:13 +08:00
1191c77986 Update YukiHookAPI 2022-04-09 02:35:08 +08:00
2f4539d8f6 Update README.md 2022-04-09 01:53:45 +08:00
030a1590ae Update README.md 2022-04-05 22:45:54 +08:00
52820c0b07 加入新安装应用的通知图标优化适配通知忽略 DEBUG 版本的 APP 2022-04-05 22:03:09 +08:00
1f2b1d5046 Update version to 1.53 2022-04-04 23:22:10 +08:00
7896e4836c Update YukiHookAPI 2022-04-04 23:13:24 +08:00
d2ff1fe3ec 修复 ColorOS 11 Android 11 上的问题 2022-04-04 23:12:58 +08:00
f5722e3e5c Update version to 1.52 2022-04-04 14:49:03 +08:00
44e99cb3da 修复缓存图标过大造成系统界面停止运行的问题 2022-04-04 14:45:56 +08:00
1386833c91 Merge code 2022-04-04 12:03:58 +08:00
69af0172eb Update YukiHookAPI 2022-04-04 03:19:41 +08:00
81e66d2da2 Update README.md 2022-03-30 20:56:21 +08:00
73a9142e71 Merge code 2022-03-30 14:14:23 +08:00
5af6ffb614 Merge code 2022-03-29 23:04:16 +08:00
230b3b4e38 Merge code 2022-03-29 21:45:19 +08:00
11 changed files with 164 additions and 71 deletions

View File

@@ -2,45 +2,55 @@
[![Blank](https://img.shields.io/badge/build-passing-brightgreen)](https://github.com/fankes/ColorOSNotifyIcon) [![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/license-AGPL3.0-blue)](https://github.com/fankes/ColorOSNotifyIcon/blob/master/LICENSE)
[![Blank](https://img.shields.io/badge/version-v1.51-green)](https://github.com/fankes/ColorOSNotifyIcon/releases) [![Blank](https://img.shields.io/badge/version-v1.6-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/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) [![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/static/v1?label=Telegram&message=交流讨论&color=0088cc)](https://t.me/XiaofangInternet) [![Telegram](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/XiaofangInternet)
<br/><br/> <br/><br/>
<img src="https://github.com/fankes/ColorOSNotifyIcon/blob/master/app/src/main/ic_launcher-playstore.png" width = "100" height = "100"/> <img src="https://github.com/fankes/ColorOSNotifyIcon/blob/master/app/src/main/ic_launcher-playstore.png" width = "100" height = "100"/>
<br/> <br/>
Optimize notification icons for ColorOS and adapt to native notification icon specifications.<br/> Optimize notification icons for ColorOS and adapt to native notification icon specifications.
为 ColorOS 优化通知图标以及适配原生通知图标规范,理论支持 OxygenOS 和 RealmeUI。 为 ColorOS 优化通知图标以及适配原生通知图标规范,理论支持 OxygenOS 和 RealmeUI。
# Developer ## Developer
[酷安 @星夜不荟](http://www.coolapk.com/u/876977) [酷安 @星夜不荟](http://www.coolapk.com/u/876977)
# 适配说明 ## 适配说明
- 此模块仅支持 <b>LSPosed</b>(作用域“系统界面”)、<b>~~EdXposed(随时停止支持)~~</b>、不支持<b>太极、无极</b> - 此模块仅支持 <b>LSPosed</b>(作用域“系统界面”)、<b>~~EdXposed(随时停止支持)~~</b>、不支持<b>太极、无极</b>
- 目前仅在 ColorOS 12 for OnePlus 上测试通过,如有问题请提交 `issues` - 目前仅在 ColorOS 12 for OnePlus 上测试通过,如有问题请提交 `issues`
- 建议在不低于 ColorOS 11 的版本上使用 - 建议在不低于 ColorOS 11 的版本上使用
# 请勿用于非法用途 ## 请勿用于非法用途
- 本模块完全开源免费,如果好用你可以打赏支持开发,但是请不要用于非法用途。 - 本模块完全开源免费,如果好用你可以打赏支持开发,但是请不要用于非法用途。
- 本模块发布地址仅有 [Xposed-Modules-Repo](https://github.com/Xposed-Modules-Repo/com.fankes.coloros.notify/releases)、 - 本模块发布地址仅有 [Xposed-Modules-Repo](https://github.com/Xposed-Modules-Repo/com.fankes.coloros.notify/releases)、
[Release](https://github.com/fankes/ColorOSNotifyIcon/releases) [Release](https://github.com/fankes/ColorOSNotifyIcon/releases)
及 [蓝奏云](https://fankes.lanzouy.com/b030rvjyf),从其他非正规渠道下载到的版本或对您造成任何影响均与我们无关。 及 [蓝奏云](https://fankes.lanzouy.com/b030rvjyf),从其他非正规渠道下载到的版本或对您造成任何影响均与我们无关。
# 贡献通知图标优化名单 ## 贡献通知图标优化名单
此项目是 `AndroidNotifyIconAdapt` 项目的一部分,详情请参考下方。<br/> 此项目是 `AndroidNotifyIconAdapt` 项目的一部分,详情请参考下方。
- [Android 通知图标规范适配计划](https://github.com/fankes/AndroidNotifyIconAdapt) - [Android 通知图标规范适配计划](https://github.com/fankes/AndroidNotifyIconAdapt)
# 历史背景 ## 历史背景
继 MIUI 之后的第二大系统 ColorOS 虽然支持原生通知图标,但是第三方推送五颜六色的图标系统并没有做适配,甚至系统自己的图标都是彩色的,极其不友好。
继 MIUI 之后的第二大系统 ColorOS 虽然支持原生通知图标,但是第三方推送五颜六色的图标系统并没有做适配,甚至系统自己的图标都是彩色的,极其不友好。<br/>
而且从 ColorOS 12 开始,原生图标丢失了着色属性,这也是一种对原生 Android 生态的破坏。 而且从 ColorOS 12 开始,原生图标丢失了着色属性,这也是一种对原生 Android 生态的破坏。
# 许可证 ## 捐赠支持
- 工作不易,无意外情况此项目将继续维护下去,提供更多可能,欢迎打赏。<br/><br/>
<img src="https://github.com/fankes/YuKiHookAPI/blob/master/img-src/wechat_code.jpg" width = "200" height = "200"/>
## 许可证
- [AGPL-3.0](https://www.gnu.org/licenses/agpl-3.0.html) - [AGPL-3.0](https://www.gnu.org/licenses/agpl-3.0.html)
@@ -61,5 +71,6 @@ You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
``` ```
Powered by [YukiHookAPI](https://github.com/fankes/YukiHookAPI)<br/><br/> Powered by [YukiHookAPI](https://github.com/fankes/YukiHookAPI)
版权所有 © 2019-2022 Fankes Studio(qzmmcn@163.com) 版权所有 © 2019-2022 Fankes Studio(qzmmcn@163.com)

View File

@@ -38,7 +38,7 @@ android {
buildTypes { buildTypes {
release { release {
minifyEnabled true minifyEnabled rootProject.ext.enableR8
signingConfig signingConfigs.debug signingConfig signingConfigs.debug
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
} }
@@ -72,8 +72,8 @@ tasks.whenTaskAdded {
dependencies { dependencies {
compileOnly 'de.robv.android.xposed:api:82' compileOnly 'de.robv.android.xposed:api:82'
implementation 'com.highcapable.yukihookapi:api:1.0.68' implementation 'com.highcapable.yukihookapi:api:1.0.75'
ksp 'com.highcapable.yukihookapi:ksp-xposed:1.0.68' ksp 'com.highcapable.yukihookapi:ksp-xposed:1.0.75'
implementation 'com.github.tiann:FreeReflection:3.1.0' implementation 'com.github.tiann:FreeReflection:3.1.0'
implementation "com.github.topjohnwu.libsu:core:3.1.2" implementation "com.github.topjohnwu.libsu:core:3.1.2"
implementation 'androidx.annotation:annotation:1.3.0' implementation 'androidx.annotation:annotation:1.3.0'

View File

@@ -41,7 +41,7 @@ object Const {
const val MODULE_VERSION_CODE = BuildConfig.VERSION_CODE const val MODULE_VERSION_CODE = BuildConfig.VERSION_CODE
/** 当前模块的版本校验 */ /** 当前模块的版本校验 */
const val MODULE_VERSION_VERIFY = "${MODULE_VERSION_NAME}_${MODULE_VERSION_CODE}_202203292119" const val MODULE_VERSION_VERIFY = "${MODULE_VERSION_NAME}_${MODULE_VERSION_CODE}_202204140318"
/** 当前模块的版本校验标签 */ /** 当前模块的版本校验标签 */
const val MODULE_VERSION_VERIFY_TAG = "module_version_verify" const val MODULE_VERSION_VERIFY_TAG = "module_version_verify"

View File

@@ -35,10 +35,13 @@ import android.graphics.drawable.Drawable
import android.graphics.drawable.Icon import android.graphics.drawable.Icon
import android.graphics.drawable.VectorDrawable import android.graphics.drawable.VectorDrawable
import android.service.notification.StatusBarNotification import android.service.notification.StatusBarNotification
import android.util.ArrayMap
import android.view.View import android.view.View
import android.view.ViewGroup
import android.view.ViewOutlineProvider import android.view.ViewOutlineProvider
import android.widget.ImageView import android.widget.ImageView
import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.drawable.toBitmap
import androidx.core.view.children
import com.fankes.coloros.notify.bean.IconDataBean import com.fankes.coloros.notify.bean.IconDataBean
import com.fankes.coloros.notify.const.Const import com.fankes.coloros.notify.const.Const
import com.fankes.coloros.notify.data.DataConst import com.fankes.coloros.notify.data.DataConst
@@ -52,6 +55,7 @@ import com.fankes.coloros.notify.utils.factory.*
import com.fankes.coloros.notify.utils.tool.IconAdaptationTool import com.fankes.coloros.notify.utils.tool.IconAdaptationTool
import com.highcapable.yukihookapi.hook.bean.VariousClass import com.highcapable.yukihookapi.hook.bean.VariousClass
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
import com.highcapable.yukihookapi.hook.factory.current
import com.highcapable.yukihookapi.hook.factory.field import com.highcapable.yukihookapi.hook.factory.field
import com.highcapable.yukihookapi.hook.factory.method import com.highcapable.yukihookapi.hook.factory.method
import com.highcapable.yukihookapi.hook.log.loggerD import com.highcapable.yukihookapi.hook.log.loggerD
@@ -74,33 +78,40 @@ class SystemUIHooker : YukiBaseHooker() {
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"
/** ColorOS 存在的类 - 旧版本不存在 */ /** ColorOS 存在的类 - 旧版本不存在 */
private const val OplusContrastColorUtilClass = "com.oplusos.util.OplusContrastColorUtil" private const val OplusContrastColorUtilClass = "com.oplusos.util.OplusContrastColorUtil"
/** 原生存在的类 */ /** 原生存在的类 */
private const val PluginManagerImplClass = "${SYSTEMUI_PACKAGE_NAME}.shared.plugins.PluginManagerImpl" private const val PluginManagerImplClass = "$SYSTEMUI_PACKAGE_NAME.shared.plugins.PluginManagerImpl"
/** 根据多个版本存在不同的包名相同的类 */
private val OplusNotificationIconAreaControllerClass = VariousClass(
"com.oplusos.systemui.statusbar.phone.OplusNotificationIconAreaController",
"com.oplusos.systemui.statusbar.policy.OplusNotificationIconAreaController",
"com.coloros.systemui.statusbar.policy.ColorNotificationIconAreaController"
)
/** 根据多个版本存在不同的包名相同的类 */ /** 根据多个版本存在不同的包名相同的类 */
private val SystemPromptControllerClass = VariousClass( private val SystemPromptControllerClass = VariousClass(
"com.oplusos.systemui.statusbar.policy.SystemPromptController", "com.oplusos.systemui.statusbar.policy.SystemPromptController",
"com.coloros.systemui.statusbar.policy.SystemPromptController" "com.coloros.systemui.statusbar.policy.ColorSystemPromptController"
) )
/** 根据多个版本存在不同的包名相同的类 */ /** 根据多个版本存在不同的包名相同的类 */
@@ -133,36 +144,45 @@ class SystemUIHooker : YukiBaseHooker() {
"com.coloros.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( private val ExpandableNotificationRowClass = VariousClass(
"${SYSTEMUI_PACKAGE_NAME}.statusbar.notification.row.ExpandableNotificationRow", "$SYSTEMUI_PACKAGE_NAME.statusbar.notification.row.ExpandableNotificationRow",
"${SYSTEMUI_PACKAGE_NAME}.statusbar.ExpandableNotificationRow" "$SYSTEMUI_PACKAGE_NAME.statusbar.ExpandableNotificationRow"
) )
/** 根据多个版本存在不同的包名相同的类 */ /** 根据多个版本存在不同的包名相同的类 */
private val NotificationViewWrapperClass = VariousClass( private val NotificationViewWrapperClass = VariousClass(
"${SYSTEMUI_PACKAGE_NAME}.statusbar.notification.row.wrapper.NotificationViewWrapper", "$SYSTEMUI_PACKAGE_NAME.statusbar.notification.row.wrapper.NotificationViewWrapper",
"${SYSTEMUI_PACKAGE_NAME}.statusbar.notification.NotificationViewWrapper" "$SYSTEMUI_PACKAGE_NAME.statusbar.notification.NotificationViewWrapper"
) )
/** 根据多个版本存在不同的包名相同的类 */ /** 根据多个版本存在不同的包名相同的类 */
private val NotificationHeaderViewWrapperClass = VariousClass( private val NotificationHeaderViewWrapperClass = VariousClass(
"${SYSTEMUI_PACKAGE_NAME}.statusbar.notification.row.wrapper.NotificationHeaderViewWrapper", "$SYSTEMUI_PACKAGE_NAME.statusbar.notification.row.wrapper.NotificationHeaderViewWrapper",
"${SYSTEMUI_PACKAGE_NAME}.statusbar.notification.NotificationHeaderViewWrapper" "$SYSTEMUI_PACKAGE_NAME.statusbar.notification.NotificationHeaderViewWrapper"
) )
} }
/** 缓存的彩色 APP 图标 */ /** 缓存的彩色 APP 图标 */
private var appIcons = HashMap<String, Drawable>() private var appIcons = ArrayMap<String, Drawable>()
/** 缓存的通知优化图标数组 */ /** 缓存的通知优化图标数组 */
private var iconDatas = ArrayList<IconDataBean>() private var iconDatas = ArrayList<IconDataBean>()
/** 缓存的状态栏小图标实例 */ /** 状态栏通知图标容器 */
private var statusBarIconViews = HashSet<ImageView>() private var notificationIconContainer: ViewGroup? = null
/** 缓存的通知图标包装纸实例 */ /** 状态栏通知图标数组 */
private var notificationViewWrappers = HashSet<Any>() private var notificationIconInstances = ArrayList<View>()
/** 通知栏通知控制器 */
private var notificationPresenter: Any? = null
/** 仅监听一次主题壁纸颜色变化 */ /** 仅监听一次主题壁纸颜色变化 */
private var isWallpaperColorListenerSetUp = false private var isWallpaperColorListenerSetUp = false
@@ -290,7 +310,7 @@ class SystemUIHooker : YukiBaseHooker() {
.get(RoundRectDrawableUtilClass.clazz.field { name = "Companion" }.get().self) .get(RoundRectDrawableUtilClass.clazz.field { name = "Companion" }.get().self)
/** 启动一个线程防止卡顿 */ /** 启动一个线程防止卡顿 */
Thread { Thread {
statusBarIconViews.takeIf { it.isNotEmpty() }?.forEach { (notificationIconContainer?.children?.toList() ?: notificationIconInstances.takeIf { it.isNotEmpty() })?.forEach {
runInSafe { runInSafe {
/** 得到通知实例 */ /** 得到通知实例 */
val nf = nfField.get(it).cast<StatusBarNotification>() ?: return@Thread val nf = nfField.get(it).cast<StatusBarNotification>() ?: return@Thread
@@ -311,7 +331,7 @@ class SystemUIHooker : YukiBaseHooker() {
/** 得到缩放大小 */ /** 得到缩放大小 */
val sNfSize = sNfSizeField.get(it).int() val sNfSize = sNfSizeField.get(it).int()
/** 在主线程设置图标 */ /** 在主线程设置图标 */
it.post { it.setImageDrawable(roundUtil.invoke(pair.first, sRadius, sNfSize, sNfSize, it.context)) } it.post { (it as? ImageView?)?.setImageDrawable(roundUtil.invoke(pair.first, sRadius, sNfSize, sNfSize, it.context)) }
} }
} }
} }
@@ -320,8 +340,11 @@ class SystemUIHooker : YukiBaseHooker() {
/** 刷新通知小图标 */ /** 刷新通知小图标 */
private fun refreshNotificationIcons() = runInSafe { private fun refreshNotificationIcons() = runInSafe {
NotificationHeaderViewWrapperClass.clazz.method { name = "resolveHeaderViews" }.also { result -> notificationPresenter?.current {
notificationViewWrappers.takeIf { it.isNotEmpty() }?.forEach { result.get(it).call() } method {
name = "updateNotificationsOnDensityOrFontScaleChanged"
emptyParam()
}.call()
} }
} }
@@ -535,7 +558,7 @@ class SystemUIHooker : YukiBaseHooker() {
} }
beforeHook { beforeHook {
/** 是否移除 */ /** 是否移除 */
if (args().int() == 7 && prefs.get(DataConst.REMOVE_CHANGECP_NOTIFY)) resultNull() if (args().first().int() == 7 && prefs.get(DataConst.REMOVE_CHANGECP_NOTIFY)) resultNull()
} }
} }
} }
@@ -552,14 +575,14 @@ class SystemUIHooker : YukiBaseHooker() {
} }
} }
} }
/** 修复并替换新版本 ColorOS 原生灰度图标色彩判断*/ /** 修复并替换新版本 ColorOS 原生灰度图标色彩判断 */
NotificationUtilsClass.hook { NotificationUtilsClass.hook {
injectMember { injectMember {
method { method {
name = "isGrayscaleOplus" name = "isGrayscaleOplus"
param(ImageViewClass, OplusContrastColorUtilClass.clazz) param(ImageViewClass, OplusContrastColorUtilClass)
} }
replaceAny { firstArgs<ImageView>()?.let { isGrayscaleIcon(it.context, it.drawable) } } replaceAny { args().first().cast<ImageView>()?.let { isGrayscaleIcon(it.context, it.drawable) } }
}.ignoredHookingFailure() }.ignoredHookingFailure()
} }
/** 替换状态栏图标 */ /** 替换状态栏图标 */
@@ -567,14 +590,14 @@ class SystemUIHooker : YukiBaseHooker() {
injectMember { injectMember {
method { method {
name = "getIconDescriptor" name = "getIconDescriptor"
param(NotificationEntryClass.clazz, BooleanType) param(NotificationEntryClass, BooleanType)
} }
afterHook { afterHook {
IconBuilderClass.clazz.field { name = "context" } IconBuilderClass.clazz.field { name = "context" }
.get(field { name = "iconBuilder" }.get(instance).cast()).cast<Context>()?.also { context -> .get(field { name = "iconBuilder" }.get(instance).cast()).cast<Context>()?.also { context ->
NotificationEntryClass.clazz.method { NotificationEntryClass.clazz.method {
name = "getSbn" name = "getSbn"
}.get(firstArgs).invoke<StatusBarNotification>()?.also { nf -> }.get(args[0]).invoke<StatusBarNotification>()?.also { nf ->
nf.notification.smallIcon.loadDrawable(context).also { iconDrawable -> nf.notification.smallIcon.loadDrawable(context).also { iconDrawable ->
compatStatusIcon( compatStatusIcon(
context = context, context = context,
@@ -606,14 +629,44 @@ class SystemUIHooker : YukiBaseHooker() {
param(StatusBarNotificationClass) param(StatusBarNotificationClass)
} }
afterHook { afterHook {
if (firstArgs != null) instance<ImageView>().also { if (args[0] != null) instance<ImageView>().also {
/** 注册壁纸颜色监听 */
registerWallpaperColorChanged(it) registerWallpaperColorChanged(it)
/** 注册广播 */
registerReceiver(it.context) registerReceiver(it.context)
statusBarIconViews.add(it)
} }
} }
} }
} }
/** 注入通知控制器实例 */
StatusBarNotificationPresenterClass.hook {
injectMember {
allConstructors()
afterHook { notificationPresenter = instance }
}
}
/** 注入状态栏通知图标容器实例 */
OplusNotificationIconAreaControllerClass.hook {
injectMember {
var isOldWay = false
method {
name = "updateIconsForLayout"
paramCount = 10
}.remedys {
method {
name = "updateIconsForLayout"
paramCount = 1
}.onFind { isOldWay = true }
}
afterHook {
if (isOldWay) {
notificationIconInstances.clear()
field { name = "mLastToShow" }.get(instance).list<View>()
.takeIf { it.isNotEmpty() }?.forEach { notificationIconInstances.add(it) }
} else notificationIconContainer = args(index = 1).cast()
}
}
}
/** 替换通知图标和样式 */ /** 替换通知图标和样式 */
NotificationHeaderViewWrapperClass.hook { NotificationHeaderViewWrapperClass.hook {
injectMember { injectMember {
@@ -647,11 +700,6 @@ class SystemUIHooker : YukiBaseHooker() {
} }
} }
} }
/** 记录实例 */
injectMember {
constructor { param(ContextClass, ViewClass, ExpandableNotificationRowClass.clazz) }
afterHook { notificationViewWrappers.add(instance) }
}
} }
/** 发送适配新的 APP 图标通知 */ /** 发送适配新的 APP 图标通知 */
PluginManagerImplClass.hook { PluginManagerImplClass.hook {
@@ -661,7 +709,7 @@ class SystemUIHooker : YukiBaseHooker() {
param(ContextClass, IntentClass) param(ContextClass, IntentClass)
} }
afterHook { afterHook {
if (isEnableHookColorNotifyIcon()) (lastArgs as? Intent)?.also { if (isEnableHookColorNotifyIcon()) args().last().cast<Intent>()?.also {
if (it.action.equals(Intent.ACTION_PACKAGE_REPLACED).not() && if (it.action.equals(Intent.ACTION_PACKAGE_REPLACED).not() &&
it.getBooleanExtra(Intent.EXTRA_REPLACING, false) it.getBooleanExtra(Intent.EXTRA_REPLACING, false)
) return@also ) return@also
@@ -671,11 +719,11 @@ class SystemUIHooker : YukiBaseHooker() {
if (iconDatas.takeIf { e -> e.isNotEmpty() } if (iconDatas.takeIf { e -> e.isNotEmpty() }
?.filter { e -> e.packageName == newPkgName } ?.filter { e -> e.packageName == newPkgName }
.isNullOrEmpty() .isNullOrEmpty()
) IconAdaptationTool.pushNewAppSupportNotify(firstArgs()!!, newPkgName) ) IconAdaptationTool.pushNewAppSupportNotify(args().first().cast()!!, newPkgName)
} }
Intent.ACTION_PACKAGE_REMOVED -> Intent.ACTION_PACKAGE_REMOVED ->
IconAdaptationTool.removeNewAppSupportNotify( IconAdaptationTool.removeNewAppSupportNotify(
context = firstArgs()!!, context = args().first().cast()!!,
packageName = it.data?.schemeSpecificPart ?: "" packageName = it.data?.schemeSpecificPart ?: ""
) )
} }
@@ -691,11 +739,16 @@ class SystemUIHooker : YukiBaseHooker() {
param(ContextClass, IntentClass) param(ContextClass, IntentClass)
} }
afterHook { afterHook {
if (isEnableHookColorNotifyIcon() && prefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX_AUTO)) args().first().cast<Context>()?.also {
IconAdaptationTool.prepareAutoUpdateIconRule( /** 注册广播 */
context = firstArgs()!!, registerReceiver(it)
timeSet = prefs.get(DataConst.NOTIFY_ICON_FIX_AUTO_TIME) /** 注册定时监听 */
) if (isEnableHookColorNotifyIcon() && prefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX_AUTO))
IconAdaptationTool.prepareAutoUpdateIconRule(
context = it,
timeSet = prefs.get(DataConst.NOTIFY_ICON_FIX_AUTO_TIME)
)
}
} }
} }
} }

View File

@@ -39,7 +39,7 @@ import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.viewbinding.ViewBinding import androidx.viewbinding.ViewBinding
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.highcapable.yukihookapi.annotation.DoNotUseField import com.highcapable.yukihookapi.annotation.CauseProblemsApi
import com.highcapable.yukihookapi.hook.factory.method import com.highcapable.yukihookapi.hook.factory.method
import com.highcapable.yukihookapi.hook.type.android.LayoutInflaterClass import com.highcapable.yukihookapi.hook.type.android.LayoutInflaterClass
@@ -71,7 +71,7 @@ class DialogBuilder(val context: Context, private val isUseBlackTheme: Boolean)
private var dialogInstance: Dialog? = null // 对话框实例 private var dialogInstance: Dialog? = null // 对话框实例
@DoNotUseField @CauseProblemsApi
var customLayoutView: View? = null // 自定义布局 var customLayoutView: View? = null // 自定义布局
/** /**

View File

@@ -33,6 +33,7 @@ import android.content.ClipData
import android.content.ClipboardManager import android.content.ClipboardManager
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.ApplicationInfo
import android.content.pm.PackageInfo import android.content.pm.PackageInfo
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.content.res.Configuration import android.content.res.Configuration
@@ -193,6 +194,14 @@ fun Context.findAppName(name: String) =
fun Context.findAppIcon(name: String) = fun Context.findAppIcon(name: String) =
safeOfNull { packageManager?.getPackageInfo(name, 0)?.applicationInfo?.loadIcon(packageManager) } safeOfNull { packageManager?.getPackageInfo(name, 0)?.applicationInfo?.loadIcon(packageManager) }
/**
* 获取 APP 是否为 DEBUG 版本
* @param name APP 包名
* @return [Boolean]
*/
fun Context.isAppDebuggable(name: String) =
safeOfFalse { (packageManager?.getPackageInfo(name, 0)?.applicationInfo?.flags?.and(ApplicationInfo.FLAG_DEBUGGABLE) ?: 0) != 0 }
/** /**
* 对数值自动补零 * 对数值自动补零
* @return [String] * @return [String]
@@ -320,12 +329,19 @@ fun findPropString(key: String, default: String = "") = safeOf(default) {
} }
/** /**
* 执行命令 - su * 是否有 Root 权限
* @return [Boolean]
*/
val isRootAccess get() = safeOfFalse { Shell.rootAccess() }
/**
* 执行命令
* @param cmd 命令 * @param cmd 命令
* @param isSu 是否使用 Root 权限执行 - 默认:是
* @return [String] 执行结果 * @return [String] 执行结果
*/ */
fun execShellSu(cmd: String) = safeOfNothing { fun execShell(cmd: String, isSu: Boolean = true) = safeOfNothing {
Shell.su(cmd).exec().out.let { (if (isSu) Shell.su(cmd) else Shell.sh(cmd)).exec().out.let {
if (it.isNotEmpty()) it[0].trim() else "" if (it.isNotEmpty()) it[0].trim() else ""
} }
} }

View File

@@ -116,6 +116,7 @@ object IconAdaptationTool {
* @param packageName 安装的 APP 包名 * @param packageName 安装的 APP 包名
*/ */
fun pushNewAppSupportNotify(context: Context, packageName: String) { fun pushNewAppSupportNotify(context: Context, packageName: String) {
if (context.isAppDebuggable(packageName)) return
context.getSystemService(NotificationManager::class.java)?.apply { context.getSystemService(NotificationManager::class.java)?.apply {
createNotificationChannel( createNotificationChannel(
NotificationChannel( NotificationChannel(

View File

@@ -121,7 +121,7 @@ object IconRuleManagerTool {
cancelButton() cancelButton()
neutralButton(text = "自定义规则") { neutralButton(text = "自定义规则") {
context.showDialog { context.showDialog {
title = "自定义规则" title = "自定义规则(调试)"
val editText = bind<DiaSourceFromStringBinding>().diaSfsInputEdit.apply { val editText = bind<DiaSourceFromStringBinding>().diaSfsInputEdit.apply {
requestFocus() requestFocus()
invalidate() invalidate()

View File

@@ -86,9 +86,9 @@ object SystemUITool {
msg = "你确定要立即重启系统界面吗?\n\n" + msg = "你确定要立即重启系统界面吗?\n\n" +
"重启过程会黑屏并等待进入锁屏重新解锁。" "重启过程会黑屏并等待进入锁屏重新解锁。"
confirmButton { confirmButton {
execShellSu(cmd = "pgrep systemui").also { pid -> execShell(cmd = "pgrep systemui").also { pid ->
if (pid.isNotBlank()) if (pid.isNotBlank())
execShellSu(cmd = "kill -9 $pid") execShell(cmd = "kill -9 $pid")
else toast(msg = "ROOT 权限获取失败") else toast(msg = "ROOT 权限获取失败")
} }
} }

View File

@@ -9,6 +9,17 @@
android:paddingRight="15dp" android:paddingRight="15dp"
tools:ignore="HardcodedText"> tools:ignore="HardcodedText">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginBottom="17.5dp"
android:lineSpacingExtra="6dp"
android:text="此功能仅用于调试单条规则或多条规则,同步最新在线规则后这里的内容将会被覆盖清空。"
android:textColor="@color/colorTextDark"
android:textSize="13sp" />
<com.google.android.material.textfield.TextInputLayout <com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">

View File

@@ -1,12 +1,13 @@
plugins { plugins {
id 'com.android.application' version '7.1.2' apply false id 'com.android.application' version '7.1.3' apply false
id 'com.android.library' version '7.1.2' apply false id 'com.android.library' version '7.1.3' apply false
id 'org.jetbrains.kotlin.android' version '1.6.10' apply false id 'org.jetbrains.kotlin.android' version '1.6.10' apply false
} }
ext { ext {
appVersionName = "1.51" appVersionName = "1.6"
appVersionCode = 8 appVersionCode = 11
enableR8 = true
} }
task clean(type: Delete) { task clean(type: Delete) {