19 Commits
1.77 ... 1.85

21 changed files with 470 additions and 404 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.3060926669098869" />
<entry key="app/src/main/res/layout/activity_main.xml" value="0.29182608695652174" />
<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.77-green)](https://github.com/fankes/ColorOSNotifyIcon/releases)
[![Blank](https://img.shields.io/badge/version-v1.85-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

@@ -31,6 +31,8 @@ android {
buildTypes {
release {
minifyEnabled rootProject.ext.enableR8
shrinkResources rootProject.ext.enableR8
zipAlignEnabled rootProject.ext.enableR8
signingConfig signingConfigs.debug
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
@@ -50,36 +52,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.86'
ksp 'com.highcapable.yukihookapi:ksp-xposed:1.0.86'
implementation 'com.highcapable.yukihookapi:api:1.0.92'
ksp 'com.highcapable.yukihookapi:ksp-xposed:1.0.92'
implementation "com.github.topjohnwu.libsu:core:3.1.2"
implementation 'androidx.annotation:annotation:1.3.0'
implementation 'com.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.6.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
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}_202205091602"
/** 当前模块的版本校验标签 */
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,6 +33,7 @@ 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)
@@ -40,6 +41,7 @@ object DataConst {
val ENABLE_NOTIFY_ICON_FIX_AUTO = PrefsData("_enable_notify_icon_fix_auto", true)
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_ICON_CORNER = PrefsData("_notify_icon_corner", 10)
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

@@ -32,7 +32,7 @@ import com.highcapable.yukihookapi.hook.factory.encase
import com.highcapable.yukihookapi.hook.log.loggerW
import com.highcapable.yukihookapi.hook.xposed.proxy.IYukiHookXposedInit
@InjectYukiHookWithXposed
@InjectYukiHookWithXposed(isUsingResourcesHook = false)
class HookEntry : IYukiHookXposedInit {
override fun onInit() = configs {
@@ -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

@@ -25,10 +25,8 @@
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
@@ -37,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
@@ -46,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
@@ -56,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
@@ -216,65 +215,6 @@ object 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 是否判断启用通知功能 - 默认:是
@@ -488,6 +428,13 @@ object 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
@@ -515,7 +462,12 @@ object SystemUIHooker : YukiBaseHooker() {
/** 判断风格并开始 Hook */
if (isA12Style) {
background = DrawableBuilder().rounded().solidColor(newApplyColor).build()
/** 通知图标边框圆角大小 */
background = DrawableBuilder()
.rectangle()
.cornerRadius(prefs.get(DataConst.NOTIFY_ICON_CORNER).dp(context))
.solidColor(newApplyColor)
.build()
setColorFilter(newStyle)
setPadding(2.dp(context), 2.dp(context), 2.dp(context), 2.dp(context))
} else {
@@ -527,23 +479,8 @@ object 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()
}
}
/** 打印日志 */
@@ -580,6 +517,35 @@ object SystemUIHooker : YukiBaseHooker() {
}
}
/** 设置默认通知栏通知图标样式 */
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) }
}
/** 缓存图标数据 */
private fun cachingIconDatas() {
iconDatas.clear()
@@ -594,17 +560,25 @@ object 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()
/** 移除开发者警告通知 */
@@ -697,12 +671,8 @@ object 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) }
}
}
}
@@ -902,8 +872,6 @@ object 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,6 +124,9 @@ 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.notifyIconCustomCornerItem.isVisible = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX) &&
modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FORCE_APP_ICON).not()
binding.notifyIconForceAppIconItem.isVisible = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX)
binding.notifyIconFixNotifyItem.isVisible = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX)
binding.notifyIconAutoSyncItem.isVisible = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX)
binding.notifyIconAutoSyncChildItem.isVisible = modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FIX_AUTO)
@@ -137,11 +142,14 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
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.notifyIconCustomCornerSeekbar.progress = modulePrefs.get(DataConst.NOTIFY_ICON_CORNER)
binding.notifyPanelConfigText.text = "${modulePrefs.get(DataConst.NOTIFY_PANEL_ALPHA)}%"
binding.notifyIconCustomCornerText.text = "${modulePrefs.get(DataConst.NOTIFY_ICON_CORNER)} dp"
binding.notifyIconAutoSyncText.text = notifyIconAutoSyncTime
/** 媒体通知自动展开仅支持 12.1 - 旧版本适配过于复杂已放弃 */
if (colorOSNumberVersion != "V12.1") {
@@ -175,10 +183,29 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
if (btn.isPressed.not()) return@setOnCheckedChangeListener
modulePrefs.put(DataConst.ENABLE_NOTIFY_ICON_FIX, b)
binding.notifyIconFixButton.isVisible = b
binding.notifyIconCustomCornerItem.isVisible = b && modulePrefs.get(DataConst.ENABLE_NOTIFY_ICON_FORCE_APP_ICON).not()
binding.notifyIconForceAppIconItem.isVisible = b
binding.notifyIconFixNotifyItem.isVisible = b
binding.notifyIconAutoSyncItem.isVisible = b
SystemUITool.refreshSystemUI(context = this)
}
binding.notifyIconForceAppIconSwitch.setOnCheckedChangeListener { btn, b ->
if (btn.isPressed.not()) return@setOnCheckedChangeListener
fun saveState() {
binding.notifyIconCustomCornerItem.isVisible = b.not()
modulePrefs.put(DataConst.ENABLE_NOTIFY_ICON_FORCE_APP_ICON, b)
SystemUITool.refreshSystemUI(context = this)
}
if (b) showDialog {
title = "破坏性功能警告"
msg = "开启这个功能后,任何通知栏中的通知图标都会被强制替换为当前推送通知的 APP 的图标," +
"某些系统级别的 APP 通知图标可能会显示异常或发生图标丢失。\n\n" +
"此功能仅面向一些追求图标美观度的用户,我们不推荐开启这个功能,且发生任何 BUG 都不会去修复,仍然继续开启吗?"
confirmButton { saveState() }
cancelButton { btn.isChecked = btn.isChecked.not() }
noCancelable()
} else saveState()
}
binding.notifyIconFixNotifySwitch.setOnCheckedChangeListener { btn, b ->
if (btn.isPressed.not()) return@setOnCheckedChangeListener
modulePrefs.put(DataConst.ENABLE_NOTIFY_ICON_FIX_NOTIFY, b)
@@ -235,6 +262,18 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
override fun onStartTrackingTouch(seekBar: SeekBar?) {}
})
binding.notifyIconCustomCornerSeekbar.setOnSeekBarChangeListener(object : OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
binding.notifyIconCustomCornerText.text = "$progress dp"
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
modulePrefs.put(DataConst.NOTIFY_ICON_CORNER, seekBar.progress)
SystemUITool.refreshSystemUI(context = this@MainActivity)
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {}
})
/** 通知图标优化名单按钮点击事件 */
binding.notifyIconFixButton.setOnClickListener { navigate<ConfigureActivity>() }
/** 自动更新在线规则修改时间按钮点击事件 */
@@ -273,36 +312,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

@@ -43,8 +43,6 @@ class NotifyIconRuleUpdateActivity : Activity() {
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
window?.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
window?.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
/** 注册 */
SystemUITool.register(context = this)
/** 检测运行状态 */
if (BaseActivity.isMainThreadRunning) {
finish()
@@ -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

@@ -370,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) = runInSafe {
/** 注册广播检查模块激活状态 */
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) = runInSafe {
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

@@ -563,15 +563,13 @@
android:elevation="0dp"
android:gravity="center"
android:orientation="vertical"
android:paddingLeft="10dp"
android:paddingTop="15dp"
android:paddingRight="10dp">
android:paddingTop="15dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:gravity="center|start">
<ImageView
@@ -594,8 +592,8 @@
android:id="@+id/notify_icon_fix_switch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:text="启用通知图标优化"
android:textColor="@color/colorTextGray"
android:textSize="15sp" />
@@ -604,8 +602,8 @@
android:id="@+id/notify_icon_fix_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="3dp"
android:layout_marginRight="3dp"
android:layout_marginLeft="13dp"
android:layout_marginRight="13dp"
android:layout_marginBottom="10dp"
android:background="@drawable/bg_button_round"
android:gravity="center"
@@ -618,8 +616,8 @@
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginBottom="10dp"
android:alpha="0.6"
android:lineSpacingExtra="6dp"
@@ -630,8 +628,8 @@
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginBottom="10dp"
android:alpha="0.6"
android:lineSpacingExtra="6dp"
@@ -639,12 +637,119 @@
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
<LinearLayout
android:id="@+id/notify_icon_custom_corner_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginBottom="5dp"
android:gravity="center|start"
android:text="调整通知栏中的图标边框圆角大小"
android:textAllCaps="false"
android:textColor="@color/colorTextGray"
android:textSize="15sp" />
<androidx.appcompat.widget.AppCompatSeekBar
android:id="@+id/notify_icon_custom_corner_seekbar"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginTop="5dp"
android:max="10"
android:min="0"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:progress="10" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:gravity="center"
android:orientation="horizontal"
android:paddingTop="5dp"
android:paddingBottom="15dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="5dp"
android:alpha="0.75"
android:ellipsize="end"
android:gravity="center"
android:maxWidth="100dp"
android:singleLine="true"
android:text="当前"
android:textColor="@color/colorTextGray"
android:textSize="13.5sp" />
<TextView
android:id="@+id/notify_icon_custom_corner_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:gravity="center"
android:maxWidth="100dp"
android:singleLine="true"
android:text="10 dp"
android:textColor="@color/colorTextGray"
android:textSize="15sp"
android:textStyle="bold" />
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:alpha="0.6"
android:lineSpacingExtra="6dp"
android:text="你可以拖拽滑动条来调整通知栏中图标的边框圆角大小,仅支持启用了 Android 12 通知栏风格的通知图标。"
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/notify_icon_force_app_icon_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:orientation="vertical">
<com.fankes.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"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:orientation="vertical">
<com.fankes.coloros.notify.ui.view.MaterialSwitch
@@ -671,8 +776,8 @@
android:id="@+id/notify_icon_auto_sync_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:animateLayoutChanges="true"
android:orientation="vertical">

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.77"
appVersionCode = 15
appVersionName = "1.85"
appVersionCode = 17
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