From 7c3d3d1bda5af0b6830c93f77421bbeafc3e4327 Mon Sep 17 00:00:00 2001 From: fankesyooni Date: Thu, 6 Oct 2022 03:18:53 +0800 Subject: [PATCH] Modify merge YukiHookAPI new usage and compatible with API 33 --- .../com/fankes/miui/notify/hook/HookEntry.kt | 2 +- .../miui/notify/hook/entity/SystemUIHooker.kt | 109 +++++++-------- .../notify/ui/activity/ConfigureActivity.kt | 34 ++--- .../notify/ui/activity/base/BaseActivity.kt | 16 +-- .../utils/factory/BackPressedEventFactory.kt | 66 +++++++++ .../notify/utils/factory/FunctionFactory.kt | 132 +++++++++++------- .../notify/utils/tool/GithubReleaseTool.kt | 2 +- .../notify/utils/tool/IconAdaptationTool.kt | 6 +- 8 files changed, 231 insertions(+), 136 deletions(-) create mode 100644 app/src/main/java/com/fankes/miui/notify/utils/factory/BackPressedEventFactory.kt diff --git a/app/src/main/java/com/fankes/miui/notify/hook/HookEntry.kt b/app/src/main/java/com/fankes/miui/notify/hook/HookEntry.kt index 65f4657..741b0d6 100644 --- a/app/src/main/java/com/fankes/miui/notify/hook/HookEntry.kt +++ b/app/src/main/java/com/fankes/miui/notify/hook/HookEntry.kt @@ -39,7 +39,7 @@ import com.highcapable.yukihookapi.hook.xposed.proxy.IYukiHookXposedInit class HookEntry : IYukiHookXposedInit { override fun onInit() = configs { - debugTag = "MIUINativeNotifyIcon" + debugLog { tag = "MIUINativeNotifyIcon" } isDebug = false } diff --git a/app/src/main/java/com/fankes/miui/notify/hook/entity/SystemUIHooker.kt b/app/src/main/java/com/fankes/miui/notify/hook/entity/SystemUIHooker.kt index 2087d0b..2f09a3b 100644 --- a/app/src/main/java/com/fankes/miui/notify/hook/entity/SystemUIHooker.kt +++ b/app/src/main/java/com/fankes/miui/notify/hook/entity/SystemUIHooker.kt @@ -179,7 +179,7 @@ object SystemUIHooker : YukiBaseHooker() { */ private fun isGrayscaleIcon(context: Context, drawable: Drawable) = if (prefs.get(DataConst.ENABLE_COLOR_ICON_COMPAT).not()) safeOfFalse { - ContrastColorUtilClass.clazz.let { + ContrastColorUtilClass.toClass().let { it.method { name = "isGrayscaleIcon" param(DrawableClass) @@ -197,7 +197,7 @@ object SystemUIHooker : YukiBaseHooker() { * @return [Boolean] */ 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) { /** 给 MIPUSH 设置 APP 自己的图标 */ if (isXmsf && nfPkgName.isNotBlank()) - context.findAppIcon(xmsfPkgName) ?: iconDrawable + context.appIconOf(xmsfPkgName) ?: iconDrawable else iconDrawable } @@ -237,7 +237,7 @@ object SystemUIHooker : YukiBaseHooker() { isGrayscale: Boolean ) { 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] " + "grayscale [$isGrayscale] " + "xmsf [${expandedNf?.isXmsf}]" @@ -282,22 +282,21 @@ object SystemUIHooker : YukiBaseHooker() { * 是否为 MIUI 样式通知栏 - 旧版 - 新版一律返回 false * @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 通知栏样式 * @return [Boolean] */ - private val isNotHasAbsoluteMiuiStyle get() = MiuiNotificationViewWrapperClass.hasClass.not() + private val isNotHasAbsoluteMiuiStyle get() = MiuiNotificationViewWrapperClass.hasClass().not() /** * 获取全局上下文 * @return [Context] or null */ private val globalContext - get() = safeOfNull { - SystemUIApplicationClass.clazz.method { name = "getContext" }.ignoredError().get().invoke() ?: appContext - } + get() = SystemUIApplicationClass.toClassOrNull()?.method { name = "getContext" }?.ignored()?.get()?.invoke() ?: appContext /** * 注册主题壁纸改变颜色监听 @@ -314,7 +313,7 @@ object SystemUIHooker : YukiBaseHooker() { /** 刷新状态栏小图标 */ private fun refreshStatusBarIcons() = runInSafe { - StatusBarIconViewClass.clazz.field { name = "mNotification" }.also { result -> + StatusBarIconViewClass.toClassOrNull()?.field { name = "mNotification" }?.also { result -> notificationIconContainer?.children?.forEach { /** 得到通知实例 */ val nf = result.get(it).cast() ?: return @@ -328,12 +327,10 @@ object SystemUIHooker : YukiBaseHooker() { /** 刷新通知小图标 */ private fun refreshNotificationIcons() = runInSafe { - notificationPresenter?.current { - method { - name = "updateNotificationsOnDensityOrFontScaleChanged" - emptyParam() - }.call() - } + notificationPresenter?.current()?.method { + name = "updateNotificationsOnDensityOrFontScaleChanged" + emptyParam() + }?.call() } /** @@ -460,6 +457,7 @@ object SystemUIHooker : YukiBaseHooker() { /** 获取通知小图标 */ val iconDrawable = notifyInstance.notification.smallIcon.loadDrawable(context) + ?: return@let loggerW(msg = "compatNotifyIcon got null smallIcon") /** 判断图标风格 */ val isGrayscaleIcon = notifyInstance.isXmsf.not() && isGrayscaleIcon(context, iconDrawable) @@ -479,7 +477,7 @@ object SystemUIHooker : YukiBaseHooker() { /** 处理自定义通知图标优化 */ when { 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 { /** 设置不要裁切到边界 */ clipToOutline = false @@ -492,7 +490,7 @@ object SystemUIHooker : YukiBaseHooker() { background = DrawableBuilder() .rectangle() .cornerRadius(iconCorner.dp(context)) - .solidColor(if (context.isSystemInDarkMode) customIconColor.brighter else customIconColor) + .solidColor(if (context.isSystemInDarkMode) customIconColor.brighterColor else customIconColor) .build() /** 设置原生的背景边距 */ if (isUseAndroid12Style) setPadding(4.dp(context), 4.dp(context), 4.dp(context), 4.dp(context)) @@ -512,7 +510,7 @@ object SystemUIHooker : YukiBaseHooker() { background = DrawableBuilder() .rectangle() .cornerRadius(iconCorner.dp(context)) - .solidColor(if (context.isSystemInDarkMode) it.brighter else it) + .solidColor(if (context.isSystemInDarkMode) it.brighterColor else it) .build() } /** 设置原生的背景边距 */ @@ -536,6 +534,7 @@ object SystemUIHooker : YukiBaseHooker() { expandedNf?.let { notifyInstance -> /** 获取通知小图标 */ val iconDrawable = notifyInstance.notification.smallIcon.loadDrawable(context) + ?: return loggerW(msg = "hasIgnoreStatusBarIconColor got null smallIcon").let { true } /** 判断是否不是灰度图标 */ val isNotGrayscaleIcon = notifyInstance.isXmsf || isGrayscaleIcon(context, iconDrawable).not() @@ -564,13 +563,13 @@ object SystemUIHooker : YukiBaseHooker() { * 从父类中得到 mRow 变量 - [ExpandableNotificationRowClass] * 获取其中的得到通知方法 */ - val row = NotificationViewWrapperClass.clazz.field { + val row = NotificationViewWrapperClass.toClassOrNull()?.field { name = "mRow" - }.get(this).self?.also { - isExpanded = ExpandableNotificationRowClass.clazz.method { + }?.get(this)?.any()?.also { + isExpanded = ExpandableNotificationRowClass.toClassOrNull()?.method { name = "isExpanded" returnType = BooleanType - }.get(it).boolean() + }?.get(it)?.boolean() ?: false } return Pair(isExpanded, row) } @@ -580,15 +579,15 @@ object SystemUIHooker : YukiBaseHooker() { * @return [StatusBarNotification] or null */ private fun Any?.getSbn() = - ExpandableNotificationRowClass.clazz - .method { name = "getEntry" } - .get(this).call()?.let { + ExpandableNotificationRowClass.toClassOrNull() + ?.method { name = "getEntry" } + ?.get(this)?.call()?.let { it.javaClass.method { name = "getSbn" - }.ignoredError().get(it).invoke() - } ?: ExpandableNotificationRowClass.clazz - .method { name = "getStatusBarNotification" } - .get(this).invoke() + }.ignored().get(it).invoke() + } ?: ExpandableNotificationRowClass.toClassOrNull() + ?.method { name = "getStatusBarNotification" } + ?.get(this)?.invoke() /** * 根据当前 [ImageView] 的父布局克隆一个新的 [ImageView] @@ -614,8 +613,8 @@ object SystemUIHooker : YukiBaseHooker() { } ?: initiate(this) } - /** 注册 */ - private fun register() { + /** 注册生命周期 */ + private fun registerLifecycle() { /** 解锁后重新刷新状态栏图标防止系统重新设置它 */ onAppLifecycle { registerReceiver(Intent.ACTION_USER_PRESENT) { _, _ -> if (isUsingCachingMethod) refreshStatusBarIcons() } } /** 刷新图标缓存 */ @@ -653,8 +652,8 @@ object SystemUIHooker : YukiBaseHooker() { } override fun onHook() { - /** 注册 */ - register() + /** 注册生命周期 */ + registerLifecycle() /** 缓存图标数据 */ cachingIconDatas() /** 注入 MIUI 自己增加的一个工具类 */ @@ -714,8 +713,8 @@ object SystemUIHooker : YukiBaseHooker() { * MIUI 12 进行单独判断 */ field { name = "mCurrentSetColor" }.get(instance).int().also { color -> - alpha = if (color.isWhite) 0.95f else 0.8f - setColorFilter(if (color.isWhite) color else Color.BLACK) + alpha = if (color.isWhiteColor) 0.95f else 0.8f + setColorFilter(if (color.isWhiteColor) color else Color.BLACK) } } } @@ -741,7 +740,7 @@ object SystemUIHooker : YukiBaseHooker() { /** 注入通知控制器实例 */ StatusBarNotificationPresenterClass.hook { injectMember { - allConstructors() + allMembers(MembersType.CONSTRUCTOR) afterHook { notificationPresenter = instance } } } @@ -768,7 +767,7 @@ object SystemUIHooker : YukiBaseHooker() { .get(instance).set(prefs.get(DataConst.HOOK_STATUS_ICON_COUNT) .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 { method { @@ -798,9 +797,8 @@ object SystemUIHooker : YukiBaseHooker() { if (isNotHasAbsoluteMiuiStyle && isShowMiuiStyle) return@afterHook /** 获取小图标 */ - val iconImageView = - NotificationHeaderViewWrapperClass.clazz - .field { name = "mIcon" }.get(instance).cast() ?: return@afterHook + val iconImageView = NotificationHeaderViewWrapperClass.toClassOrNull() + ?.field { name = "mIcon" }?.get(instance)?.cast() ?: return@afterHook /** 获取 [ExpandableNotificationRowClass] */ val rowPair = instance.getRowPair() @@ -848,11 +846,10 @@ object SystemUIHooker : YukiBaseHooker() { param(BooleanType) } afterHook { - val expandedNf = NotificationChildrenContainerClass.clazz.field { - name = "mContainingNotification" - }.get(instance).self.getSbn() field { name = "mAppIcon" }.get(instance).cast()?.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) ) return@also when (it.action) { - Intent.ACTION_PACKAGE_ADDED -> - it.data?.schemeSpecificPart?.also { newPkgName -> - if (iconDatas.takeIf { e -> e.isNotEmpty() } - ?.filter { e -> e.packageName == newPkgName } - .isNullOrEmpty() - ) IconAdaptationTool.pushNewAppSupportNotify(args().first().cast()!!, newPkgName) - } - Intent.ACTION_PACKAGE_REMOVED -> - IconAdaptationTool.removeNewAppSupportNotify( - context = args().first().cast()!!, - packageName = it.data?.schemeSpecificPart ?: "" - ) + Intent.ACTION_PACKAGE_ADDED -> it.data?.schemeSpecificPart?.also { newPkgName -> + if (iconDatas.takeIf { e -> e.isNotEmpty() } + ?.filter { e -> e.packageName == newPkgName } + .isNullOrEmpty() + ) IconAdaptationTool.pushNewAppSupportNotify(args().first().cast()!!, newPkgName) + } + Intent.ACTION_PACKAGE_REMOVED -> IconAdaptationTool.removeNewAppSupportNotify( + context = args().first().cast()!!, + packageName = it.data?.schemeSpecificPart ?: "" + ) } } } diff --git a/app/src/main/java/com/fankes/miui/notify/ui/activity/ConfigureActivity.kt b/app/src/main/java/com/fankes/miui/notify/ui/activity/ConfigureActivity.kt index 10d2d24..8b28d01 100644 --- a/app/src/main/java/com/fankes/miui/notify/ui/activity/ConfigureActivity.kt +++ b/app/src/main/java/com/fankes/miui/notify/ui/activity/ConfigureActivity.kt @@ -20,7 +20,7 @@ * * 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 @@ -67,7 +67,7 @@ class ConfigureActivity : BaseActivity() { return } /** 返回按钮点击事件 */ - binding.titleBackIcon.setOnClickListener { onBackPressed() } + binding.titleBackIcon.setOnClickListener { callOnBackPressed() } /** 刷新适配器结果相关 */ refreshAdapterResult() /** 设置上下按钮点击事件 */ @@ -117,7 +117,7 @@ class ConfigureActivity : BaseActivity() { onBindViews { binding, position -> iconDatas[position].also { bean -> 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.adpAppName.setTextColor(color) } @@ -203,6 +203,20 @@ class ConfigureActivity : BaseActivity() { removeExtra("isNewAppSupport") removeExtra("isShowUpdDialog") } + /** 设置返回监听事件 */ + addOnBackPressedEvent { + if (MainActivity.isActivityLive.not()) + showDialog { + title = "提示" + msg = "要返回模块主页吗?" + confirmButton { + releaseEventAndBack() + navigate() + } + cancelButton { releaseEventAndBack() } + } + else releaseEventAndBack() + } } /** 开始手动同步 */ @@ -239,18 +253,4 @@ class ConfigureActivity : BaseActivity() { else iconAllDatas.filter { 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() - } - cancelButton { super.onBackPressed() } - } - else super.onBackPressed() - } } \ No newline at end of file diff --git a/app/src/main/java/com/fankes/miui/notify/ui/activity/base/BaseActivity.kt b/app/src/main/java/com/fankes/miui/notify/ui/activity/base/BaseActivity.kt index d5833a4..9ec4da9 100644 --- a/app/src/main/java/com/fankes/miui/notify/ui/activity/base/BaseActivity.kt +++ b/app/src/main/java/com/fankes/miui/notify/ui/activity/base/BaseActivity.kt @@ -31,9 +31,9 @@ import androidx.core.view.WindowCompat import androidx.viewbinding.ViewBinding import com.fankes.miui.notify.R 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.type.android.LayoutInflaterClass -import java.lang.reflect.ParameterizedType abstract class BaseActivity : AppCompatActivity() { @@ -49,15 +49,11 @@ abstract class BaseActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) isMainThreadRunning = true - javaClass.genericSuperclass.also { type -> - if (type is ParameterizedType) { - binding = (type.actualTypeArguments[0] as Class).method { - name = "inflate" - param(LayoutInflaterClass) - }.get().invoke(layoutInflater) ?: error("binding failed") - setContentView(binding.root) - } else error("binding but got wrong type") - } + binding = current().generic()?.argument()?.method { + name = "inflate" + param(LayoutInflaterClass) + }?.get()?.invoke(layoutInflater) ?: error("binding failed") + setContentView(binding.root) /** 隐藏系统的标题栏 */ supportActionBar?.hide() /** 初始化沉浸状态栏 */ diff --git a/app/src/main/java/com/fankes/miui/notify/utils/factory/BackPressedEventFactory.kt b/app/src/main/java/com/fankes/miui/notify/utils/factory/BackPressedEventFactory.kt new file mode 100644 index 0000000..0a09116 --- /dev/null +++ b/app/src/main/java/com/fankes/miui/notify/utils/factory/BackPressedEventFactory.kt @@ -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. + *

+ * + * 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 + * + * + * 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() + +/** + * 手动调用返回事件 + * @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) +} \ No newline at end of file diff --git a/app/src/main/java/com/fankes/miui/notify/utils/factory/FunctionFactory.kt b/app/src/main/java/com/fankes/miui/notify/utils/factory/FunctionFactory.kt index 43fdec0..a0cbb40 100644 --- a/app/src/main/java/com/fankes/miui/notify/utils/factory/FunctionFactory.kt +++ b/app/src/main/java/com/fankes/miui/notify/utils/factory/FunctionFactory.kt @@ -20,7 +20,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 @@ -34,8 +34,9 @@ import android.content.Context import android.content.Intent import android.content.pm.ApplicationInfo 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.Resources import android.graphics.* import android.graphics.drawable.Drawable import android.net.ConnectivityManager @@ -45,12 +46,16 @@ import android.os.Handler import android.provider.Settings import android.util.Base64 import android.widget.Toast +import androidx.annotation.ColorRes +import androidx.annotation.DrawableRes import androidx.core.app.NotificationManagerCompat 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.highcapable.yukihookapi.hook.factory.classOf import com.highcapable.yukihookapi.hook.factory.hasClass 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.xposed.application.ModuleApplication.Companion.appContext import com.topjohnwu.superuser.Shell @@ -58,7 +63,6 @@ import java.io.ByteArrayOutputStream import java.text.SimpleDateFormat import java.util.* - /** * 系统深色模式是否开启 * @return [Boolean] 是否开启 @@ -83,6 +87,12 @@ val Context.isSystemInDarkMode get() = (resources.configuration.uiMode and Confi */ inline val Context.isNotSystemInDarkMode get() = !isSystemInDarkMode +/** + * 系统版本是否高于或等于 Android 13 + * @return [Boolean] 是否符合条件 + */ +inline val isUpperOfAndroidT get() = Build.VERSION.SDK_INT > Build.VERSION_CODES.S + /** * 系统版本是否高于或等于 Android 12 * @return [Boolean] 是否符合条件 @@ -105,7 +115,7 @@ inline val isLowerAndroidR get() = Build.VERSION.SDK_INT < Build.VERSION_CODES.R * 当前设备是否是 MIUI 定制 Android 系统 * @return [Boolean] 是否符合条件 */ -val isMIUI by lazy { ("android.miui.R").hasClass } +val isMIUI by lazy { "android.miui.R".hasClass() } /** * 当前设备是否不是 MIUI 定制 Android 系统 @@ -199,59 +209,79 @@ val miuiFullVersion } else "不是 MIUI 系统" /** - * 得到安装包信息 - * @return [PackageInfo] + * 获取 [Drawable] + * @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] - */ -val String.isInstall - get() = safeOfFalse { - appContext.packageManager.getPackageInfo( - this, - PackageManager.GET_UNINSTALLED_PACKAGES - ) - true - } - -/** - * 得到版本信息 - * @return [String] - */ -val Context.versionName get() = packageInfo.versionName ?: "" - -/** - * 得到版本号 + * 获取颜色 + * @param resId 属性资源 ID * @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 名称 - * @param name APP 包名 + * @param packageName APP 包名 - 默认为当前 APP * @return [String] */ -fun Context.findAppName(name: String) = - safeOfNothing { packageManager?.getPackageInfo(name, 0)?.applicationInfo?.loadLabel(packageManager).toString() } +fun Context.appNameOf(packageName: String = getPackageName()) = + getPackageInfoCompat(packageName)?.applicationInfo?.loadLabel(packageManager)?.toString() ?: "" /** * 得到 APP 图标 - * @param name APP 包名 + * @param packageName APP 包名 - 默认为当前 APP * @return [Drawable] or null */ -fun Context.findAppIcon(name: String) = - safeOfNull { packageManager?.getPackageInfo(name, 0)?.applicationInfo?.loadIcon(packageManager) } +fun Context.appIconOf(packageName: String = getPackageName()) = getPackageInfoCompat(packageName)?.applicationInfo?.loadIcon(packageManager) /** * 获取 APP 是否为 DEBUG 版本 - * @param name APP 包名 + * @param packageName APP 包名 * @return [Boolean] */ -fun Context.isAppDebuggable(name: String) = - safeOfFalse { (packageManager?.getPackageInfo(name, 0)?.applicationInfo?.flags?.and(ApplicationInfo.FLAG_DEBUGGABLE) ?: 0) != 0 } +fun Context.isAppDebuggable(packageName: String) = + safeOfFalse { (getPackageInfoCompat(packageName)?.applicationInfo?.flags?.and(ApplicationInfo.FLAG_DEBUGGABLE) ?: 0) != 0 } /** * 对数值自动补零 @@ -291,8 +321,11 @@ val isNotNoificationEnabled get() = !NotificationManagerCompat.from(appContext). * 网络连接是否正常 * @return [Boolean] 网络是否连接 */ -val isNetWorkSuccess - get() = safeOfFalse { appContext.getSystemService()?.activeNetworkInfo != null } +val Context.isNetWorkSuccess + get() = safeOfFalse { + @Suppress("DEPRECATION") + getSystemService()?.activeNetworkInfo != null + } /** * dp 转换为 pxInt @@ -313,7 +346,9 @@ fun Number.dpFloat(context: Context) = toFloat() * context.resources.displayMetr * @return [Int] Android < 12 返回 [wallpaperColor] */ 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] */ -val Int.brighter: Int +val Int.brighterColor: Int get() { val hsv = FloatArray(3) Color.colorToHSV(this, hsv) @@ -341,7 +376,7 @@ val Int.brighter: Int * 是否为白色 * @return [Boolean] */ -val Int.isWhite +val Int.isWhiteColor get() = safeOfTrue { val r = this and 0xff0000 shr 16 val g = this and 0x00ff00 shr 8 @@ -411,10 +446,10 @@ fun Bitmap.round(radius: Float): Bitmap = safeOf(default = this) { * @return [String] */ fun findPropString(key: String, default: String = "") = safeOf(default) { - (classOf(name = "android.os.SystemProperties").method { + "android.os.SystemProperties".toClassOrNull()?.method { name = "get" 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 包名 */ fun Context.openSelfSetting(packageName: String = appContext.packageName) = runCatching { - if (packageName.isInstall) + if (isInstall(packageName)) startActivity(Intent().apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK 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 it 方法体 */ -fun Any?.delayedRun(ms: Long = 150, it: () -> Unit) = runInSafe { Handler().postDelayed({ it() }, ms) } \ No newline at end of file +fun Any?.delayedRun(ms: Long = 150, it: () -> Unit) = runInSafe { + @Suppress("DEPRECATION") + Handler().postDelayed({ it() }, ms) +} \ No newline at end of file diff --git a/app/src/main/java/com/fankes/miui/notify/utils/tool/GithubReleaseTool.kt b/app/src/main/java/com/fankes/miui/notify/utils/tool/GithubReleaseTool.kt index c5af682..33fc18e 100644 --- a/app/src/main/java/com/fankes/miui/notify/utils/tool/GithubReleaseTool.kt +++ b/app/src/main/java/com/fankes/miui/notify/utils/tool/GithubReleaseTool.kt @@ -91,7 +91,7 @@ object GithubReleaseTool { * @param callback 已连接回调 */ private fun checkingInternetConnect(context: Context, callback: () -> Unit) = runInSafe { - if (isNetWorkSuccess) + if (context.isNetWorkSuccess) OkHttpClient().newBuilder().build().newCall( Request.Builder() .url("https://www.baidu.com") diff --git a/app/src/main/java/com/fankes/miui/notify/utils/tool/IconAdaptationTool.kt b/app/src/main/java/com/fankes/miui/notify/utils/tool/IconAdaptationTool.kt index 7b112eb..31932f3 100644 --- a/app/src/main/java/com/fankes/miui/notify/utils/tool/IconAdaptationTool.kt +++ b/app/src/main/java/com/fankes/miui/notify/utils/tool/IconAdaptationTool.kt @@ -129,12 +129,12 @@ object IconAdaptationTool { ) notify(packageName.hashCode(), Notification.Builder(context, NOTIFY_CHANNEL).apply { setShowWhen(true) - setContentTitle("您已安装 ${context.findAppName(packageName)}") + setContentTitle("您已安装 ${context.appNameOf(packageName)}") setContentText("尚未适配此应用,点按打开在线规则。") setColor(0xFF2993F0.toInt()) setAutoCancel(true) setSmallIcon(Icon.createWithBitmap(smallIcon)) - setLargeIcon(context.findAppIcon(packageName)?.toBitmap()) + setLargeIcon(context.appIconOf(packageName)?.toBitmap()) setContentIntent( PendingIntent.getActivity( context, packageName.hashCode(), @@ -146,7 +146,7 @@ object IconAdaptationTool { flags = Intent.FLAG_ACTIVITY_NEW_TASK }.apply { putExtra("isNewAppSupport", true) - putExtra("appName", context.findAppName(packageName)) + putExtra("appName", context.appNameOf(packageName)) putExtra("pkgName", packageName) }, if (Build.VERSION.SDK_INT < 31) PendingIntent.FLAG_UPDATE_CURRENT else PendingIntent.FLAG_IMMUTABLE )