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 {
override fun onInit() = configs {
debugTag = "MIUINativeNotifyIcon"
debugLog { tag = "MIUINativeNotifyIcon" }
isDebug = false
}

View File

@@ -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<Context?>() ?: appContext
}
get() = SystemUIApplicationClass.toClassOrNull()?.method { name = "getContext" }?.ignored()?.get()?.invoke<Context?>() ?: 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<StatusBarNotification>() ?: 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<StatusBarNotification>()
} ?: ExpandableNotificationRowClass.clazz
.method { name = "getStatusBarNotification" }
.get(this).invoke<StatusBarNotification>()
}.ignored().get(it).invoke<StatusBarNotification>()
} ?: ExpandableNotificationRowClass.toClassOrNull()
?.method { name = "getStatusBarNotification" }
?.get(this)?.invoke<StatusBarNotification>()
/**
* 根据当前 [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<ImageView>() ?: return@afterHook
val iconImageView = NotificationHeaderViewWrapperClass.toClassOrNull()
?.field { name = "mIcon" }?.get(instance)?.cast<ImageView>() ?: 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<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)
) 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 ?: ""
)
}
}
}

View File

@@ -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<ActivityConfigBinding>() {
return
}
/** 返回按钮点击事件 */
binding.titleBackIcon.setOnClickListener { onBackPressed() }
binding.titleBackIcon.setOnClickListener { callOnBackPressed() }
/** 刷新适配器结果相关 */
refreshAdapterResult()
/** 设置上下按钮点击事件 */
@@ -117,7 +117,7 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
onBindViews<AdapterConfigBinding> { 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<ActivityConfigBinding>() {
removeExtra("isNewAppSupport")
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 {
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 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<VB : ViewBinding> : AppCompatActivity() {
@@ -49,15 +49,11 @@ abstract class BaseActivity<VB : ViewBinding> : 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<VB>).method {
name = "inflate"
param(LayoutInflaterClass)
}.get().invoke<VB>(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<VB>(layoutInflater) ?: error("binding failed")
setContentView(binding.root)
/** 隐藏系统的标题栏 */
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.
*/
@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<ConnectivityManager>()?.activeNetworkInfo != null }
val Context.isNetWorkSuccess
get() = safeOfFalse {
@Suppress("DEPRECATION")
getSystemService<ConnectivityManager>()?.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) }
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 已连接回调
*/
private fun checkingInternetConnect(context: Context, callback: () -> Unit) = runInSafe {
if (isNetWorkSuccess)
if (context.isNetWorkSuccess)
OkHttpClient().newBuilder().build().newCall(
Request.Builder()
.url("https://www.baidu.com")

View File

@@ -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
)