diff --git a/app/build.gradle.kts b/app/build.gradle.kts index d68b7cb..01083fd 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -15,8 +15,8 @@ android { applicationId = namespace minSdk = 34 targetSdk = 35 - versionCode = 2410 - versionName = "2.4.1" + versionCode = 2500 + versionName = "2.5.0" } val properties = Properties() runCatching { properties.load(project.rootProject.file("local.properties").inputStream()) } diff --git a/app/src/main/kotlin/top/yukonga/mediaControlBlur/MainHook.kt b/app/src/main/kotlin/top/yukonga/mediaControlBlur/MainHook.kt index 99d8ae6..f6b788c 100644 --- a/app/src/main/kotlin/top/yukonga/mediaControlBlur/MainHook.kt +++ b/app/src/main/kotlin/top/yukonga/mediaControlBlur/MainHook.kt @@ -5,6 +5,7 @@ import android.app.AndroidAppHelper import android.content.Context import android.content.res.ColorStateList import android.content.res.Resources +import android.database.ContentObserver import android.graphics.Bitmap import android.graphics.Canvas import android.graphics.Color @@ -18,6 +19,9 @@ import android.graphics.drawable.ClipDrawable import android.graphics.drawable.GradientDrawable import android.graphics.drawable.Icon import android.graphics.drawable.LayerDrawable +import android.os.Handler +import android.os.Looper +import android.provider.Settings import android.util.TypedValue import android.view.Gravity import android.view.ViewGroup @@ -53,13 +57,50 @@ class MainHook : IXposedHookLoadPackage { when (lpparam.packageName) { "com.android.systemui" -> { try { + var lockScreenStatus: Boolean? = null + var darkModeStatus: Boolean? = null + val miuiMediaControlPanel = loadClassOrNull("com.android.systemui.statusbar.notification.mediacontrol.MiuiMediaControlPanel") val notificationUtil = loadClassOrNull("com.android.systemui.statusbar.notification.NotificationUtil") val playerTwoCircleView = loadClassOrNull("com.android.systemui.statusbar.notification.mediacontrol.PlayerTwoCircleView") val seekBarObserver = loadClassOrNull("com.android.systemui.media.controls.models.player.SeekBarObserver") + val mediaViewHolder = loadClassOrNull("com.android.systemui.media.controls.models.player.MediaViewHolder") val statusBarStateControllerImpl = loadClassOrNull("com.android.systemui.statusbar.StatusBarStateControllerImpl") + mediaViewHolder?.constructors?.first()?.createAfterHook { + val context = AndroidAppHelper.currentApplication().applicationContext + val action0 = it.thisObject.objectHelper().getObjectOrNullAs("action0") + val action1 = it.thisObject.objectHelper().getObjectOrNullAs("action1") + val action2 = it.thisObject.objectHelper().getObjectOrNullAs("action2") + val action3 = it.thisObject.objectHelper().getObjectOrNullAs("action3") + val action4 = it.thisObject.objectHelper().getObjectOrNullAs("action4") + + fun updateColorFilter() { + val color = if (isDarkMode(context)) Color.WHITE else Color.BLACK + action0?.setColorFilter(color) + action1?.setColorFilter(color) + action2?.setColorFilter(color) + action3?.setColorFilter(color) + action4?.setColorFilter(color) + } + + updateColorFilter() + + val darkModeObserver = object : ContentObserver(Handler(Looper.getMainLooper())) { + override fun onChange(selfChange: Boolean) { + updateColorFilter() + } + } + + context.contentResolver.registerContentObserver( + Settings.Secure.getUriFor("ui_night_mode"), false, darkModeObserver + ) + } + seekBarObserver?.constructors?.first()?.createAfterHook { + it.thisObject.objectHelper().setObject("seekBarEnabledMaxHeight", 9.dp) + val seekBar = it.args[0].objectHelper().getObjectOrNullAs("seekBar") + val backgroundDrawable = GradientDrawable().apply { color = ColorStateList(arrayOf(intArrayOf()), intArrayOf(Color.parseColor("#20ffffff"))) cornerRadius = 9.dp.toFloat() @@ -70,21 +111,17 @@ class MainHook : IXposedHookLoadPackage { cornerRadius = 9.dp.toFloat() } + val thumbDrawable = seekBar?.thumb as LayerDrawable val layerDrawable = LayerDrawable(arrayOf(backgroundDrawable, ClipDrawable(onProgressDrawable, Gravity.START, ClipDrawable.HORIZONTAL))) - it.thisObject.objectHelper().setObject("seekBarEnabledMaxHeight", 9.dp) - val seekBar = it.args[0].objectHelper().getObjectOrNullAs("seekBar") - seekBar?.apply { - thumb = (thumb as LayerDrawable).apply { - setMinimumWidth(9.dp) - setMinimumHeight(9.dp) - } + seekBar.apply { + thumb = thumbDrawable progressDrawable = layerDrawable } } miuiMediaControlPanel?.methodFinder()?.filterByName("bindPlayer")?.first()?.createAfterHook { - val context = AndroidAppHelper.currentApplication().applicationContext + val context = it.thisObject.objectHelper().getObjectOrNullUntilSuperclassAs("mContext") ?: return@createAfterHook val isBackgroundBlurOpened = XposedHelpers.callStaticMethod(notificationUtil, "isBackgroundBlurOpened", context) as Boolean @@ -93,102 +130,85 @@ class MainHook : IXposedHookLoadPackage { val titleText = mMediaViewHolder.objectHelper().getObjectOrNullAs("titleText") val artistText = mMediaViewHolder.objectHelper().getObjectOrNullAs("artistText") val seamlessIcon = mMediaViewHolder.objectHelper().getObjectOrNullAs("seamlessIcon") - val action0 = mMediaViewHolder.objectHelper().getObjectOrNullAs("action0") - val action1 = mMediaViewHolder.objectHelper().getObjectOrNullAs("action1") - val action2 = mMediaViewHolder.objectHelper().getObjectOrNullAs("action2") - val action3 = mMediaViewHolder.objectHelper().getObjectOrNullAs("action3") - val action4 = mMediaViewHolder.objectHelper().getObjectOrNullAs("action4") val seekBar = mMediaViewHolder.objectHelper().getObjectOrNullAs("seekBar") val elapsedTimeView = mMediaViewHolder.objectHelper().getObjectOrNullAs("elapsedTimeView") val totalTimeView = mMediaViewHolder.objectHelper().getObjectOrNullAs("totalTimeView") val albumView = mMediaViewHolder.objectHelper().getObjectOrNullAs("albumView") val appIcon = mMediaViewHolder.objectHelper().getObjectOrNullAs("appIcon") - val grey = if (isDarkMode(context)) Color.parseColor("#80ffffff") else Color.parseColor("#99000000") - + val artwork = it.args[0].objectHelper().getObjectOrNullAs("artwork") ?: return@createAfterHook + val artworkLayer = artwork.loadDrawable(context) ?: return@createAfterHook + + val artworkBitmap = Bitmap.createBitmap(artworkLayer.intrinsicWidth, artworkLayer.intrinsicHeight, Bitmap.Config.ARGB_8888) + val canvas = Canvas(artworkBitmap) + artworkLayer.setBounds(0, 0, artworkLayer.intrinsicWidth, artworkLayer.intrinsicHeight) + artworkLayer.draw(canvas) + val resizedBitmap = Bitmap.createScaledBitmap(artworkBitmap, 300, 300, true) + val radius = 45f + val newBitmap = Bitmap.createBitmap(resizedBitmap.width, resizedBitmap.height, Bitmap.Config.ARGB_8888) + val canvas1 = Canvas(newBitmap) + val paint = Paint() + val rect = Rect(0, 0, resizedBitmap.width, resizedBitmap.height) + val rectF = RectF(rect) + paint.isAntiAlias = true + canvas1.drawARGB(0, 0, 0, 0) + paint.color = Color.BLACK + canvas1.drawRoundRect(rectF, radius, radius, paint) + paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN) + canvas1.drawBitmap(resizedBitmap, rect, rect, paint) + albumView?.setImageDrawable(BitmapDrawable(context.resources, newBitmap)) + (appIcon?.parent as ViewGroup?)?.removeView(appIcon) + + val grey = if (isDarkMode(context)) Color.LTGRAY else Color.DKGRAY + val color = if (isDarkMode(context)) Color.WHITE else Color.BLACK + seekBar?.thumb?.colorFilter = colorFilter(Color.TRANSPARENT) + elapsedTimeView?.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 11f) + totalTimeView?.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 11f) if (!isBackgroundBlurOpened) { titleText?.setTextColor(Color.WHITE) seamlessIcon?.setColorFilter(Color.WHITE) - action0?.setColorFilter(Color.WHITE) - action1?.setColorFilter(Color.WHITE) - action2?.setColorFilter(Color.WHITE) - action3?.setColorFilter(Color.WHITE) - action4?.setColorFilter(Color.WHITE) seekBar?.progressDrawable?.colorFilter = colorFilter(Color.WHITE) - seekBar?.thumb?.colorFilter = colorFilter(Color.TRANSPARENT) } else { - seekBar?.thumb?.colorFilter = colorFilter(Color.TRANSPARENT) artistText?.setTextColor(grey) elapsedTimeView?.setTextColor(grey) totalTimeView?.setTextColor(grey) - if (!isDarkMode(context)) { - titleText?.setTextColor(Color.BLACK) - seamlessIcon?.setColorFilter(Color.BLACK) - action0?.setColorFilter(Color.BLACK) - action1?.setColorFilter(Color.BLACK) - action2?.setColorFilter(Color.BLACK) - action3?.setColorFilter(Color.BLACK) - action4?.setColorFilter(Color.BLACK) - seekBar?.progressDrawable?.colorFilter = colorFilter(Color.BLACK) - } else { - titleText?.setTextColor(Color.WHITE) - seamlessIcon?.setColorFilter(Color.WHITE) - action0?.setColorFilter(Color.WHITE) - action1?.setColorFilter(Color.WHITE) - action2?.setColorFilter(Color.WHITE) - action3?.setColorFilter(Color.WHITE) - action4?.setColorFilter(Color.WHITE) - seekBar?.progressDrawable?.colorFilter = colorFilter(Color.WHITE) - } - - val artwork = it.args[0].objectHelper().getObjectOrNullAs("artwork") ?: return@createAfterHook - val artworkLayer = artwork.loadDrawable(context) ?: return@createAfterHook - val artworkBitmap = Bitmap.createBitmap(artworkLayer.intrinsicWidth, artworkLayer.intrinsicHeight, Bitmap.Config.ARGB_8888) - val canvas = Canvas(artworkBitmap) - artworkLayer.setBounds(0, 0, artworkLayer.intrinsicWidth, artworkLayer.intrinsicHeight) - artworkLayer.draw(canvas) - val resizedBitmap = Bitmap.createScaledBitmap(artworkBitmap, 300, 300, true) - - val radius = 45f - val newBitmap = Bitmap.createBitmap(resizedBitmap.width, resizedBitmap.height, Bitmap.Config.ARGB_8888) - val canvas1 = Canvas(newBitmap) - - val paint = Paint() - val rect = Rect(0, 0, resizedBitmap.width, resizedBitmap.height) - val rectF = RectF(rect) - - paint.isAntiAlias = true - canvas1.drawARGB(0, 0, 0, 0) - paint.color = Color.BLACK - canvas1.drawRoundRect(rectF, radius, radius, paint) - - paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_IN) - canvas1.drawBitmap(resizedBitmap, rect, rect, paint) - - albumView?.setImageDrawable(BitmapDrawable(context.resources, newBitmap)) - - (appIcon?.parent as ViewGroup?)?.removeView(appIcon) - - elapsedTimeView?.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 11f) - totalTimeView?.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 11f) + titleText?.setTextColor(grey) + titleText?.setTextColor(color) + seamlessIcon?.setColorFilter(color) + seekBar?.progressDrawable?.colorFilter = colorFilter(color) } } - var lockScreenStatus: Boolean? = null - var darkModeStatus: Boolean? = null playerTwoCircleView?.methodFinder()?.filterByName("onDraw")?.first()?.createBeforeHook { val context = AndroidAppHelper.currentApplication().applicationContext val isBackgroundBlurOpened = XposedHelpers.callStaticMethod(notificationUtil, "isBackgroundBlurOpened", context) as Boolean if (!isBackgroundBlurOpened) return@createBeforeHook - it.thisObject.objectHelper().getObjectOrNullAs("mPaint1")?.alpha = 0 - it.thisObject.objectHelper().getObjectOrNullAs("mPaint2")?.alpha = 0 + val mPaint1 = it.thisObject.objectHelper().getObjectOrNullAs("mPaint1") + val mPaint2 = it.thisObject.objectHelper().getObjectOrNullAs("mPaint2") + if (mPaint1?.alpha == 0) return@createBeforeHook + + if (BuildConfig.DEBUG) Log.dx("PlayerTwoCircleView onDraw called!") + + mPaint1?.alpha = 0 + mPaint2?.alpha = 0 it.thisObject.objectHelper().setObject("mRadius", 0f) (it.thisObject as ImageView).setMiViewBlurMode(BACKGROUND) (it.thisObject as ImageView).setBlurRoundRect(getNotificationElementRoundRect(context)) + val miuiStubClass = loadClassOrNull("miui.stub.MiuiStub") + val miuiStubInstance = XposedHelpers.getStaticObjectField(miuiStubClass, "INSTANCE") + val mSysUIProvider = XposedHelpers.getObjectField(miuiStubInstance, "mSysUIProvider") + val mStatusBarStateController = XposedHelpers.getObjectField(mSysUIProvider, "mStatusBarStateController") + val getLazyClass = XposedHelpers.callMethod(mStatusBarStateController, "get") + val getState = XposedHelpers.callMethod(getLazyClass, "getState") + + (it.thisObject as ImageView).apply { + getNotificationElementBlendColors(context, getState == 1)?.let { iArr -> setMiBackgroundBlendColors(iArr, 1f) } + } + statusBarStateControllerImpl?.methodFinder()?.filterByName("getState")?.first()?.createAfterHook { hookParam1 -> val getStatusBarState = hookParam1.result as Int val isInLockScreen = getStatusBarState == 1 @@ -203,8 +223,6 @@ class MainHook : IXposedHookLoadPackage { } } } - - it.result = null } playerTwoCircleView?.methodFinder()?.filterByName("setBackground")?.first()?.createBeforeHook { @@ -213,7 +231,6 @@ class MainHook : IXposedHookLoadPackage { val isBackgroundBlurOpened = XposedHelpers.callStaticMethod(notificationUtil, "isBackgroundBlurOpened", context) as Boolean if (!isBackgroundBlurOpened) return@createBeforeHook - (it.thisObject as ImageView).background = null it.result = null } } catch (t: Throwable) { @@ -225,7 +242,6 @@ class MainHook : IXposedHookLoadPackage { } } - @SuppressLint("DiscouragedApi") private fun getResourceValue(resources: Resources, name: String, type: String, theme: Resources.Theme? = null): Int { val id = resources.getIdentifier(name, type, "com.android.systemui")