mirror of
https://github.com/fankes/MIUINativeNotifyIcon.git
synced 2025-09-06 10:45:20 +08:00
将通知优化图标迁移至云端
This commit is contained in:
@@ -13,27 +13,33 @@
|
|||||||
|
|
||||||
## 贡献方法
|
## 贡献方法
|
||||||
|
|
||||||
- 在下方的类中添加新的 APP 通知图标适配条目
|
- 2022.02.25 适配数据已变更为云端更新
|
||||||
- [IconPackParams.kt](https://github.com/fankes/MIUINativeNotifyIcon/blob/master/app/src/main/java/com/fankes/miui/notify/params/IconPackParams.kt)
|
- 在下方的 JSON 文件中添加新的 APP 通知图标适配条目
|
||||||
|
- [NotifyIconsSupportConfig.json](https://github.com/fankes/MIUINativeNotifyIcon/blob/master/iconPack/NotifyIconsSupportConfig.json)
|
||||||
- 使用灰度位图转 Base64 来得到 Base64 的位图数据字符串
|
- 使用灰度位图转 Base64 来得到 Base64 的位图数据字符串
|
||||||
- [BitmapToBase64](https://github.com/fankes/BitmapToBase64)
|
- [BitmapToBase64](https://github.com/fankes/BitmapToBase64)
|
||||||
- 新增条目的模板如下所示
|
- 新增条目的模板如下所示
|
||||||
|
|
||||||
```kotlin
|
```json
|
||||||
IconDataBean(
|
{
|
||||||
isEnabled = true, // 是否默认启用替换彩色图标 - 关闭后将全部停止替换
|
"appName": "", // APP 名称
|
||||||
isEnabledAll = false, // 是否默认启用替换全部图标
|
"packageName": "", // APP 包名
|
||||||
appName = "", // APP 名称
|
"isEnabled": true, // 是否默认启用替换彩色图标 - 关闭后将全部停止替换
|
||||||
packageName = "", // APP 包名
|
"isEnabledAll": false, // 是否默认启用替换全部图标
|
||||||
iconBitmap = ("").bitmap, // 位图数据 Base64
|
"iconBitmap": "", // 位图数据 Base64 字符串
|
||||||
iconColor = 0, // 通知栏中显示的图标颜色 - 设置为 0 使用系统默认颜色 (不设置颜色可不写)
|
"iconColor": "#ff232323", // 通知栏中显示的图标颜色 - 不设置使用系统默认颜色 (不设置颜色可删除此项)
|
||||||
contributorName = "" // 贡献者昵称
|
"contributorName": "" // 贡献者昵称
|
||||||
)
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
- 图标大小建议保持在 50x50
|
- 图标大小建议保持在 50x50
|
||||||
- 提交时请将后方的注释删除,否则不予合并代码
|
- 提交时请将后方的注释删除,否则不予合并代码
|
||||||
|
|
||||||
|
## 同步列表地址
|
||||||
|
|
||||||
|
- Github 直连地址 [Raw](https://raw.githubusercontent.com/fankes/MIUINativeNotifyIcon/master/iconPack/NotifyIconsSupportConfig.json)
|
||||||
|
- 数据将在稍后同步至 [Surge](https://fankes.mnn.surge.sh/NotifyIconsSupportConfig.json)
|
||||||
|
|
||||||
## 其它要求
|
## 其它要求
|
||||||
|
|
||||||
- 1.调试性质或大批量注释代码,禁止提交
|
- 1.调试性质或大批量注释代码,禁止提交
|
||||||
|
@@ -30,7 +30,7 @@ android {
|
|||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
minifyEnabled true
|
minifyEnabled false
|
||||||
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,6 +72,7 @@ dependencies {
|
|||||||
ksp 'com.highcapable.yukihookapi:ksp-xposed:1.0.2'
|
ksp 'com.highcapable.yukihookapi:ksp-xposed:1.0.2'
|
||||||
implementation 'com.geyifeng.immersionbar:immersionbar:3.2.0'
|
implementation 'com.geyifeng.immersionbar:immersionbar:3.2.0'
|
||||||
implementation 'com.geyifeng.immersionbar:immersionbar-ktx:3.2.0'
|
implementation 'com.geyifeng.immersionbar:immersionbar-ktx:3.2.0'
|
||||||
|
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
|
||||||
implementation 'androidx.core:core-ktx:1.7.0'
|
implementation 'androidx.core:core-ktx:1.7.0'
|
||||||
implementation 'androidx.appcompat:appcompat:1.4.1'
|
implementation 'androidx.appcompat:appcompat:1.4.1'
|
||||||
implementation 'com.google.android.material:material:1.5.0'
|
implementation 'com.google.android.material:material:1.5.0'
|
||||||
|
@@ -3,6 +3,8 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
package="com.fankes.miui.notify">
|
package="com.fankes.miui.notify">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".application.MNNApplication"
|
android:name=".application.MNNApplication"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
|
@@ -32,6 +32,7 @@ object HookConst {
|
|||||||
const val ENABLE_COLOR_ICON_HOOK = "_color_icon_hook"
|
const val ENABLE_COLOR_ICON_HOOK = "_color_icon_hook"
|
||||||
const val ENABLE_COLOR_ICON_COMPAT = "_color_icon_compat"
|
const val ENABLE_COLOR_ICON_COMPAT = "_color_icon_compat"
|
||||||
const val ENABLE_NOTIFY_ICON_FIX = "_notify_icon_fix"
|
const val ENABLE_NOTIFY_ICON_FIX = "_notify_icon_fix"
|
||||||
|
const val NOTIFY_ICON_DATAS = "_notify_icon_datas"
|
||||||
|
|
||||||
const val SYSTEMUI_PACKAGE_NAME = "com.android.systemui"
|
const val SYSTEMUI_PACKAGE_NAME = "com.android.systemui"
|
||||||
}
|
}
|
@@ -34,6 +34,7 @@ import android.view.View
|
|||||||
import android.view.ViewOutlineProvider
|
import android.view.ViewOutlineProvider
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import androidx.core.graphics.drawable.toBitmap
|
import androidx.core.graphics.drawable.toBitmap
|
||||||
|
import com.fankes.miui.notify.bean.IconDataBean
|
||||||
import com.fankes.miui.notify.hook.HookConst.ENABLE_COLOR_ICON_COMPAT
|
import com.fankes.miui.notify.hook.HookConst.ENABLE_COLOR_ICON_COMPAT
|
||||||
import com.fankes.miui.notify.hook.HookConst.ENABLE_COLOR_ICON_HOOK
|
import com.fankes.miui.notify.hook.HookConst.ENABLE_COLOR_ICON_HOOK
|
||||||
import com.fankes.miui.notify.hook.HookConst.ENABLE_MODULE
|
import com.fankes.miui.notify.hook.HookConst.ENABLE_MODULE
|
||||||
@@ -96,6 +97,9 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 缓存的通知优化图标数组 */
|
||||||
|
private var iconDatas = ArrayList<IconDataBean>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* - 这个是修复彩色图标的关键核心代码判断
|
* - 这个是修复彩色图标的关键核心代码判断
|
||||||
*
|
*
|
||||||
@@ -235,16 +239,17 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
var customIcon: Bitmap? = null
|
var customIcon: Bitmap? = null
|
||||||
if (prefs.getBoolean(ENABLE_NOTIFY_ICON_FIX, default = true))
|
if (prefs.getBoolean(ENABLE_NOTIFY_ICON_FIX, default = true))
|
||||||
run {
|
run {
|
||||||
IconPackParams.iconDatas.forEach {
|
if (iconDatas.isNotEmpty())
|
||||||
if ((notifyInstance.opPkgName == it.packageName ||
|
iconDatas.forEach {
|
||||||
findAppName(notifyInstance) == it.appName) &&
|
if ((notifyInstance.opPkgName == it.packageName ||
|
||||||
isAppNotifyHookOf(it)
|
findAppName(notifyInstance) == it.appName) &&
|
||||||
) {
|
isAppNotifyHookOf(it)
|
||||||
if (isNotGrayscaleIcon || isAppNotifyHookAllOf(it))
|
) {
|
||||||
customIcon = it.iconBitmap
|
if (isNotGrayscaleIcon || isAppNotifyHookAllOf(it))
|
||||||
return@run
|
customIcon = it.iconBitmap
|
||||||
|
return@run
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/** 打印日志 */
|
/** 打印日志 */
|
||||||
if (prefs.getBoolean(ENABLE_MODULE_LOG))
|
if (prefs.getBoolean(ENABLE_MODULE_LOG))
|
||||||
@@ -309,18 +314,19 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
var customIconColor = 0
|
var customIconColor = 0
|
||||||
|
|
||||||
if (isNotifyIconFix) run {
|
if (isNotifyIconFix) run {
|
||||||
IconPackParams.iconDatas.forEach {
|
if (iconDatas.isNotEmpty())
|
||||||
if ((notifyInstance.opPkgName == it.packageName ||
|
iconDatas.forEach {
|
||||||
findAppName(notifyInstance) == it.appName) &&
|
if ((notifyInstance.opPkgName == it.packageName ||
|
||||||
isAppNotifyHookOf(it)
|
findAppName(notifyInstance) == it.appName) &&
|
||||||
) {
|
isAppNotifyHookOf(it)
|
||||||
if (!isGrayscaleIcon || isAppNotifyHookAllOf(it)) {
|
) {
|
||||||
customIcon = it.iconBitmap
|
if (!isGrayscaleIcon || isAppNotifyHookAllOf(it)) {
|
||||||
customIconColor = it.iconColor
|
customIcon = it.iconBitmap
|
||||||
return@run
|
customIconColor = it.iconColor
|
||||||
|
return@run
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/** 处理自定义通知图标优化 */
|
/** 处理自定义通知图标优化 */
|
||||||
if (customIcon != null)
|
if (customIcon != null)
|
||||||
@@ -390,15 +396,16 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
/** 如果开启了自定义通知图标优化 */
|
/** 如果开启了自定义通知图标优化 */
|
||||||
if (prefs.getBoolean(ENABLE_NOTIFY_ICON_FIX, default = true))
|
if (prefs.getBoolean(ENABLE_NOTIFY_ICON_FIX, default = true))
|
||||||
run {
|
run {
|
||||||
IconPackParams.iconDatas.forEach {
|
if (iconDatas.isNotEmpty())
|
||||||
if ((notifyInstance.opPkgName == it.packageName ||
|
iconDatas.forEach {
|
||||||
findAppName(notifyInstance) == it.appName) &&
|
if ((notifyInstance.opPkgName == it.packageName ||
|
||||||
isAppNotifyHookOf(it)
|
findAppName(notifyInstance) == it.appName) &&
|
||||||
) {
|
isAppNotifyHookOf(it)
|
||||||
if (isNotGrayscaleIcon || isAppNotifyHookAllOf(it)) isTargetFixApp = true
|
) {
|
||||||
return@run
|
if (isNotGrayscaleIcon || isAppNotifyHookAllOf(it)) isTargetFixApp = true
|
||||||
|
return@run
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 只要不是灰度就返回彩色图标
|
* 只要不是灰度就返回彩色图标
|
||||||
@@ -425,6 +432,9 @@ class HookEntry : YukiHookXposedInitProxy {
|
|||||||
!prefs.getBoolean(ENABLE_MODULE, default = true) -> loggerW(msg = "Aborted Hook -> Hook Closed")
|
!prefs.getBoolean(ENABLE_MODULE, default = true) -> loggerW(msg = "Aborted Hook -> Hook Closed")
|
||||||
/** 开始 Hook */
|
/** 开始 Hook */
|
||||||
else -> {
|
else -> {
|
||||||
|
/** 缓存图标数据 */
|
||||||
|
iconDatas = IconPackParams(param = this).iconDatas
|
||||||
|
/** 执行 Hook */
|
||||||
NotificationUtilClass.hook {
|
NotificationUtilClass.hook {
|
||||||
/** 强制回写系统的状态栏图标样式为原生 */
|
/** 强制回写系统的状态栏图标样式为原生 */
|
||||||
injectMember {
|
injectMember {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
package com.fankes.miui.notify.ui
|
package com.fankes.miui.notify.ui
|
||||||
|
|
||||||
|
import android.app.ProgressDialog
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
@@ -36,18 +37,17 @@ import android.widget.TextView
|
|||||||
import androidx.constraintlayout.utils.widget.ImageFilterView
|
import androidx.constraintlayout.utils.widget.ImageFilterView
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import com.fankes.miui.notify.R
|
import com.fankes.miui.notify.R
|
||||||
|
import com.fankes.miui.notify.bean.IconDataBean
|
||||||
import com.fankes.miui.notify.hook.factory.isAppNotifyHookAllOf
|
import com.fankes.miui.notify.hook.factory.isAppNotifyHookAllOf
|
||||||
import com.fankes.miui.notify.hook.factory.isAppNotifyHookOf
|
import com.fankes.miui.notify.hook.factory.isAppNotifyHookOf
|
||||||
import com.fankes.miui.notify.hook.factory.putAppNotifyHookAllOf
|
import com.fankes.miui.notify.hook.factory.putAppNotifyHookAllOf
|
||||||
import com.fankes.miui.notify.hook.factory.putAppNotifyHookOf
|
import com.fankes.miui.notify.hook.factory.putAppNotifyHookOf
|
||||||
import com.fankes.miui.notify.params.IconPackParams
|
import com.fankes.miui.notify.params.IconPackParams
|
||||||
import com.fankes.miui.notify.ui.base.BaseActivity
|
import com.fankes.miui.notify.ui.base.BaseActivity
|
||||||
import com.fankes.miui.notify.utils.SystemUITool
|
import com.fankes.miui.notify.utils.*
|
||||||
import com.fankes.miui.notify.utils.showDialog
|
|
||||||
import com.fankes.miui.notify.utils.snake
|
|
||||||
import com.fankes.miui.notify.utils.toast
|
|
||||||
import com.fankes.miui.notify.view.MaterialSwitch
|
import com.fankes.miui.notify.view.MaterialSwitch
|
||||||
import com.google.android.material.textfield.TextInputEditText
|
import com.google.android.material.textfield.TextInputEditText
|
||||||
|
import com.highcapable.yukihookapi.hook.xposed.YukiHookModuleStatus
|
||||||
|
|
||||||
class ConfigureActivity : BaseActivity() {
|
class ConfigureActivity : BaseActivity() {
|
||||||
|
|
||||||
@@ -60,9 +60,22 @@ class ConfigureActivity : BaseActivity() {
|
|||||||
/** 回调滚动事件改变 */
|
/** 回调滚动事件改变 */
|
||||||
private var onScrollEvent: ((Boolean) -> Unit)? = null
|
private var onScrollEvent: ((Boolean) -> Unit)? = null
|
||||||
|
|
||||||
|
/** 全部的通知优化图标数据 */
|
||||||
|
private var iconAllDatas = ArrayList<IconDataBean>()
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_config)
|
setContentView(R.layout.activity_config)
|
||||||
|
/** 检查激活状态 */
|
||||||
|
if (!YukiHookModuleStatus.isActive()) {
|
||||||
|
showDialog {
|
||||||
|
title = "模块没有激活"
|
||||||
|
msg = "模块没有激活,你无法使用这里的功能,请先激活模块。"
|
||||||
|
confirmButton(text = "我知道了") { finish() }
|
||||||
|
noCancelable()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
/** 返回按钮点击事件 */
|
/** 返回按钮点击事件 */
|
||||||
findViewById<View>(R.id.title_back_icon).setOnClickListener { onBackPressed() }
|
findViewById<View>(R.id.title_back_icon).setOnClickListener { onBackPressed() }
|
||||||
/** 刷新适配器结果相关 */
|
/** 刷新适配器结果相关 */
|
||||||
@@ -94,7 +107,6 @@ class ConfigureActivity : BaseActivity() {
|
|||||||
confirmButton {
|
confirmButton {
|
||||||
if (editText.text.toString().isNotBlank()) {
|
if (editText.text.toString().isNotBlank()) {
|
||||||
filterText = editText.text.toString().trim()
|
filterText = editText.text.toString().trim()
|
||||||
onChanged?.invoke()
|
|
||||||
refreshAdapterResult()
|
refreshAdapterResult()
|
||||||
} else {
|
} else {
|
||||||
toast(msg = "条件不能为空")
|
toast(msg = "条件不能为空")
|
||||||
@@ -105,11 +117,12 @@ class ConfigureActivity : BaseActivity() {
|
|||||||
if (filterText.isNotBlank())
|
if (filterText.isNotBlank())
|
||||||
neutralButton(text = "清除条件") {
|
neutralButton(text = "清除条件") {
|
||||||
filterText = ""
|
filterText = ""
|
||||||
onChanged?.invoke()
|
|
||||||
refreshAdapterResult()
|
refreshAdapterResult()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/** 设置同步列表按钮点击事件 */
|
||||||
|
findViewById<View>(R.id.config_title_sync).setOnClickListener { onStartRefresh() }
|
||||||
/** 设置列表元素和 Adapter */
|
/** 设置列表元素和 Adapter */
|
||||||
findViewById<ListView>(R.id.config_list_view).apply {
|
findViewById<ListView>(R.id.config_list_view).apply {
|
||||||
adapter = object : BaseAdapter() {
|
adapter = object : BaseAdapter() {
|
||||||
@@ -182,7 +195,7 @@ class ConfigureActivity : BaseActivity() {
|
|||||||
runCatching {
|
runCatching {
|
||||||
startActivity(Intent().apply {
|
startActivity(Intent().apply {
|
||||||
action = "android.intent.action.VIEW"
|
action = "android.intent.action.VIEW"
|
||||||
data = Uri.parse("https://github.com/fankes/MIUINativeNotifyIcon")
|
data = Uri.parse("https://github.com/fankes/MIUINativeNotifyIcon/blob/master/CONTRIBUTING.md")
|
||||||
/** 防止顶栈一样重叠在自己的 APP 中 */
|
/** 防止顶栈一样重叠在自己的 APP 中 */
|
||||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
})
|
})
|
||||||
@@ -190,14 +203,78 @@ class ConfigureActivity : BaseActivity() {
|
|||||||
toast(msg = "无法启动系统默认浏览器")
|
toast(msg = "无法启动系统默认浏览器")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/** 装载数据 */
|
||||||
|
mockLocalData()
|
||||||
|
/** 更新数据 */
|
||||||
|
onStartRefresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 装载或刷新本地数据 */
|
||||||
|
private fun mockLocalData() {
|
||||||
|
iconAllDatas = IconPackParams(context = this).iconDatas
|
||||||
|
refreshAdapterResult()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 首次进入或更新数据 */
|
||||||
|
private fun onStartRefresh() =
|
||||||
|
showDialog {
|
||||||
|
title = if (iconAllDatas.isNotEmpty()) "同步列表" else "初始化"
|
||||||
|
msg = (if (iconAllDatas.isNotEmpty()) "建议定期从云端拉取数据以获得最新的通知图标优化名单适配数据。\n\n"
|
||||||
|
else "首次装载需要从云端下载最新适配数据,后续可继续前往这里检查更新。\n\n") +
|
||||||
|
"[Github] 同步最新数据,无法连接可能需要魔法上网。\n\n[Surge] 缓存 CDN 数据,可以直连,但数据可能会有更新延迟。\n\n" +
|
||||||
|
"如果以上地址均无法使用,建议魔法上网或修改 Host 文件直连。"
|
||||||
|
confirmButton(text = "Surge") {
|
||||||
|
onRefreshing(url = "https://fankes.mnn.surge.sh/NotifyIconsSupportConfig.json")
|
||||||
|
}
|
||||||
|
cancelButton(text = "Github") {
|
||||||
|
onRefreshing(url = "https://raw.githubusercontent.com/fankes/MIUINativeNotifyIcon/master/iconPack/NotifyIconsSupportConfig.json")
|
||||||
|
}
|
||||||
|
neutralButton(text = "取消")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始更新数据
|
||||||
|
* @param url 使用的地址
|
||||||
|
*/
|
||||||
|
private fun onRefreshing(url: String) {
|
||||||
|
ProgressDialog(this).apply {
|
||||||
|
setDefaultStyle(context = this@ConfigureActivity)
|
||||||
|
setCancelable(false)
|
||||||
|
setTitle("同步中")
|
||||||
|
setMessage("正在同步云端数据")
|
||||||
|
show()
|
||||||
|
}.also {
|
||||||
|
ClientRequestTool.wait(context = this, url) { isDone, content ->
|
||||||
|
it.cancel()
|
||||||
|
IconPackParams(context = this).also { params ->
|
||||||
|
if (isDone)
|
||||||
|
if (params.isCompareDifferent(content)) {
|
||||||
|
params.save(content)
|
||||||
|
filterText = ""
|
||||||
|
mockLocalData()
|
||||||
|
SystemUITool.showNeedUpdateApplySnake(context = this)
|
||||||
|
} else snake(msg = "列表数据已是最新")
|
||||||
|
else
|
||||||
|
showDialog {
|
||||||
|
title = "连接失败"
|
||||||
|
msg = "连接失败,错误如下:\n$content"
|
||||||
|
confirmButton(text = "我知道了")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 刷新适配器结果相关 */
|
/** 刷新适配器结果相关 */
|
||||||
private fun refreshAdapterResult() {
|
private fun refreshAdapterResult() {
|
||||||
|
onChanged?.invoke()
|
||||||
findViewById<TextView>(R.id.config_title_count_text).text =
|
findViewById<TextView>(R.id.config_title_count_text).text =
|
||||||
if (filterText.isBlank()) "已适配 ${iconDatas.size} 个 APP 的通知图标"
|
if (filterText.isBlank()) "已适配 ${iconDatas.size} 个 APP 的通知图标"
|
||||||
else "“${filterText}” 匹配到 ${iconDatas.size} 个结果"
|
else "“${filterText}” 匹配到 ${iconDatas.size} 个结果"
|
||||||
findViewById<View>(R.id.config_list_no_data_view).isVisible = iconDatas.isEmpty()
|
findViewById<TextView>(R.id.config_list_no_data_view).apply {
|
||||||
|
text = if (iconAllDatas.isEmpty()) "噫,竟然什么都没有~\n请点击右上角同步按钮获取云端数据" else "噫,竟然什么都没找到~"
|
||||||
|
isVisible = iconDatas.isEmpty()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -205,8 +282,8 @@ class ConfigureActivity : BaseActivity() {
|
|||||||
* @return [Array]
|
* @return [Array]
|
||||||
*/
|
*/
|
||||||
private val iconDatas
|
private val iconDatas
|
||||||
get() = if (filterText.isBlank()) IconPackParams.iconDatas
|
get() = if (filterText.isBlank()) iconAllDatas
|
||||||
else IconPackParams.iconDatas.filter {
|
else iconAllDatas.filter {
|
||||||
it.appName.lowercase().contains(filterText.lowercase()) || it.packageName.lowercase().contains(filterText.lowercase())
|
it.appName.lowercase().contains(filterText.lowercase()) || it.packageName.lowercase().contains(filterText.lowercase())
|
||||||
}.toTypedArray()
|
}
|
||||||
}
|
}
|
@@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
|
||||||
|
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||||
|
* https://github.com/fankes/MIUINativeNotifyIcon
|
||||||
|
*
|
||||||
|
* This software is non-free but opensource software: you can redistribute it
|
||||||
|
* and/or modify it under the terms of the GNU Affero General Public License
|
||||||
|
* as published by the Free Software Foundation; either
|
||||||
|
* version 3 of the License, or any later version.
|
||||||
|
* <p>
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* and eula along with this software. If not, see
|
||||||
|
* <https://www.gnu.org/licenses/>
|
||||||
|
*
|
||||||
|
* This file is Created by fankes on 2022/2/25.
|
||||||
|
*/
|
||||||
|
@file:Suppress("TrustAllX509TrustManager", "CustomX509TrustManager")
|
||||||
|
|
||||||
|
package com.fankes.miui.notify.utils
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import com.highcapable.yukihookapi.hook.log.loggerD
|
||||||
|
import okhttp3.*
|
||||||
|
import java.io.IOException
|
||||||
|
import java.security.SecureRandom
|
||||||
|
import java.security.cert.X509Certificate
|
||||||
|
import javax.net.ssl.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网络请求管理类
|
||||||
|
*/
|
||||||
|
object ClientRequestTool {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送 GET 请求内容并等待
|
||||||
|
* @param context 实例
|
||||||
|
* @param url 请求地址
|
||||||
|
* @param it 回调 - ([Boolean] 是否成功,[String] 成功的内容或失败消息)
|
||||||
|
*/
|
||||||
|
fun wait(context: Activity, url: String, it: (Boolean, String) -> Unit) {
|
||||||
|
OkHttpClient().newBuilder().apply {
|
||||||
|
SSLSocketClient.sSLSocketFactory?.let { sslSocketFactory(it, SSLSocketClient.trustManager) }
|
||||||
|
hostnameVerifier(SSLSocketClient.hostnameVerifier)
|
||||||
|
}.build().newCall(
|
||||||
|
Request.Builder()
|
||||||
|
.url(url)
|
||||||
|
.get()
|
||||||
|
.build()
|
||||||
|
).enqueue(object : Callback {
|
||||||
|
override fun onFailure(call: Call, e: IOException) {
|
||||||
|
context.runOnUiThread { it(false, e.toString()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResponse(call: Call, response: Response) {
|
||||||
|
val bodyString = response.body?.string() ?: ""
|
||||||
|
context.runOnUiThread { it(true, bodyString) }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动信任 SSL 证书
|
||||||
|
*
|
||||||
|
* 放行全部加密 SSL 请求
|
||||||
|
*/
|
||||||
|
object SSLSocketClient {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化实例
|
||||||
|
* @return [SSLSocketFactory] or null
|
||||||
|
*/
|
||||||
|
val sSLSocketFactory
|
||||||
|
get() = safeOfNull {
|
||||||
|
SSLContext.getInstance("TLS").let {
|
||||||
|
it.init(null, arrayOf<TrustManager>(trustManager), SecureRandom())
|
||||||
|
it.socketFactory
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用的实例
|
||||||
|
* @return [HostnameVerifier]
|
||||||
|
*/
|
||||||
|
val hostnameVerifier get() = HostnameVerifier { _, _ -> true }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 信任管理者
|
||||||
|
* @return [X509TrustManager]
|
||||||
|
*/
|
||||||
|
val trustManager
|
||||||
|
get() = object : X509TrustManager {
|
||||||
|
|
||||||
|
override fun checkClientTrusted(chain: Array<X509Certificate?>?, authType: String?) {
|
||||||
|
loggerD(msg = "TrustX509 --> $authType")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun checkServerTrusted(chain: Array<X509Certificate?>?, authType: String?) {
|
||||||
|
loggerD(msg = "TrustX509 --> $authType")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAcceptedIssuers() = arrayOf<X509Certificate>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -26,8 +26,6 @@ package com.fankes.miui.notify.utils
|
|||||||
|
|
||||||
import android.app.AlertDialog
|
import android.app.AlertDialog
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Color
|
|
||||||
import android.graphics.drawable.GradientDrawable
|
|
||||||
import android.util.DisplayMetrics
|
import android.util.DisplayMetrics
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@@ -109,14 +107,7 @@ class DialogBuilder(private val context: Context) {
|
|||||||
internal fun show() = instance?.create()?.apply {
|
internal fun show() = instance?.create()?.apply {
|
||||||
val dm = DisplayMetrics()
|
val dm = DisplayMetrics()
|
||||||
(context.getSystemService(Context.WINDOW_SERVICE) as WindowManager).defaultDisplay.getMetrics(dm)
|
(context.getSystemService(Context.WINDOW_SERVICE) as WindowManager).defaultDisplay.getMetrics(dm)
|
||||||
customLayoutView?.let { setView(it.apply { minimumWidth = round(dm.widthPixels / 1.3).toInt() }) }
|
customLayoutView?.let { setView(it.apply { minimumWidth = round(x = dm.widthPixels / 1.3).toInt() }) }
|
||||||
window?.setBackgroundDrawable(GradientDrawable(
|
setDefaultStyle(context = this@DialogBuilder.context)
|
||||||
GradientDrawable.Orientation.TOP_BOTTOM,
|
|
||||||
intArrayOf(Color.WHITE, Color.WHITE)
|
|
||||||
).apply {
|
|
||||||
shape = GradientDrawable.RECTANGLE
|
|
||||||
gradientType = GradientDrawable.LINEAR_GRADIENT
|
|
||||||
cornerRadius = 15.dp(this@DialogBuilder.context)
|
|
||||||
})
|
|
||||||
}?.show()
|
}?.show()
|
||||||
}
|
}
|
@@ -58,4 +58,13 @@ object SystemUITool {
|
|||||||
if (YukiHookModuleStatus.isActive())
|
if (YukiHookModuleStatus.isActive())
|
||||||
context.snake(msg = "设置需要重启系统界面才能生效", actionText = "立即重启") { restartSystemUI(context) }
|
context.snake(msg = "设置需要重启系统界面才能生效", actionText = "立即重启") { restartSystemUI(context) }
|
||||||
else context.snake(msg = "模块没有激活,更改不会生效")
|
else context.snake(msg = "模块没有激活,更改不会生效")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示更新数据后需要重启系统界面的 [Snackbar]
|
||||||
|
* @param context 实例
|
||||||
|
*/
|
||||||
|
fun showNeedUpdateApplySnake(context: Context) =
|
||||||
|
if (YukiHookModuleStatus.isActive())
|
||||||
|
context.snake(msg = "数据已更新,请重启系统界面使更改生效", actionText = "立即重启") { restartSystemUI(context) }
|
||||||
|
else context.snake(msg = "模块没有激活,更改不会生效")
|
||||||
}
|
}
|
@@ -25,6 +25,7 @@
|
|||||||
package com.fankes.miui.notify.utils
|
package com.fankes.miui.notify.utils
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
import android.app.AlertDialog
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.pm.PackageInfo
|
import android.content.pm.PackageInfo
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
@@ -32,6 +33,7 @@ import android.content.res.Configuration
|
|||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
|
import android.graphics.drawable.GradientDrawable
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import android.util.Base64
|
import android.util.Base64
|
||||||
@@ -215,6 +217,21 @@ val ByteArray.bitmap: Bitmap get() = BitmapFactory.decodeByteArray(this, 0, size
|
|||||||
*/
|
*/
|
||||||
val String.bitmap: Bitmap get() = unbase64.bitmap
|
val String.bitmap: Bitmap get() = unbase64.bitmap
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置对话框默认风格
|
||||||
|
* @param context 使用的实例
|
||||||
|
*/
|
||||||
|
fun AlertDialog.setDefaultStyle(context: Context) =
|
||||||
|
window?.setBackgroundDrawable(
|
||||||
|
GradientDrawable(
|
||||||
|
GradientDrawable.Orientation.TOP_BOTTOM,
|
||||||
|
intArrayOf(Color.WHITE, Color.WHITE)
|
||||||
|
).apply {
|
||||||
|
shape = GradientDrawable.RECTANGLE
|
||||||
|
gradientType = GradientDrawable.LINEAR_GRADIENT
|
||||||
|
cornerRadius = 15.dp(context)
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取系统 Prop 值
|
* 获取系统 Prop 值
|
||||||
* @param key Key
|
* @param key Key
|
||||||
|
@@ -52,7 +52,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
android:text="..."
|
android:text="适配列表正在等待装载"
|
||||||
android:textColor="@color/colorTextDark"
|
android:textColor="@color/colorTextDark"
|
||||||
android:textSize="12sp" />
|
android:textSize="12sp" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
@@ -61,7 +61,7 @@
|
|||||||
android:id="@+id/config_title_up"
|
android:id="@+id/config_title_up"
|
||||||
android:layout_width="22dp"
|
android:layout_width="22dp"
|
||||||
android:layout_height="22dp"
|
android:layout_height="22dp"
|
||||||
android:layout_marginEnd="10dp"
|
android:layout_marginEnd="5dp"
|
||||||
android:src="@mipmap/ic_page_top"
|
android:src="@mipmap/ic_page_top"
|
||||||
android:tint="@color/colorTextGray"
|
android:tint="@color/colorTextGray"
|
||||||
android:tooltipText="滚动到顶部" />
|
android:tooltipText="滚动到顶部" />
|
||||||
@@ -70,7 +70,7 @@
|
|||||||
android:id="@+id/config_title_down"
|
android:id="@+id/config_title_down"
|
||||||
android:layout_width="22dp"
|
android:layout_width="22dp"
|
||||||
android:layout_height="22dp"
|
android:layout_height="22dp"
|
||||||
android:layout_marginEnd="17dp"
|
android:layout_marginEnd="15dp"
|
||||||
android:src="@mipmap/ic_page_bottom"
|
android:src="@mipmap/ic_page_bottom"
|
||||||
android:tint="@color/colorTextGray"
|
android:tint="@color/colorTextGray"
|
||||||
android:tooltipText="滚动到底部" />
|
android:tooltipText="滚动到底部" />
|
||||||
@@ -83,6 +83,15 @@
|
|||||||
android:src="@mipmap/ic_filter"
|
android:src="@mipmap/ic_filter"
|
||||||
android:tint="@color/colorTextGray"
|
android:tint="@color/colorTextGray"
|
||||||
android:tooltipText="按条件过滤" />
|
android:tooltipText="按条件过滤" />
|
||||||
|
|
||||||
|
<androidx.constraintlayout.utils.widget.ImageFilterView
|
||||||
|
android:id="@+id/config_title_sync"
|
||||||
|
android:layout_width="23dp"
|
||||||
|
android:layout_height="23dp"
|
||||||
|
android:layout_marginEnd="10dp"
|
||||||
|
android:src="@mipmap/ic_sync"
|
||||||
|
android:tint="@color/colorTextGray"
|
||||||
|
android:tooltipText="同步列表" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
@@ -126,7 +135,9 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:text="噫,竟然什么都没找到~"
|
android:gravity="center"
|
||||||
|
android:lineSpacingExtra="6dp"
|
||||||
|
android:text="没有数据"
|
||||||
android:textColor="@color/colorTextDark"
|
android:textColor="@color/colorTextDark"
|
||||||
android:textSize="17sp"
|
android:textSize="17sp"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
@@ -280,6 +280,18 @@
|
|||||||
android:textColor="@color/colorTextGray"
|
android:textColor="@color/colorTextGray"
|
||||||
android:textSize="15sp" />
|
android:textSize="15sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="5dp"
|
||||||
|
android:layout_marginRight="5dp"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:alpha="0.6"
|
||||||
|
android:lineSpacingExtra="6dp"
|
||||||
|
android:text="首次安装请打开名单列表从云端更新数据,后期适配的内容也请手动打开名单列表重新拉取数据以检查更新,数据更新后重启系统界面即可生效。"
|
||||||
|
android:textColor="@color/colorTextDark"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
BIN
app/src/main/res/mipmap-xxhdpi/ic_sync.png
Normal file
BIN
app/src/main/res/mipmap-xxhdpi/ic_sync.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.0 KiB |
@@ -2,16 +2,13 @@ package com.fankes.miui.notify
|
|||||||
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
import org.junit.Assert.*
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Example local unit test, which will execute on the development machine (host).
|
* Example local unit test, which will execute on the development machine (host).
|
||||||
*
|
*
|
||||||
* See [testing documentation](http://d.android.com/tools/testing).
|
* See [testing documentation](http://d.android.com/tools/testing).
|
||||||
*/
|
*/
|
||||||
class ExampleUnitTest {
|
class ExampleUnitTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun addition_isCorrect() {
|
fun main() = println("Hello world")
|
||||||
assertEquals(4, 2 + 2)
|
|
||||||
}
|
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user