Modify merge YukiHookAPI new usage and compatible with API 33

This commit is contained in:
2022-10-06 03:18:53 +08:00
parent 7a35833bb6
commit 7c3d3d1bda
8 changed files with 231 additions and 136 deletions

View File

@@ -39,7 +39,7 @@ import com.highcapable.yukihookapi.hook.xposed.proxy.IYukiHookXposedInit
class HookEntry : IYukiHookXposedInit { class HookEntry : IYukiHookXposedInit {
override fun onInit() = configs { override fun onInit() = configs {
debugTag = "MIUINativeNotifyIcon" debugLog { tag = "MIUINativeNotifyIcon" }
isDebug = false isDebug = false
} }

View File

@@ -179,7 +179,7 @@ object SystemUIHooker : YukiBaseHooker() {
*/ */
private fun isGrayscaleIcon(context: Context, drawable: Drawable) = private fun isGrayscaleIcon(context: Context, drawable: Drawable) =
if (prefs.get(DataConst.ENABLE_COLOR_ICON_COMPAT).not()) safeOfFalse { if (prefs.get(DataConst.ENABLE_COLOR_ICON_COMPAT).not()) safeOfFalse {
ContrastColorUtilClass.clazz.let { ContrastColorUtilClass.toClass().let {
it.method { it.method {
name = "isGrayscaleIcon" name = "isGrayscaleIcon"
param(DrawableClass) param(DrawableClass)
@@ -197,7 +197,7 @@ object SystemUIHooker : YukiBaseHooker() {
* @return [Boolean] * @return [Boolean]
*/ */
private val hasHandleHeaderViews private val hasHandleHeaderViews
get() = safeOfFalse { NotificationHeaderViewWrapperClass.clazz.hasMethod { name = "handleHeaderViews" } } get() = NotificationHeaderViewWrapperClass.toClassOrNull()?.hasMethod { name = "handleHeaderViews" } ?: false
/** /**
* 处理为圆角图标 * 处理为圆角图标
@@ -217,7 +217,7 @@ object SystemUIHooker : YukiBaseHooker() {
private fun StatusBarNotification.compatPushingIcon(context: Context, iconDrawable: Drawable) = safeOf(iconDrawable) { private fun StatusBarNotification.compatPushingIcon(context: Context, iconDrawable: Drawable) = safeOf(iconDrawable) {
/** 给 MIPUSH 设置 APP 自己的图标 */ /** 给 MIPUSH 设置 APP 自己的图标 */
if (isXmsf && nfPkgName.isNotBlank()) if (isXmsf && nfPkgName.isNotBlank())
context.findAppIcon(xmsfPkgName) ?: iconDrawable context.appIconOf(xmsfPkgName) ?: iconDrawable
else iconDrawable else iconDrawable
} }
@@ -237,7 +237,7 @@ object SystemUIHooker : YukiBaseHooker() {
isGrayscale: Boolean isGrayscale: Boolean
) { ) {
if (prefs.get(DataConst.ENABLE_MODULE_LOG)) loggerD( if (prefs.get(DataConst.ENABLE_MODULE_LOG)) loggerD(
msg = "$tag --> [${context.findAppName(name = expandedNf?.nfPkgName ?: "")}][${expandedNf?.nfPkgName}] " + msg = "$tag --> [${context.appNameOf(packageName = expandedNf?.nfPkgName ?: "")}][${expandedNf?.nfPkgName}] " +
"custom [$isCustom] " + "custom [$isCustom] " +
"grayscale [$isGrayscale] " + "grayscale [$isGrayscale] " +
"xmsf [${expandedNf?.isXmsf}]" "xmsf [${expandedNf?.isXmsf}]"
@@ -282,22 +282,21 @@ object SystemUIHooker : YukiBaseHooker() {
* 是否为 MIUI 样式通知栏 - 旧版 - 新版一律返回 false * 是否为 MIUI 样式通知栏 - 旧版 - 新版一律返回 false
* @return [Boolean] * @return [Boolean]
*/ */
private val isShowMiuiStyle get() = NotificationUtilClass.clazz.method { name = "showMiuiStyle" }.ignoredError().get().boolean() private val isShowMiuiStyle
get() = NotificationUtilClass.toClassOrNull()?.method { name = "showMiuiStyle" }?.ignored()?.get()?.boolean() ?: false
/** /**
* 是否没有单独的 MIUI 通知栏样式 * 是否没有单独的 MIUI 通知栏样式
* @return [Boolean] * @return [Boolean]
*/ */
private val isNotHasAbsoluteMiuiStyle get() = MiuiNotificationViewWrapperClass.hasClass.not() private val isNotHasAbsoluteMiuiStyle get() = MiuiNotificationViewWrapperClass.hasClass().not()
/** /**
* 获取全局上下文 * 获取全局上下文
* @return [Context] or null * @return [Context] or null
*/ */
private val globalContext private val globalContext
get() = safeOfNull { get() = SystemUIApplicationClass.toClassOrNull()?.method { name = "getContext" }?.ignored()?.get()?.invoke<Context?>() ?: appContext
SystemUIApplicationClass.clazz.method { name = "getContext" }.ignoredError().get().invoke<Context?>() ?: appContext
}
/** /**
* 注册主题壁纸改变颜色监听 * 注册主题壁纸改变颜色监听
@@ -314,7 +313,7 @@ object SystemUIHooker : YukiBaseHooker() {
/** 刷新状态栏小图标 */ /** 刷新状态栏小图标 */
private fun refreshStatusBarIcons() = runInSafe { private fun refreshStatusBarIcons() = runInSafe {
StatusBarIconViewClass.clazz.field { name = "mNotification" }.also { result -> StatusBarIconViewClass.toClassOrNull()?.field { name = "mNotification" }?.also { result ->
notificationIconContainer?.children?.forEach { notificationIconContainer?.children?.forEach {
/** 得到通知实例 */ /** 得到通知实例 */
val nf = result.get(it).cast<StatusBarNotification>() ?: return val nf = result.get(it).cast<StatusBarNotification>() ?: return
@@ -328,12 +327,10 @@ object SystemUIHooker : YukiBaseHooker() {
/** 刷新通知小图标 */ /** 刷新通知小图标 */
private fun refreshNotificationIcons() = runInSafe { private fun refreshNotificationIcons() = runInSafe {
notificationPresenter?.current { notificationPresenter?.current()?.method {
method { name = "updateNotificationsOnDensityOrFontScaleChanged"
name = "updateNotificationsOnDensityOrFontScaleChanged" emptyParam()
emptyParam() }?.call()
}.call()
}
} }
/** /**
@@ -460,6 +457,7 @@ object SystemUIHooker : YukiBaseHooker() {
/** 获取通知小图标 */ /** 获取通知小图标 */
val iconDrawable = notifyInstance.notification.smallIcon.loadDrawable(context) val iconDrawable = notifyInstance.notification.smallIcon.loadDrawable(context)
?: return@let loggerW(msg = "compatNotifyIcon got null smallIcon")
/** 判断图标风格 */ /** 判断图标风格 */
val isGrayscaleIcon = notifyInstance.isXmsf.not() && isGrayscaleIcon(context, iconDrawable) val isGrayscaleIcon = notifyInstance.isXmsf.not() && isGrayscaleIcon(context, iconDrawable)
@@ -479,7 +477,7 @@ object SystemUIHooker : YukiBaseHooker() {
/** 处理自定义通知图标优化 */ /** 处理自定义通知图标优化 */
when { when {
prefs.get(DataConst.ENABLE_NOTIFY_ICON_FORCE_APP_ICON) && isEnableHookColorNotifyIcon(isHooking = false) -> prefs.get(DataConst.ENABLE_NOTIFY_ICON_FORCE_APP_ICON) && isEnableHookColorNotifyIcon(isHooking = false) ->
setDefaultNotifyIcon(context.findAppIcon(notifyInstance.nfPkgName)) setDefaultNotifyIcon(context.appIconOf(notifyInstance.nfPkgName))
customIcon != null -> iconImageView.apply { customIcon != null -> iconImageView.apply {
/** 设置不要裁切到边界 */ /** 设置不要裁切到边界 */
clipToOutline = false clipToOutline = false
@@ -492,7 +490,7 @@ object SystemUIHooker : YukiBaseHooker() {
background = DrawableBuilder() background = DrawableBuilder()
.rectangle() .rectangle()
.cornerRadius(iconCorner.dp(context)) .cornerRadius(iconCorner.dp(context))
.solidColor(if (context.isSystemInDarkMode) customIconColor.brighter else customIconColor) .solidColor(if (context.isSystemInDarkMode) customIconColor.brighterColor else customIconColor)
.build() .build()
/** 设置原生的背景边距 */ /** 设置原生的背景边距 */
if (isUseAndroid12Style) setPadding(4.dp(context), 4.dp(context), 4.dp(context), 4.dp(context)) if (isUseAndroid12Style) setPadding(4.dp(context), 4.dp(context), 4.dp(context), 4.dp(context))
@@ -512,7 +510,7 @@ object SystemUIHooker : YukiBaseHooker() {
background = DrawableBuilder() background = DrawableBuilder()
.rectangle() .rectangle()
.cornerRadius(iconCorner.dp(context)) .cornerRadius(iconCorner.dp(context))
.solidColor(if (context.isSystemInDarkMode) it.brighter else it) .solidColor(if (context.isSystemInDarkMode) it.brighterColor else it)
.build() .build()
} }
/** 设置原生的背景边距 */ /** 设置原生的背景边距 */
@@ -536,6 +534,7 @@ object SystemUIHooker : YukiBaseHooker() {
expandedNf?.let { notifyInstance -> expandedNf?.let { notifyInstance ->
/** 获取通知小图标 */ /** 获取通知小图标 */
val iconDrawable = notifyInstance.notification.smallIcon.loadDrawable(context) val iconDrawable = notifyInstance.notification.smallIcon.loadDrawable(context)
?: return loggerW(msg = "hasIgnoreStatusBarIconColor got null smallIcon").let { true }
/** 判断是否不是灰度图标 */ /** 判断是否不是灰度图标 */
val isNotGrayscaleIcon = notifyInstance.isXmsf || isGrayscaleIcon(context, iconDrawable).not() val isNotGrayscaleIcon = notifyInstance.isXmsf || isGrayscaleIcon(context, iconDrawable).not()
@@ -564,13 +563,13 @@ object SystemUIHooker : YukiBaseHooker() {
* 从父类中得到 mRow 变量 - [ExpandableNotificationRowClass] * 从父类中得到 mRow 变量 - [ExpandableNotificationRowClass]
* 获取其中的得到通知方法 * 获取其中的得到通知方法
*/ */
val row = NotificationViewWrapperClass.clazz.field { val row = NotificationViewWrapperClass.toClassOrNull()?.field {
name = "mRow" name = "mRow"
}.get(this).self?.also { }?.get(this)?.any()?.also {
isExpanded = ExpandableNotificationRowClass.clazz.method { isExpanded = ExpandableNotificationRowClass.toClassOrNull()?.method {
name = "isExpanded" name = "isExpanded"
returnType = BooleanType returnType = BooleanType
}.get(it).boolean() }?.get(it)?.boolean() ?: false
} }
return Pair(isExpanded, row) return Pair(isExpanded, row)
} }
@@ -580,15 +579,15 @@ object SystemUIHooker : YukiBaseHooker() {
* @return [StatusBarNotification] or null * @return [StatusBarNotification] or null
*/ */
private fun Any?.getSbn() = private fun Any?.getSbn() =
ExpandableNotificationRowClass.clazz ExpandableNotificationRowClass.toClassOrNull()
.method { name = "getEntry" } ?.method { name = "getEntry" }
.get(this).call()?.let { ?.get(this)?.call()?.let {
it.javaClass.method { it.javaClass.method {
name = "getSbn" name = "getSbn"
}.ignoredError().get(it).invoke<StatusBarNotification>() }.ignored().get(it).invoke<StatusBarNotification>()
} ?: ExpandableNotificationRowClass.clazz } ?: ExpandableNotificationRowClass.toClassOrNull()
.method { name = "getStatusBarNotification" } ?.method { name = "getStatusBarNotification" }
.get(this).invoke<StatusBarNotification>() ?.get(this)?.invoke<StatusBarNotification>()
/** /**
* 根据当前 [ImageView] 的父布局克隆一个新的 [ImageView] * 根据当前 [ImageView] 的父布局克隆一个新的 [ImageView]
@@ -614,8 +613,8 @@ object SystemUIHooker : YukiBaseHooker() {
} ?: initiate(this) } ?: initiate(this)
} }
/** 注册 */ /** 注册生命周期 */
private fun register() { private fun registerLifecycle() {
/** 解锁后重新刷新状态栏图标防止系统重新设置它 */ /** 解锁后重新刷新状态栏图标防止系统重新设置它 */
onAppLifecycle { registerReceiver(Intent.ACTION_USER_PRESENT) { _, _ -> if (isUsingCachingMethod) refreshStatusBarIcons() } } onAppLifecycle { registerReceiver(Intent.ACTION_USER_PRESENT) { _, _ -> if (isUsingCachingMethod) refreshStatusBarIcons() } }
/** 刷新图标缓存 */ /** 刷新图标缓存 */
@@ -653,8 +652,8 @@ object SystemUIHooker : YukiBaseHooker() {
} }
override fun onHook() { override fun onHook() {
/** 注册 */ /** 注册生命周期 */
register() registerLifecycle()
/** 缓存图标数据 */ /** 缓存图标数据 */
cachingIconDatas() cachingIconDatas()
/** 注入 MIUI 自己增加的一个工具类 */ /** 注入 MIUI 自己增加的一个工具类 */
@@ -714,8 +713,8 @@ object SystemUIHooker : YukiBaseHooker() {
* MIUI 12 进行单独判断 * MIUI 12 进行单独判断
*/ */
field { name = "mCurrentSetColor" }.get(instance).int().also { color -> field { name = "mCurrentSetColor" }.get(instance).int().also { color ->
alpha = if (color.isWhite) 0.95f else 0.8f alpha = if (color.isWhiteColor) 0.95f else 0.8f
setColorFilter(if (color.isWhite) color else Color.BLACK) setColorFilter(if (color.isWhiteColor) color else Color.BLACK)
} }
} }
} }
@@ -741,7 +740,7 @@ object SystemUIHooker : YukiBaseHooker() {
/** 注入通知控制器实例 */ /** 注入通知控制器实例 */
StatusBarNotificationPresenterClass.hook { StatusBarNotificationPresenterClass.hook {
injectMember { injectMember {
allConstructors() allMembers(MembersType.CONSTRUCTOR)
afterHook { notificationPresenter = instance } afterHook { notificationPresenter = instance }
} }
} }
@@ -768,7 +767,7 @@ object SystemUIHooker : YukiBaseHooker() {
.get(instance).set(prefs.get(DataConst.HOOK_STATUS_ICON_COUNT) .get(instance).set(prefs.get(DataConst.HOOK_STATUS_ICON_COUNT)
.let { if (it in 0..100) it else 5 }) .let { if (it in 0..100) it else 5 })
} }
}.by { NotificationIconContainerClass.clazz.hasField { name = "MAX_STATIC_ICONS" } } }.by { NotificationIconContainerClass.toClassOrNull()?.hasField { name = "MAX_STATIC_ICONS" } ?: false }
/** 旧版方法 - 新版不存在 */ /** 旧版方法 - 新版不存在 */
injectMember { injectMember {
method { method {
@@ -798,9 +797,8 @@ object SystemUIHooker : YukiBaseHooker() {
if (isNotHasAbsoluteMiuiStyle && isShowMiuiStyle) return@afterHook if (isNotHasAbsoluteMiuiStyle && isShowMiuiStyle) return@afterHook
/** 获取小图标 */ /** 获取小图标 */
val iconImageView = val iconImageView = NotificationHeaderViewWrapperClass.toClassOrNull()
NotificationHeaderViewWrapperClass.clazz ?.field { name = "mIcon" }?.get(instance)?.cast<ImageView>() ?: return@afterHook
.field { name = "mIcon" }.get(instance).cast<ImageView>() ?: return@afterHook
/** 获取 [ExpandableNotificationRowClass] */ /** 获取 [ExpandableNotificationRowClass] */
val rowPair = instance.getRowPair() val rowPair = instance.getRowPair()
@@ -848,11 +846,10 @@ object SystemUIHooker : YukiBaseHooker() {
param(BooleanType) param(BooleanType)
} }
afterHook { afterHook {
val expandedNf = NotificationChildrenContainerClass.clazz.field {
name = "mContainingNotification"
}.get(instance).self.getSbn()
field { name = "mAppIcon" }.get(instance).cast<ImageView>()?.apply { field { name = "mAppIcon" }.get(instance).cast<ImageView>()?.apply {
compatNotifyIcon(context, expandedNf, iconImageView = this, isUseAndroid12Style = true) compatNotifyIcon(context, NotificationChildrenContainerClass.toClassOrNull()?.field {
name = "mContainingNotification"
}?.get(instance)?.any()?.getSbn(), iconImageView = this, isUseAndroid12Style = true)
} }
} }
} }
@@ -892,18 +889,16 @@ object SystemUIHooker : YukiBaseHooker() {
it.getBooleanExtra(Intent.EXTRA_REPLACING, false) it.getBooleanExtra(Intent.EXTRA_REPLACING, false)
) return@also ) return@also
when (it.action) { when (it.action) {
Intent.ACTION_PACKAGE_ADDED -> Intent.ACTION_PACKAGE_ADDED -> it.data?.schemeSpecificPart?.also { newPkgName ->
it.data?.schemeSpecificPart?.also { newPkgName -> if (iconDatas.takeIf { e -> e.isNotEmpty() }
if (iconDatas.takeIf { e -> e.isNotEmpty() } ?.filter { e -> e.packageName == newPkgName }
?.filter { e -> e.packageName == newPkgName } .isNullOrEmpty()
.isNullOrEmpty() ) IconAdaptationTool.pushNewAppSupportNotify(args().first().cast()!!, newPkgName)
) IconAdaptationTool.pushNewAppSupportNotify(args().first().cast()!!, newPkgName) }
} Intent.ACTION_PACKAGE_REMOVED -> IconAdaptationTool.removeNewAppSupportNotify(
Intent.ACTION_PACKAGE_REMOVED -> context = args().first().cast()!!,
IconAdaptationTool.removeNewAppSupportNotify( packageName = it.data?.schemeSpecificPart ?: ""
context = args().first().cast()!!, )
packageName = it.data?.schemeSpecificPart ?: ""
)
} }
} }
} }

View File

@@ -20,7 +20,7 @@
* *
* This file is Created by fankes on 2022/1/30. * This file is Created by fankes on 2022/1/30.
*/ */
@file:Suppress("SetTextI18n", "InflateParams", "DEPRECATION") @file:Suppress("SetTextI18n", "InflateParams")
package com.fankes.miui.notify.ui.activity package com.fankes.miui.notify.ui.activity
@@ -67,7 +67,7 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
return return
} }
/** 返回按钮点击事件 */ /** 返回按钮点击事件 */
binding.titleBackIcon.setOnClickListener { onBackPressed() } binding.titleBackIcon.setOnClickListener { callOnBackPressed() }
/** 刷新适配器结果相关 */ /** 刷新适配器结果相关 */
refreshAdapterResult() refreshAdapterResult()
/** 设置上下按钮点击事件 */ /** 设置上下按钮点击事件 */
@@ -117,7 +117,7 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
onBindViews<AdapterConfigBinding> { binding, position -> onBindViews<AdapterConfigBinding> { binding, position ->
iconDatas[position].also { bean -> iconDatas[position].also { bean ->
binding.adpAppIcon.setImageBitmap(bean.iconBitmap) binding.adpAppIcon.setImageBitmap(bean.iconBitmap)
(if (bean.iconColor != 0) bean.iconColor else resources.getColor(R.color.colorTextGray)).also { color -> (if (bean.iconColor != 0) bean.iconColor else resources.colorOf(R.color.colorTextGray)).also { color ->
binding.adpAppIcon.setColorFilter(color) binding.adpAppIcon.setColorFilter(color)
binding.adpAppName.setTextColor(color) binding.adpAppName.setTextColor(color)
} }
@@ -203,6 +203,20 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
removeExtra("isNewAppSupport") removeExtra("isNewAppSupport")
removeExtra("isShowUpdDialog") removeExtra("isShowUpdDialog")
} }
/** 设置返回监听事件 */
addOnBackPressedEvent {
if (MainActivity.isActivityLive.not())
showDialog {
title = "提示"
msg = "要返回模块主页吗?"
confirmButton {
releaseEventAndBack()
navigate<MainActivity>()
}
cancelButton { releaseEventAndBack() }
}
else releaseEventAndBack()
}
} }
/** 开始手动同步 */ /** 开始手动同步 */
@@ -239,18 +253,4 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
else iconAllDatas.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())
} }
override fun onBackPressed() {
if (MainActivity.isActivityLive.not())
showDialog {
title = "提示"
msg = "要返回模块主页吗?"
confirmButton {
super.onBackPressed()
navigate<MainActivity>()
}
cancelButton { super.onBackPressed() }
}
else super.onBackPressed()
}
} }

View File

@@ -31,9 +31,9 @@ import androidx.core.view.WindowCompat
import androidx.viewbinding.ViewBinding import androidx.viewbinding.ViewBinding
import com.fankes.miui.notify.R import com.fankes.miui.notify.R
import com.fankes.miui.notify.utils.factory.isNotSystemInDarkMode import com.fankes.miui.notify.utils.factory.isNotSystemInDarkMode
import com.highcapable.yukihookapi.hook.factory.current
import com.highcapable.yukihookapi.hook.factory.method import com.highcapable.yukihookapi.hook.factory.method
import com.highcapable.yukihookapi.hook.type.android.LayoutInflaterClass import com.highcapable.yukihookapi.hook.type.android.LayoutInflaterClass
import java.lang.reflect.ParameterizedType
abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() { abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
@@ -49,15 +49,11 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
isMainThreadRunning = true isMainThreadRunning = true
javaClass.genericSuperclass.also { type -> binding = current().generic()?.argument()?.method {
if (type is ParameterizedType) { name = "inflate"
binding = (type.actualTypeArguments[0] as Class<VB>).method { param(LayoutInflaterClass)
name = "inflate" }?.get()?.invoke<VB>(layoutInflater) ?: error("binding failed")
param(LayoutInflaterClass) setContentView(binding.root)
}.get().invoke<VB>(layoutInflater) ?: error("binding failed")
setContentView(binding.root)
} else error("binding but got wrong type")
}
/** 隐藏系统的标题栏 */ /** 隐藏系统的标题栏 */
supportActionBar?.hide() supportActionBar?.hide()
/** 初始化沉浸状态栏 */ /** 初始化沉浸状态栏 */

View File

@@ -0,0 +1,66 @@
/*
* 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/10/6.
*/
package com.fankes.miui.notify.utils.factory
import androidx.activity.OnBackPressedCallback
import androidx.appcompat.app.AppCompatActivity
/** 已添加的返回监听事件 */
private val onBackPressedCallbacks = HashMap<AppCompatActivity, OnBackPressedCallback>()
/**
* 手动调用返回事件
* @param ignored 是否忽略现有返回监听事件立即返回 - 否则将执行返回事件 - 默认否
*/
fun AppCompatActivity.callOnBackPressed(ignored: Boolean = false) {
if (isDestroyed) return
onBackPressedCallbacks[this]?.isEnabled = ignored.not()
onBackPressedDispatcher.onBackPressed()
}
/**
* 添加返回监听事件
* @param callback 回调事件
*/
fun AppCompatActivity.addOnBackPressedEvent(callback: OnBackPressedEvent.() -> Unit) {
object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
OnBackPressedEvent(this@addOnBackPressedEvent).apply(callback)
}
}.also { result ->
onBackPressedCallbacks.computeIfAbsent(this) {
onBackPressedDispatcher.addCallback(result)
result
}
}
}
/**
* 返回监听事件实现类
* @param instance 当前实例
*/
class OnBackPressedEvent(private val instance: AppCompatActivity) {
/** 立即释放返回事件并调用返回功能 */
fun releaseEventAndBack() = instance.callOnBackPressed(ignored = true)
}

View File

@@ -20,7 +20,7 @@
* *
* This file is Created by fankes on 2022/1/7. * This file is Created by fankes on 2022/1/7.
*/ */
@file:Suppress("DEPRECATION", "PrivateApi", "unused", "ObsoleteSdkInt") @file:Suppress("unused", "ObsoleteSdkInt")
package com.fankes.miui.notify.utils.factory package com.fankes.miui.notify.utils.factory
@@ -34,8 +34,9 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo
import android.content.pm.PackageInfo import android.content.pm.PackageInfo
import android.content.pm.PackageManager import android.content.pm.PackageManager.PackageInfoFlags
import android.content.res.Configuration import android.content.res.Configuration
import android.content.res.Resources
import android.graphics.* import android.graphics.*
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.net.ConnectivityManager import android.net.ConnectivityManager
@@ -45,12 +46,16 @@ import android.os.Handler
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.annotation.ColorRes
import androidx.annotation.DrawableRes
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import androidx.core.content.pm.PackageInfoCompat
import androidx.core.content.res.ResourcesCompat
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.hasClass import com.highcapable.yukihookapi.hook.factory.hasClass
import com.highcapable.yukihookapi.hook.factory.method import com.highcapable.yukihookapi.hook.factory.method
import com.highcapable.yukihookapi.hook.factory.toClassOrNull
import com.highcapable.yukihookapi.hook.type.java.StringType import com.highcapable.yukihookapi.hook.type.java.StringType
import com.highcapable.yukihookapi.hook.xposed.application.ModuleApplication.Companion.appContext import com.highcapable.yukihookapi.hook.xposed.application.ModuleApplication.Companion.appContext
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
@@ -58,7 +63,6 @@ import java.io.ByteArrayOutputStream
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
/** /**
* 系统深色模式是否开启 * 系统深色模式是否开启
* @return [Boolean] 是否开启 * @return [Boolean] 是否开启
@@ -83,6 +87,12 @@ val Context.isSystemInDarkMode get() = (resources.configuration.uiMode and Confi
*/ */
inline val Context.isNotSystemInDarkMode get() = !isSystemInDarkMode inline val Context.isNotSystemInDarkMode get() = !isSystemInDarkMode
/**
* 系统版本是否高于或等于 Android 13
* @return [Boolean] 是否符合条件
*/
inline val isUpperOfAndroidT get() = Build.VERSION.SDK_INT > Build.VERSION_CODES.S
/** /**
* 系统版本是否高于或等于 Android 12 * 系统版本是否高于或等于 Android 12
* @return [Boolean] 是否符合条件 * @return [Boolean] 是否符合条件
@@ -105,7 +115,7 @@ inline val isLowerAndroidR get() = Build.VERSION.SDK_INT < Build.VERSION_CODES.R
* 当前设备是否是 MIUI 定制 Android 系统 * 当前设备是否是 MIUI 定制 Android 系统
* @return [Boolean] 是否符合条件 * @return [Boolean] 是否符合条件
*/ */
val isMIUI by lazy { ("android.miui.R").hasClass } val isMIUI by lazy { "android.miui.R".hasClass() }
/** /**
* 当前设备是否不是 MIUI 定制 Android 系统 * 当前设备是否不是 MIUI 定制 Android 系统
@@ -199,59 +209,79 @@ val miuiFullVersion
} else "不是 MIUI 系统" } else "不是 MIUI 系统"
/** /**
* 得到安装包信息 * 获取 [Drawable]
* @return [PackageInfo] * @param resId 属性资源 ID
* @return [Drawable]
*/ */
val Context.packageInfo get() = packageManager?.getPackageInfo(packageName, 0) ?: PackageInfo() fun Resources.drawableOf(@DrawableRes resId: Int) = ResourcesCompat.getDrawable(this, resId, null) ?: error("Invalid resources")
/** /**
* 判断应用是否安装 * 获取颜色
* @return [Boolean] * @param resId 属性资源 ID
*/
val String.isInstall
get() = safeOfFalse {
appContext.packageManager.getPackageInfo(
this,
PackageManager.GET_UNINSTALLED_PACKAGES
)
true
}
/**
* 得到版本信息
* @return [String]
*/
val Context.versionName get() = packageInfo.versionName ?: ""
/**
* 得到版本号
* @return [Int] * @return [Int]
*/ */
val Context.versionCode get() = packageInfo.versionCode fun Resources.colorOf(@ColorRes resId: Int) = ResourcesCompat.getColor(this, resId, null)
/**
* 得到 APP 安装包信息 (兼容)
* @param packageName APP 包名
* @param flag [PackageInfoFlags]
* @return [PackageInfo] or null
*/
private fun Context.getPackageInfoCompat(packageName: String, flag: Number = 0) = runCatching {
@Suppress("DEPRECATION")
if (Build.VERSION.SDK_INT >= 33)
packageManager?.getPackageInfo(packageName, PackageInfoFlags.of(flag.toLong()))
else packageManager?.getPackageInfo(packageName, flag.toInt())
}.getOrNull()
/**
* 得到 APP 版本号 (兼容 [PackageInfo.getLongVersionCode])
* @return [Int]
*/
private val PackageInfo.versionCodeCompat get() = PackageInfoCompat.getLongVersionCode(this)
/**
* 判断 APP 是否安装
* @param packageName APP 包名
* @return [Boolean]
*/
fun Context.isInstall(packageName: String) = getPackageInfoCompat(packageName)?.let { true } ?: false
/**
* 得到 APP 版本信息
* @return [String]
*/
val Context.appVersionName get() = getPackageInfoCompat(packageName)?.versionName ?: ""
/**
* 得到 APP 版本号
* @return [Int]
*/
val Context.appVersionCode get() = getPackageInfoCompat(packageName)?.versionCodeCompat
/** /**
* 得到 APP 名称 * 得到 APP 名称
* @param name APP 包名 * @param packageName APP 包名 - 默认为当前 APP
* @return [String] * @return [String]
*/ */
fun Context.findAppName(name: String) = fun Context.appNameOf(packageName: String = getPackageName()) =
safeOfNothing { packageManager?.getPackageInfo(name, 0)?.applicationInfo?.loadLabel(packageManager).toString() } getPackageInfoCompat(packageName)?.applicationInfo?.loadLabel(packageManager)?.toString() ?: ""
/** /**
* 得到 APP 图标 * 得到 APP 图标
* @param name APP 包名 * @param packageName APP 包名 - 默认为当前 APP
* @return [Drawable] or null * @return [Drawable] or null
*/ */
fun Context.findAppIcon(name: String) = fun Context.appIconOf(packageName: String = getPackageName()) = getPackageInfoCompat(packageName)?.applicationInfo?.loadIcon(packageManager)
safeOfNull { packageManager?.getPackageInfo(name, 0)?.applicationInfo?.loadIcon(packageManager) }
/** /**
* 获取 APP 是否为 DEBUG 版本 * 获取 APP 是否为 DEBUG 版本
* @param name APP 包名 * @param packageName APP 包名
* @return [Boolean] * @return [Boolean]
*/ */
fun Context.isAppDebuggable(name: String) = fun Context.isAppDebuggable(packageName: String) =
safeOfFalse { (packageManager?.getPackageInfo(name, 0)?.applicationInfo?.flags?.and(ApplicationInfo.FLAG_DEBUGGABLE) ?: 0) != 0 } safeOfFalse { (getPackageInfoCompat(packageName)?.applicationInfo?.flags?.and(ApplicationInfo.FLAG_DEBUGGABLE) ?: 0) != 0 }
/** /**
* 对数值自动补零 * 对数值自动补零
@@ -291,8 +321,11 @@ val isNotNoificationEnabled get() = !NotificationManagerCompat.from(appContext).
* 网络连接是否正常 * 网络连接是否正常
* @return [Boolean] 网络是否连接 * @return [Boolean] 网络是否连接
*/ */
val isNetWorkSuccess val Context.isNetWorkSuccess
get() = safeOfFalse { appContext.getSystemService<ConnectivityManager>()?.activeNetworkInfo != null } get() = safeOfFalse {
@Suppress("DEPRECATION")
getSystemService<ConnectivityManager>()?.activeNetworkInfo != null
}
/** /**
* dp 转换为 pxInt * dp 转换为 pxInt
@@ -313,7 +346,9 @@ fun Number.dpFloat(context: Context) = toFloat() * context.resources.displayMetr
* @return [Int] Android < 12 返回 [wallpaperColor] * @return [Int] Android < 12 返回 [wallpaperColor]
*/ */
val Context.systemAccentColor val Context.systemAccentColor
get() = safeOf(wallpaperColor) { if (isUpperOfAndroidS) resources.getColor(android.R.color.system_accent1_600) else wallpaperColor } get() = safeOf(wallpaperColor) {
if (isUpperOfAndroidS) resources.colorOf(android.R.color.system_accent1_600) else wallpaperColor
}
/** /**
* 获取系统壁纸颜色 * 获取系统壁纸颜色
@@ -328,7 +363,7 @@ val Context.wallpaperColor
* 获取较浅的颜色 * 获取较浅的颜色
* @return [Int] * @return [Int]
*/ */
val Int.brighter: Int val Int.brighterColor: Int
get() { get() {
val hsv = FloatArray(3) val hsv = FloatArray(3)
Color.colorToHSV(this, hsv) Color.colorToHSV(this, hsv)
@@ -341,7 +376,7 @@ val Int.brighter: Int
* 是否为白色 * 是否为白色
* @return [Boolean] * @return [Boolean]
*/ */
val Int.isWhite val Int.isWhiteColor
get() = safeOfTrue { get() = safeOfTrue {
val r = this and 0xff0000 shr 16 val r = this and 0xff0000 shr 16
val g = this and 0x00ff00 shr 8 val g = this and 0x00ff00 shr 8
@@ -411,10 +446,10 @@ fun Bitmap.round(radius: Float): Bitmap = safeOf(default = this) {
* @return [String] * @return [String]
*/ */
fun findPropString(key: String, default: String = "") = safeOf(default) { fun findPropString(key: String, default: String = "") = safeOf(default) {
(classOf(name = "android.os.SystemProperties").method { "android.os.SystemProperties".toClassOrNull()?.method {
name = "get" name = "get"
param(StringType, StringType) param(StringType, StringType)
}.get().invoke(key, default)) ?: default }?.get()?.invoke(key, default) ?: default
} }
/** /**
@@ -490,7 +525,7 @@ fun Context.openBrowser(url: String, packageName: String = "") = runCatching {
* @param packageName 包名 * @param packageName 包名
*/ */
fun Context.openSelfSetting(packageName: String = appContext.packageName) = runCatching { fun Context.openSelfSetting(packageName: String = appContext.packageName) = runCatching {
if (packageName.isInstall) if (isInstall(packageName))
startActivity(Intent().apply { startActivity(Intent().apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK flags = Intent.FLAG_ACTIVITY_NEW_TASK
action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
@@ -535,4 +570,7 @@ fun Long.stampToDate(format: String = "yyyy-MM-dd HH:mm:ss") =
* @param ms 毫秒 - 默认150 * @param ms 毫秒 - 默认150
* @param it 方法体 * @param it 方法体
*/ */
fun Any?.delayedRun(ms: Long = 150, it: () -> Unit) = runInSafe { Handler().postDelayed({ it() }, ms) } fun Any?.delayedRun(ms: Long = 150, it: () -> Unit) = runInSafe {
@Suppress("DEPRECATION")
Handler().postDelayed({ it() }, ms)
}

View File

@@ -91,7 +91,7 @@ object GithubReleaseTool {
* @param callback 已连接回调 * @param callback 已连接回调
*/ */
private fun checkingInternetConnect(context: Context, callback: () -> Unit) = runInSafe { private fun checkingInternetConnect(context: Context, callback: () -> Unit) = runInSafe {
if (isNetWorkSuccess) if (context.isNetWorkSuccess)
OkHttpClient().newBuilder().build().newCall( OkHttpClient().newBuilder().build().newCall(
Request.Builder() Request.Builder()
.url("https://www.baidu.com") .url("https://www.baidu.com")

View File

@@ -129,12 +129,12 @@ object IconAdaptationTool {
) )
notify(packageName.hashCode(), Notification.Builder(context, NOTIFY_CHANNEL).apply { notify(packageName.hashCode(), Notification.Builder(context, NOTIFY_CHANNEL).apply {
setShowWhen(true) setShowWhen(true)
setContentTitle("您已安装 ${context.findAppName(packageName)}") setContentTitle("您已安装 ${context.appNameOf(packageName)}")
setContentText("尚未适配此应用,点按打开在线规则。") setContentText("尚未适配此应用,点按打开在线规则。")
setColor(0xFF2993F0.toInt()) setColor(0xFF2993F0.toInt())
setAutoCancel(true) setAutoCancel(true)
setSmallIcon(Icon.createWithBitmap(smallIcon)) setSmallIcon(Icon.createWithBitmap(smallIcon))
setLargeIcon(context.findAppIcon(packageName)?.toBitmap()) setLargeIcon(context.appIconOf(packageName)?.toBitmap())
setContentIntent( setContentIntent(
PendingIntent.getActivity( PendingIntent.getActivity(
context, packageName.hashCode(), context, packageName.hashCode(),
@@ -146,7 +146,7 @@ object IconAdaptationTool {
flags = Intent.FLAG_ACTIVITY_NEW_TASK flags = Intent.FLAG_ACTIVITY_NEW_TASK
}.apply { }.apply {
putExtra("isNewAppSupport", true) putExtra("isNewAppSupport", true)
putExtra("appName", context.findAppName(packageName)) putExtra("appName", context.appNameOf(packageName))
putExtra("pkgName", packageName) putExtra("pkgName", packageName)
}, if (Build.VERSION.SDK_INT < 31) PendingIntent.FLAG_UPDATE_CURRENT else PendingIntent.FLAG_IMMUTABLE }, if (Build.VERSION.SDK_INT < 31) PendingIntent.FLAG_UPDATE_CURRENT else PendingIntent.FLAG_IMMUTABLE
) )