mirror of
https://github.com/fankes/ColorOSNotifyIcon.git
synced 2025-09-04 09:45:34 +08:00
Modify merge YukiHookAPI new usage and compatible with API 33
This commit is contained in:
@@ -36,7 +36,7 @@ import com.highcapable.yukihookapi.hook.xposed.proxy.IYukiHookXposedInit
|
||||
class HookEntry : IYukiHookXposedInit {
|
||||
|
||||
override fun onInit() = configs {
|
||||
debugTag = "ColorOSNotify"
|
||||
debugLog { tag = "ColorOSNotify" }
|
||||
isDebug = false
|
||||
}
|
||||
|
||||
|
@@ -56,10 +56,7 @@ import com.fankes.coloros.notify.utils.tool.IconAdaptationTool
|
||||
import com.fankes.coloros.notify.utils.tool.SystemUITool
|
||||
import com.highcapable.yukihookapi.hook.bean.VariousClass
|
||||
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
|
||||
import com.highcapable.yukihookapi.hook.factory.current
|
||||
import com.highcapable.yukihookapi.hook.factory.field
|
||||
import com.highcapable.yukihookapi.hook.factory.hasMethod
|
||||
import com.highcapable.yukihookapi.hook.factory.method
|
||||
import com.highcapable.yukihookapi.hook.factory.*
|
||||
import com.highcapable.yukihookapi.hook.log.loggerD
|
||||
import com.highcapable.yukihookapi.hook.log.loggerE
|
||||
import com.highcapable.yukihookapi.hook.log.loggerW
|
||||
@@ -234,12 +231,10 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
* @return [Boolean]
|
||||
*/
|
||||
private val isOldNotificationBackground
|
||||
get() = safeOfFalse {
|
||||
NotificationBackgroundViewClass.clazz.hasMethod {
|
||||
name = "drawCustom"
|
||||
paramCount = 2
|
||||
}
|
||||
}
|
||||
get() = NotificationBackgroundViewClass.toClassOrNull()?.hasMethod {
|
||||
name = "drawCustom"
|
||||
paramCount = 2
|
||||
} ?: false
|
||||
|
||||
/**
|
||||
* 打印日志
|
||||
@@ -257,7 +252,7 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
isGrayscale: Boolean
|
||||
) {
|
||||
if (prefs.get(DataConst.ENABLE_MODULE_LOG)) loggerD(
|
||||
msg = "$tag --> [${context.findAppName(packageName)}][$packageName] " +
|
||||
msg = "$tag --> [${context.appNameOf(packageName)}][$packageName] " +
|
||||
"custom [$isCustom] " +
|
||||
"grayscale [$isGrayscale]"
|
||||
)
|
||||
@@ -278,14 +273,14 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
|
||||
/** 刷新状态栏小图标 */
|
||||
private fun refreshStatusBarIcons() = runInSafe {
|
||||
val nfField = StatusBarIconViewClass.clazz.field { name = "mNotification" }
|
||||
val sRadiusField = StatusBarIconViewClass.clazz.field { name = "sIconRadiusFraction" }
|
||||
val sNfSizeField = StatusBarIconViewClass.clazz.field { name = "sNotificationRoundIconSize" }
|
||||
val roundUtil = RoundRectDrawableUtil_CompanionClass.clazz.method {
|
||||
val nfField = StatusBarIconViewClass.toClass().field { name = "mNotification" }
|
||||
val sRadiusField = StatusBarIconViewClass.toClass().field { name = "sIconRadiusFraction" }
|
||||
val sNfSizeField = StatusBarIconViewClass.toClass().field { name = "sNotificationRoundIconSize" }
|
||||
val roundUtil = RoundRectDrawableUtil_CompanionClass.toClass().method {
|
||||
name = "getRoundRectDrawable"
|
||||
param(DrawableClass, FloatType, IntType, IntType, ContextClass)
|
||||
}.onNoSuchMethod { loggerE(msg = "Your system not support \"getRoundRectDrawable\"!", e = it) }
|
||||
.get(RoundRectDrawableUtilClass.clazz.field { name = "Companion" }.get().self)
|
||||
.get(RoundRectDrawableUtilClass.toClass().field { name = "Companion" }.get().any())
|
||||
/** 启动一个线程防止卡顿 */
|
||||
Thread {
|
||||
(notificationIconContainer?.children?.toList() ?: notificationIconInstances.takeIf { it.isNotEmpty() })?.forEach {
|
||||
@@ -295,6 +290,7 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
|
||||
/** 得到原始通知图标 */
|
||||
val iconDrawable = nf.notification.smallIcon.loadDrawable(it.context)
|
||||
?: return@Thread loggerW(msg = "refreshStatusBarIcons got null smallIcon")
|
||||
/** 获取优化后的状态栏通知图标 */
|
||||
compatStatusIcon(
|
||||
context = it.context,
|
||||
@@ -318,12 +314,10 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
|
||||
/** 刷新通知小图标 */
|
||||
private fun refreshNotificationIcons() = runInSafe {
|
||||
notificationPresenter?.current {
|
||||
method {
|
||||
name = "updateNotificationsOnDensityOrFontScaleChanged"
|
||||
emptyParam()
|
||||
}.call()
|
||||
}
|
||||
notificationPresenter?.current()?.method {
|
||||
name = "updateNotificationsOnDensityOrFontScaleChanged"
|
||||
emptyParam()
|
||||
}?.call()
|
||||
modifyNotifyPanelAlpha(notificationPlayerView, isTint = true)
|
||||
}
|
||||
|
||||
@@ -336,7 +330,7 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
* @return [Boolean]
|
||||
*/
|
||||
private fun isGrayscaleIcon(context: Context?, drawable: Drawable?) =
|
||||
ContrastColorUtilClass.clazz.let {
|
||||
ContrastColorUtilClass.toClassOrNull()?.let {
|
||||
drawable is VectorDrawable || it.method {
|
||||
name = "isGrayscaleIcon"
|
||||
param(DrawableClass)
|
||||
@@ -344,7 +338,7 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
name = "getInstance"
|
||||
param(ContextClass)
|
||||
}.get().invoke(context)).boolean(drawable)
|
||||
}
|
||||
} ?: false
|
||||
|
||||
/**
|
||||
* 适配通知栏、状态栏来自系统推送的彩色 APP 图标
|
||||
@@ -431,7 +425,7 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
prefs.get(DataConst.ENABLE_NOTIFY_ICON_FORCE_APP_ICON) && isEnableHookColorNotifyIcon(isHooking = false) ->
|
||||
iconView.apply {
|
||||
/** 重新设置图标 */
|
||||
setImageDrawable(appIcons[packageName] ?: context.findAppIcon(packageName))
|
||||
setImageDrawable(appIcons[packageName] ?: context.appIconOf(packageName))
|
||||
/** 设置默认样式 */
|
||||
setDefaultNotifyIconViewStyle()
|
||||
}
|
||||
@@ -451,7 +445,7 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
val newStyle = (if (context.isSystemInDarkMode) 0xffdcdcdc else Color.WHITE).toInt()
|
||||
|
||||
/** 原生着色 */
|
||||
val a12Style = if (isUpperOfAndroidS) context.wallpaperColor else
|
||||
val a12Style = if (isUpperOfAndroidS) context.systemAccentColor else
|
||||
(if (context.isSystemInDarkMode) 0xff707173 else oldStyle).toInt()
|
||||
|
||||
/** 旧版图标着色 */
|
||||
@@ -538,8 +532,8 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
colorFilter = null
|
||||
}
|
||||
|
||||
/** 注册 */
|
||||
private fun register() {
|
||||
/** 注册生命周期 */
|
||||
private fun registerLifecycle() {
|
||||
/** 解锁后重新刷新状态栏图标防止系统重新设置它 */
|
||||
onAppLifecycle { registerReceiver(Intent.ACTION_USER_PRESENT) { _, _ -> if (isUsingCachingMethod) refreshStatusBarIcons() } }
|
||||
/** 刷新图标缓存 */
|
||||
@@ -577,8 +571,8 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
}
|
||||
|
||||
override fun onHook() {
|
||||
/** 注册 */
|
||||
register()
|
||||
/** 注册生命周期 */
|
||||
registerLifecycle()
|
||||
/** 缓存图标数据 */
|
||||
cachingIconDatas()
|
||||
/** 移除开发者警告通知 */
|
||||
@@ -635,24 +629,24 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
param(NotificationEntryClass, BooleanType)
|
||||
}
|
||||
afterHook {
|
||||
IconBuilderClass.clazz.field { name = "context" }
|
||||
IconBuilderClass.toClass().field { name = "context" }
|
||||
.get(field { name = "iconBuilder" }.get(instance).cast()).cast<Context>()?.also { context ->
|
||||
NotificationEntryClass.clazz.method {
|
||||
NotificationEntryClass.toClass().method {
|
||||
name = "getSbn"
|
||||
}.get(args().first().any()).invoke<StatusBarNotification>()?.also { nf ->
|
||||
nf.notification.smallIcon.loadDrawable(context).also { iconDrawable ->
|
||||
nf.notification.smallIcon.loadDrawable(context)?.also { iconDrawable ->
|
||||
compatStatusIcon(
|
||||
context = context,
|
||||
nf = nf,
|
||||
isGrayscaleIcon = isGrayscaleIcon(context, iconDrawable).also {
|
||||
/** 缓存第一次的 APP 小图标 */
|
||||
if (it.not()) context.findAppIcon(nf.packageName)
|
||||
if (it.not()) context.appIconOf(nf.packageName)
|
||||
?.also { e -> appIcons[nf.packageName] = e }
|
||||
},
|
||||
packageName = nf.packageName,
|
||||
drawable = iconDrawable
|
||||
).also { pair ->
|
||||
if (pair.second) StatusBarIconClass.clazz.field {
|
||||
if (pair.second) StatusBarIconClass.toClass().field {
|
||||
name = "icon"
|
||||
type = IconClass
|
||||
}.get(result).set(Icon.createWithBitmap(pair.first.toBitmap()))
|
||||
@@ -679,7 +673,7 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
/** 注入通知控制器实例 */
|
||||
StatusBarNotificationPresenterClass.hook {
|
||||
injectMember {
|
||||
allConstructors()
|
||||
allMembers(MembersType.CONSTRUCTOR)
|
||||
afterHook { notificationPresenter = instance }
|
||||
}
|
||||
}
|
||||
@@ -772,30 +766,30 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
superClass(isOnlySuperClass = true)
|
||||
}.get(instance).any()
|
||||
/** 记录媒体通知 [View] */
|
||||
notificationPlayerView = PlayerViewHolderClass.clazz.method {
|
||||
notificationPlayerView = PlayerViewHolderClass.toClassOrNull()?.method {
|
||||
name = "getPlayer"
|
||||
emptyParam()
|
||||
}.get(holder).invoke()
|
||||
}?.get(holder)?.invoke()
|
||||
/** 设置背景着色 */
|
||||
modifyNotifyPanelAlpha(notificationPlayerView, isTint = true)
|
||||
/** 当前是否正在播放 */
|
||||
val isPlaying = MediaDataClass.clazz.method {
|
||||
val isPlaying = MediaDataClass.toClassOrNull()?.method {
|
||||
name = "isPlaying"
|
||||
emptyParam()
|
||||
}.get(args().first().any()).boolean()
|
||||
}?.get(args().first().any())?.boolean() ?: false
|
||||
|
||||
/** 当前通知是否展开 */
|
||||
val isExpanded = OplusMediaViewControllerClass.clazz.method {
|
||||
val isExpanded = OplusMediaViewControllerClass.toClassOrNull()?.method {
|
||||
name = "getExpanded"
|
||||
emptyParam()
|
||||
}.get(field { name = "mOplusMediaViewController" }.get(instance).self).boolean()
|
||||
}?.get(field { name = "mOplusMediaViewController" }.get(instance).any())?.boolean() ?: false
|
||||
/** 符合条件后执行 */
|
||||
if (prefs.get(DataConst.ENABLE_NOTIFY_MEDIA_PANEL_AUTO_EXP).not() || isExpanded || isPlaying.not()) return@afterHook
|
||||
/** 模拟手动展开通知 */
|
||||
BasePlayViewHolderClass.clazz.method {
|
||||
BasePlayViewHolderClass.toClassOrNull()?.method {
|
||||
name = "getExpandButton"
|
||||
emptyParam()
|
||||
}.get(holder).invoke<View>()?.performClick()
|
||||
}?.get(holder)?.invoke<View>()?.performClick()
|
||||
}
|
||||
}
|
||||
}.ignoredHookClassNotFoundFailure()
|
||||
@@ -804,19 +798,19 @@ object SystemUIHooker : YukiBaseHooker() {
|
||||
injectMember {
|
||||
method { name = "resolveHeaderViews" }
|
||||
afterHook {
|
||||
NotificationHeaderViewWrapperClass.clazz
|
||||
NotificationHeaderViewWrapperClass.toClass()
|
||||
.field { name = "mIcon" }.get(instance).cast<ImageView>()?.apply {
|
||||
ExpandableNotificationRowClass.clazz
|
||||
ExpandableNotificationRowClass.toClass()
|
||||
.method { name = "getEntry" }
|
||||
.get(NotificationViewWrapperClass.clazz.field {
|
||||
.get(NotificationViewWrapperClass.toClass().field {
|
||||
name = "mRow"
|
||||
}.get(instance).self).call()?.let {
|
||||
}.get(instance).any()).call()?.let {
|
||||
it.javaClass.method {
|
||||
name = "getSbn"
|
||||
}.get(it).invoke<StatusBarNotification>()
|
||||
}.also { nf ->
|
||||
nf?.notification?.also {
|
||||
it.smallIcon.loadDrawable(context).also { iconDrawable ->
|
||||
it.smallIcon.loadDrawable(context)?.also { iconDrawable ->
|
||||
compatNotifyIcon(
|
||||
context = context,
|
||||
nf = nf,
|
||||
|
@@ -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.coloros.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()
|
||||
}
|
||||
}
|
@@ -31,9 +31,9 @@ import androidx.core.view.WindowCompat
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.fankes.coloros.notify.R
|
||||
import com.fankes.coloros.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()
|
||||
/** 初始化沉浸状态栏 */
|
||||
|
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* ColorOSNotifyIcon - Optimize notification icons for ColorOS and adapt to native notification icon specifications.
|
||||
* Copyright (C) 2019-2022 Fankes Studio(qzmmcn@163.com)
|
||||
* https://github.com/fankes/ColorOSNotifyIcon
|
||||
*
|
||||
* 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.coloros.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)
|
||||
}
|
@@ -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.coloros.notify.utils.factory
|
||||
|
||||
@@ -28,15 +28,15 @@ import android.app.Activity
|
||||
import android.app.Notification
|
||||
import android.app.Service
|
||||
import android.app.WallpaperManager
|
||||
import android.app.WallpaperManager.FLAG_SYSTEM
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
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.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Color
|
||||
@@ -48,13 +48,17 @@ 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.field
|
||||
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
|
||||
@@ -62,7 +66,6 @@ import java.io.ByteArrayOutputStream
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
|
||||
/**
|
||||
* 系统深色模式是否开启
|
||||
* @return [Boolean] 是否开启
|
||||
@@ -87,6 +90,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] 是否符合条件
|
||||
@@ -103,7 +112,7 @@ inline val isLowerAndroidP get() = Build.VERSION.SDK_INT < Build.VERSION_CODES.P
|
||||
* 当前设备是否是 ColorOS 定制 Android 系统
|
||||
* @return [Boolean] 是否符合条件
|
||||
*/
|
||||
val isColorOS by lazy { ("oppo.R").hasClass || ("com.color.os.ColorBuild").hasClass || ("oplus.R").hasClass }
|
||||
val isColorOS by lazy { "oppo.R".hasClass() || "com.color.os.ColorBuild".hasClass() || "oplus.R".hasClass() }
|
||||
|
||||
/**
|
||||
* 当前设备是否不是 ColorOS 定制 Android 系统
|
||||
@@ -146,67 +155,88 @@ val colorOSVersion get() = "$colorOSNumberVersion ${Build.DISPLAY}"
|
||||
*/
|
||||
val colorOSNumberVersion
|
||||
get() = safeOf(default = "无法获取") {
|
||||
(classOf(name = "com.oplus.os.OplusBuild").let {
|
||||
it.field { name = "VERSIONS" }.ignoredError().get().array<String>().takeIf { e -> e.isNotEmpty() }
|
||||
?.get(it.method { name = "getOplusOSVERSION" }.ignoredError().get().int() - 1)
|
||||
"com.oplus.os.OplusBuild".toClassOrNull()?.let {
|
||||
it.field { name = "VERSIONS" }.ignored().get().array<String>().takeIf { e -> e.isNotEmpty() }
|
||||
?.get(it.method { name = "getOplusOSVERSION" }.ignored().get().int() - 1)
|
||||
} ?: findPropString(
|
||||
key = "ro.system.build.fingerprint", default = "无法获取"
|
||||
).split("ssi:")[1].split("/")[0].trim())
|
||||
).split("ssi:")[1].split("/")[0].trim()
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到安装包信息
|
||||
* @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 }
|
||||
|
||||
/**
|
||||
* 对数值自动补零
|
||||
@@ -246,8 +276,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
|
||||
@@ -264,21 +297,32 @@ fun Number.dp(context: Context) = dpFloat(context).toInt()
|
||||
fun Number.dpFloat(context: Context) = toFloat() * context.resources.displayMetrics.density
|
||||
|
||||
/**
|
||||
* 获取系统壁纸颜色
|
||||
* 获取系统主题色
|
||||
*
|
||||
* 由于 ColorOS 阉割了 [android.R.color.system_accent1_600] 这里取系统壁纸颜色做补偿
|
||||
*
|
||||
* 从 ColorOS 13 (Android 13) 开始使用系统取色方案
|
||||
* @return [Int] Android < 13 返回 [wallpaperColor]
|
||||
*/
|
||||
val Context.systemAccentColor
|
||||
get() = safeOf(wallpaperColor) {
|
||||
if (isUpperOfAndroidT) resources.colorOf(android.R.color.system_accent1_600) else wallpaperColor
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统壁纸颜色
|
||||
* @return [Int] 无法获取时返回透明色
|
||||
*/
|
||||
val Context.wallpaperColor
|
||||
get() = safeOfNan {
|
||||
WallpaperManager.getInstance(this).getWallpaperColors(FLAG_SYSTEM)?.secondaryColor?.toArgb() ?: 0
|
||||
WallpaperManager.getInstance(this).getWallpaperColors(WallpaperManager.FLAG_SYSTEM)?.primaryColor?.toArgb() ?: 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为白色
|
||||
* @return [Boolean]
|
||||
*/
|
||||
val Int.isWhite
|
||||
val Int.isWhiteColor
|
||||
get() = safeOfTrue {
|
||||
val r = this and 0xff0000 shr 16
|
||||
val g = this and 0x00ff00 shr 8
|
||||
@@ -335,10 +379,10 @@ val String.bitmap: Bitmap get() = unbase64.bitmap
|
||||
* @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
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -412,7 +456,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
|
||||
@@ -457,4 +501,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)
|
||||
}
|
@@ -91,7 +91,7 @@ object GithubReleaseTool {
|
||||
* @param result 已连接回调
|
||||
*/
|
||||
private fun checkingInternetConnect(context: Context, result: () -> Unit) = runInSafe {
|
||||
if (isNetWorkSuccess)
|
||||
if (context.isNetWorkSuccess)
|
||||
OkHttpClient().newBuilder().build().newCall(
|
||||
Request.Builder()
|
||||
.url("https://www.baidu.com")
|
||||
|
@@ -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
|
||||
)
|
||||
|
Reference in New Issue
Block a user