Merge code

This commit is contained in:
2022-03-20 14:11:08 +08:00
parent b610eca3b2
commit e509f0e6db
10 changed files with 224 additions and 39 deletions

1
.idea/misc.xml generated
View File

@@ -9,6 +9,7 @@
<entry key="app/src/main/res/drawable/bg_dark_round.xml" value="0.2325" /> <entry key="app/src/main/res/drawable/bg_dark_round.xml" value="0.2325" />
<entry key="app/src/main/res/drawable/bg_dialog_background.xml" value="0.2325" /> <entry key="app/src/main/res/drawable/bg_dialog_background.xml" value="0.2325" />
<entry key="app/src/main/res/drawable/bg_green_round.xml" value="0.255" /> <entry key="app/src/main/res/drawable/bg_green_round.xml" value="0.255" />
<entry key="app/src/main/res/drawable/bg_orange_round.xml" value="0.2325" />
<entry key="app/src/main/res/drawable/bg_warn_round.xml" value="0.2325" /> <entry key="app/src/main/res/drawable/bg_warn_round.xml" value="0.2325" />
<entry key="app/src/main/res/drawable/bg_yellow_round.xml" value="0.255" /> <entry key="app/src/main/res/drawable/bg_yellow_round.xml" value="0.255" />
<entry key="app/src/main/res/drawable/permotion_round.xml" value="0.256" /> <entry key="app/src/main/res/drawable/permotion_round.xml" value="0.256" />

View File

@@ -4,6 +4,7 @@
package="com.fankes.miui.notify"> package="com.fankes.miui.notify">
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application <application
android:name=".application.MNNApplication" android:name=".application.MNNApplication"

View File

@@ -302,16 +302,16 @@ class HookEntry : YukiHookXposedInitProxy {
expandedNf: StatusBarNotification?, expandedNf: StatusBarNotification?,
iconDrawable: Drawable?, iconDrawable: Drawable?,
it: (Bitmap) -> Unit it: (Bitmap) -> Unit
) = runSafe(msg = "GetSmallIconOnSet") { ) = runInSafe(msg = "GetSmallIconOnSet") {
if (iconDrawable == null) return@runSafe if (iconDrawable == null) return@runInSafe
/** 如果没开启修复 APP 的彩色图标 */ /** 如果没开启修复 APP 的彩色图标 */
if (!prefs.getBoolean(ENABLE_COLOR_ICON_HOOK, default = true)) return@runSafe if (!prefs.getBoolean(ENABLE_COLOR_ICON_HOOK, default = true)) return@runInSafe
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */ /** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
expandedNf?.also { notifyInstance -> expandedNf?.also { notifyInstance ->
/** 判断是 MIUI 样式就停止 Hook */ /** 判断是 MIUI 样式就停止 Hook */
if (context.isMiuiNotifyStyle) { if (context.isMiuiNotifyStyle) {
it(notifyInstance.findAppIcon(context).toBitmap()) it(notifyInstance.findAppIcon(context).toBitmap())
return@runSafe return@runInSafe
} }
/** 判断是否不是灰度图标 */ /** 判断是否不是灰度图标 */
val isNotGrayscaleIcon = notifyInstance.isXmsf || !isGrayscaleIcon(context, iconDrawable) val isNotGrayscaleIcon = notifyInstance.isXmsf || !isGrayscaleIcon(context, iconDrawable)
@@ -343,11 +343,11 @@ class HookEntry : YukiHookXposedInitProxy {
expandedNf: StatusBarNotification?, expandedNf: StatusBarNotification?,
iconImageView: ImageView, iconImageView: ImageView,
isExpanded: Boolean isExpanded: Boolean
) = runSafe(msg = "AutoSetAppIconOnSet") { ) = runInSafe(msg = "AutoSetAppIconOnSet") {
/** 判断是 MIUI 样式就停止 Hook */ /** 判断是 MIUI 样式就停止 Hook */
if (context.isMiuiNotifyStyle) return@runSafe if (context.isMiuiNotifyStyle) return@runInSafe
/** 如果没开启修复 APP 的彩色图标 */ /** 如果没开启修复 APP 的彩色图标 */
if (!prefs.getBoolean(ENABLE_COLOR_ICON_HOOK, default = true)) return@runSafe if (!prefs.getBoolean(ENABLE_COLOR_ICON_HOOK, default = true)) return@runInSafe
/** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */ /** 获取通知对象 - 由于 MIUI 的版本迭代不规范性可能是空的 */
expandedNf?.let { notifyInstance -> expandedNf?.let { notifyInstance ->

View File

@@ -46,6 +46,7 @@ import com.fankes.miui.notify.hook.HookConst.HOOK_STATUS_ICON_COUNT
import com.fankes.miui.notify.params.IconPackParams import com.fankes.miui.notify.params.IconPackParams
import com.fankes.miui.notify.ui.activity.base.BaseActivity import com.fankes.miui.notify.ui.activity.base.BaseActivity
import com.fankes.miui.notify.utils.factory.* import com.fankes.miui.notify.utils.factory.*
import com.fankes.miui.notify.utils.tool.GithubReleaseTool
import com.fankes.miui.notify.utils.tool.SystemUITool import com.fankes.miui.notify.utils.tool.SystemUITool
import com.highcapable.yukihookapi.hook.factory.isXposedModuleActive import com.highcapable.yukihookapi.hook.factory.isXposedModuleActive
import com.highcapable.yukihookapi.hook.factory.modulePrefs import com.highcapable.yukihookapi.hook.factory.modulePrefs
@@ -65,6 +66,14 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
/** 设置文本 */ /** 设置文本 */
binding.mainTextVersion.text = "模块版本:$moduleVersion" binding.mainTextVersion.text = "模块版本:$moduleVersion"
binding.mainTextMiuiVersion.text = "系统版本:$miuiFullVersion" binding.mainTextMiuiVersion.text = "系统版本:$miuiFullVersion"
/** 检查更新 */
GithubReleaseTool.checkingForUpdate(context = this, moduleVersion) { version, function ->
binding.mainTextReleaseVersion.apply {
text = "点击更新 $version"
isVisible = true
setOnClickListener { function() }
}
}
when { when {
/** 判断是否为 MIUI 系统 */ /** 判断是否为 MIUI 系统 */
isNotMIUI -> isNotMIUI ->
@@ -233,9 +242,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
/** 重启按钮点击事件 */ /** 重启按钮点击事件 */
binding.titleRestartIcon.setOnClickListener { SystemUITool.restartSystemUI(context = this) } binding.titleRestartIcon.setOnClickListener { SystemUITool.restartSystemUI(context = this) }
/** 项目地址按钮点击事件 */ /** 项目地址按钮点击事件 */
binding.titleGithubIcon.setOnClickListener { binding.titleGithubIcon.setOnClickListener { openBrowser(url = "https://github.com/fankes/MIUINativeNotifyIcon") }
openBrowser(url = "https://github.com/fankes/MIUINativeNotifyIcon")
}
/** 恰饭! */ /** 恰饭! */
binding.linkWithFollowMe.setOnClickListener { binding.linkWithFollowMe.setOnClickListener {
openBrowser(url = "https://www.coolapk.com/u/876977", packageName = "com.coolapk.market") openBrowser(url = "https://www.coolapk.com/u/876977", packageName = "com.coolapk.market")
@@ -286,9 +293,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
/** 防止顶栈一样重叠在自己的 APP 中 */ /** 防止顶栈一样重叠在自己的 APP 中 */
flags = Intent.FLAG_ACTIVITY_NEW_TASK flags = Intent.FLAG_ACTIVITY_NEW_TASK
}) })
}.onFailure { }.onFailure { toast(msg = "启动失败,请手动调整设置") }
toast(msg = "启动失败,请手动调整设置")
}
isWarnDialogShowing = false isWarnDialogShowing = false
} }
cancelButton { isWarnDialogShowing = false } cancelButton { isWarnDialogShowing = false }

View File

@@ -73,8 +73,8 @@ class DialogBuilder(val context: Context, private val isUseBlackTheme: Boolean)
init { init {
if (isUsingAndroidX) if (isUsingAndroidX)
runCatching { instanceAndroidX = MaterialAlertDialogBuilder(context) } runInSafe { instanceAndroidX = MaterialAlertDialogBuilder(context) }
else runCatching { else runInSafe {
instanceAndroid = android.app.AlertDialog.Builder( instanceAndroid = android.app.AlertDialog.Builder(
context, context,
if (isUseBlackTheme) android.R.style.Theme_Material_Dialog else android.R.style.Theme_Material_Light_Dialog if (isUseBlackTheme) android.R.style.Theme_Material_Dialog else android.R.style.Theme_Material_Light_Dialog
@@ -85,8 +85,8 @@ class DialogBuilder(val context: Context, private val isUseBlackTheme: Boolean)
/** 设置对话框不可关闭 */ /** 设置对话框不可关闭 */
fun noCancelable() { fun noCancelable() {
if (isUsingAndroidX) if (isUsingAndroidX)
runCatching { instanceAndroidX?.setCancelable(false) } runInSafe { instanceAndroidX?.setCancelable(false) }
else runCatching { instanceAndroid?.setCancelable(false) } else runInSafe { instanceAndroid?.setCancelable(false) }
} }
/** 设置对话框标题 */ /** 设置对话框标题 */
@@ -94,8 +94,8 @@ class DialogBuilder(val context: Context, private val isUseBlackTheme: Boolean)
get() = "" get() = ""
set(value) { set(value) {
if (isUsingAndroidX) if (isUsingAndroidX)
runCatching { instanceAndroidX?.setTitle(value) } runInSafe { instanceAndroidX?.setTitle(value) }
else runCatching { instanceAndroid?.setTitle(value) } else runInSafe { instanceAndroid?.setTitle(value) }
} }
/** 设置对话框消息内容 */ /** 设置对话框消息内容 */
@@ -103,8 +103,8 @@ class DialogBuilder(val context: Context, private val isUseBlackTheme: Boolean)
get() = "" get() = ""
set(value) { set(value) {
if (isUsingAndroidX) if (isUsingAndroidX)
runCatching { instanceAndroidX?.setMessage(value) } runInSafe { instanceAndroidX?.setMessage(value) }
else runCatching { instanceAndroid?.setMessage(value) } else runInSafe { instanceAndroid?.setMessage(value) }
} }
/** 设置进度条对话框消息内容 */ /** 设置进度条对话框消息内容 */
@@ -145,8 +145,8 @@ class DialogBuilder(val context: Context, private val isUseBlackTheme: Boolean)
*/ */
fun confirmButton(text: String = "确定", it: () -> Unit = {}) { fun confirmButton(text: String = "确定", it: () -> Unit = {}) {
if (isUsingAndroidX) if (isUsingAndroidX)
runCatching { instanceAndroidX?.setPositiveButton(text) { _, _ -> it() } } runInSafe { instanceAndroidX?.setPositiveButton(text) { _, _ -> it() } }
else runCatching { instanceAndroid?.setPositiveButton(text) { _, _ -> it() } } else runInSafe { instanceAndroid?.setPositiveButton(text) { _, _ -> it() } }
} }
/** /**
@@ -156,8 +156,8 @@ class DialogBuilder(val context: Context, private val isUseBlackTheme: Boolean)
*/ */
fun cancelButton(text: String = "取消", it: () -> Unit = {}) { fun cancelButton(text: String = "取消", it: () -> Unit = {}) {
if (isUsingAndroidX) if (isUsingAndroidX)
runCatching { instanceAndroidX?.setNegativeButton(text) { _, _ -> it() } } runInSafe { instanceAndroidX?.setNegativeButton(text) { _, _ -> it() } }
else runCatching { instanceAndroid?.setNegativeButton(text) { _, _ -> it() } } else runInSafe { instanceAndroid?.setNegativeButton(text) { _, _ -> it() } }
} }
/** /**
@@ -167,21 +167,21 @@ class DialogBuilder(val context: Context, private val isUseBlackTheme: Boolean)
*/ */
fun neutralButton(text: String = "更多", it: () -> Unit = {}) { fun neutralButton(text: String = "更多", it: () -> Unit = {}) {
if (isUsingAndroidX) if (isUsingAndroidX)
runCatching { instanceAndroidX?.setNeutralButton(text) { _, _ -> it() } } runInSafe { instanceAndroidX?.setNeutralButton(text) { _, _ -> it() } }
else runCatching { instanceAndroid?.setNeutralButton(text) { _, _ -> it() } } else runInSafe { instanceAndroid?.setNeutralButton(text) { _, _ -> it() } }
} }
/** 取消对话框 */ /** 取消对话框 */
fun cancel() = dialogInstance?.cancel() fun cancel() = dialogInstance?.cancel()
/** 显示对话框 */ /** 显示对话框 */
internal fun show() { internal fun show() =
if (isUsingAndroidX) runCatching { if (isUsingAndroidX) runInSafe {
instanceAndroidX?.create()?.apply { instanceAndroidX?.create()?.apply {
customLayoutView?.let { setView(it) } customLayoutView?.let { setView(it) }
dialogInstance = this dialogInstance = this
}?.show() }?.show()
} else runCatching { } else runInSafe {
instanceAndroid?.create()?.apply { instanceAndroid?.create()?.apply {
customLayoutView?.let { setView(it) } customLayoutView?.let { setView(it) }
window?.setBackgroundDrawable( window?.setBackgroundDrawable(
@@ -197,5 +197,4 @@ class DialogBuilder(val context: Context, private val isUseBlackTheme: Boolean)
dialogInstance = this dialogInstance = this
}?.show() }?.show()
} }
}
} }

View File

@@ -78,6 +78,6 @@ inline fun <T> safeOf(default: T, result: () -> T) = try {
* @param msg 出错输出的消息 - 默认为空 * @param msg 出错输出的消息 - 默认为空
* @param block 正常回调 * @param block 正常回调
*/ */
inline fun <T> T.runSafe(msg: String = "", block: () -> Unit) { inline fun <T> T.runInSafe(msg: String = "", block: () -> Unit) {
runCatching(block).onFailure { if (msg.isNotBlank()) loggerE(msg = msg, e = it) } runCatching(block).onFailure { if (msg.isNotBlank()) loggerE(msg = msg, e = it) }
} }

View File

@@ -35,12 +35,14 @@ 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.net.ConnectivityManager
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.provider.Settings import android.provider.Settings
import android.util.Base64 import android.util.Base64
import android.widget.Toast import android.widget.Toast
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.core.content.getSystemService
import com.fankes.miui.notify.application.MNNApplication.Companion.appContext import com.fankes.miui.notify.application.MNNApplication.Companion.appContext
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import com.highcapable.yukihookapi.hook.factory.classOf import com.highcapable.yukihookapi.hook.factory.classOf
@@ -221,6 +223,13 @@ val Context.versionCode get() = packageInfo.versionCode
*/ */
val isNotNoificationEnabled get() = !NotificationManagerCompat.from(appContext).areNotificationsEnabled() val isNotNoificationEnabled get() = !NotificationManagerCompat.from(appContext).areNotificationsEnabled()
/**
* 网络连接是否正常
* @return [Boolean] 网络是否连接
*/
val isNetWorkSuccess
get() = safeOfFalse { appContext.getSystemService<ConnectivityManager>()?.activeNetworkInfo != null }
/** /**
* dp 转换为 pxInt * dp 转换为 pxInt
* @param context 使用的实例 * @param context 使用的实例
@@ -352,11 +361,25 @@ fun Context.openBrowser(url: String, packageName: String = "") = runCatching {
else snake(msg = "启动系统浏览器失败") else snake(msg = "启动系统浏览器失败")
} }
/**
* 跳转 APP 自身设置界面
* @param packageName 包名
*/
fun Context.openSelfSetting(packageName: String = appContext.packageName) = runCatching {
if (packageName.isInstall)
startActivity(Intent().apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK
action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
data = Uri.fromParts("package", packageName, null)
})
else toast(msg = "你没有安装此应用")
}.onFailure { toast(msg = "启动 $packageName 应用信息失败") }
/** /**
* 复制到剪贴板 * 复制到剪贴板
* @param content 要复制的文本 * @param content 要复制的文本
*/ */
fun Context.copyToClipboard(content: String) = runSafe { fun Context.copyToClipboard(content: String) = runInSafe {
(getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager).apply { (getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager).apply {
setPrimaryClip(ClipData.newPlainText(null, content)) setPrimaryClip(ClipData.newPlainText(null, content))
(primaryClip?.getItemAt(0)?.text ?: "").also { (primaryClip?.getItemAt(0)?.text ?: "").also {

View File

@@ -0,0 +1,128 @@
/*
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
* https://github.com/fankes/MIUINativeNotifyIcon
*
* This software is non-free but opensource software: you can redistribute it
* and/or modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
* <p>
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/3/20.
*/
package com.fankes.miui.notify.utils.tool
import android.app.Activity
import android.content.Context
import com.fankes.miui.notify.utils.factory.*
import okhttp3.*
import org.json.JSONObject
import java.io.IOException
import java.io.Serializable
/**
* 获取 Github Release 最新版本工具类
*/
object GithubReleaseTool {
/** 仓库作者 */
private const val repoAuthor = "fankes"
/** 仓库名称 */
private const val repoName = "MIUINativeNotifyIcon"
/**
* 获取最新版本信息
* @param context 实例
* @param version 当前版本
* @param it 成功后回调 - ([String] 最新版本,[Function] 更新对话框方法体)
*/
fun checkingForUpdate(context: Context, version: String, it: (String, () -> Unit) -> Unit) = checkingInternetConnect(context) {
OkHttpClient().newBuilder().build().newCall(
Request.Builder()
.url("https://api.github.com/repos/$repoAuthor/$repoName/releases/latest")
.get()
.build()
).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {}
override fun onResponse(call: Call, response: Response) = runInSafe {
JSONObject(response.body?.string() ?: "").apply {
GithubReleaseBean(
name = getString("name"),
htmlUrl = getString("html_url"),
content = getString("body"),
date = getString("published_at").replace(oldValue = "T", newValue = " ").replace(oldValue = "Z", newValue = "")
).apply {
fun showUpdate() = context.showDialog {
title = "最新版本 $name"
msg = "发布于 $date\n\n" +
"更新日志\n\n" + content
confirmButton(text = "更新") { context.openBrowser(htmlUrl) }
cancelButton()
}
if (name != version) (context as? Activity?)?.runOnUiThread {
showUpdate()
it(name) { showUpdate() }
}
}
}
}
})
}
/**
* 检查网络连接情况
* @param context 实例
* @param it 已连接回调
*/
private fun checkingInternetConnect(context: Context, it: () -> Unit) = runInSafe {
if (isNetWorkSuccess)
OkHttpClient().newBuilder().build().newCall(
Request.Builder()
.url("https://www.baidu.com")
.get()
.build()
).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
(context as? Activity?)?.runOnUiThread {
context.showDialog {
title = "网络不可用"
msg = "模块的联网权限可能已被禁用,请开启联网权限以定期检查更新。"
confirmButton(text = "去开启") { context.openSelfSetting() }
cancelButton()
noCancelable()
}
}
}
override fun onResponse(call: Call, response: Response) = runInSafe {
(context as? Activity?)?.runOnUiThread { runInSafe { it() } }
}
})
}
/**
* Github Release bean
* @param name 版本名称
* @param htmlUrl 网页地址
* @param content 更新日志
* @param date 发布时间
*/
private data class GithubReleaseBean(
var name: String,
var htmlUrl: String,
var content: String,
var date: String
) : Serializable
}

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#FF7043" />
<corners android:radius="15dp" />
</shape>

View File

@@ -91,16 +91,38 @@
android:textColor="@color/white" android:textColor="@color/white"
android:textSize="18sp" /> android:textSize="18sp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:gravity="center|start"
android:orientation="horizontal">
<TextView <TextView
android:id="@+id/main_text_version" android:id="@+id/main_text_version"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:alpha="0.8" android:alpha="0.8"
android:text="模块版本:%1" android:text="模块版本:%1"
android:textColor="@color/white" android:textColor="@color/white"
android:textSize="13sp" /> android:textSize="13sp" />
<TextView
android:id="@+id/main_text_release_version"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:background="@drawable/bg_orange_round"
android:paddingLeft="5dp"
android:paddingTop="2dp"
android:paddingRight="5dp"
android:paddingBottom="2dp"
android:text="点击更新 %1"
android:textColor="@color/white"
android:textSize="11sp"
android:visibility="gone" />
</LinearLayout>
<TextView <TextView
android:id="@+id/main_text_miui_version" android:id="@+id/main_text_miui_version"
android:layout_width="wrap_content" android:layout_width="wrap_content"