From 83b4ffa50f089147bd10b2a4101d84eaffb8ddf1 Mon Sep 17 00:00:00 2001 From: DrDisagree <crazymahmud08@gmail.com> Date: Sun, 10 Nov 2024 17:34:37 +0600 Subject: [PATCH] OP QS Header: Fix media output dialog for android 15 Signed-off-by: DrDisagree <crazymahmud08@gmail.com> --- .../iconify/xposed/modules/OpQsHeader.kt | 104 +++++++++++++----- .../iconify/xposed/modules/utils/Helpers.kt | 9 ++ 2 files changed, 88 insertions(+), 25 deletions(-) diff --git a/app/src/main/java/com/drdisagree/iconify/xposed/modules/OpQsHeader.kt b/app/src/main/java/com/drdisagree/iconify/xposed/modules/OpQsHeader.kt index 9535e5bb2..a3121261e 100644 --- a/app/src/main/java/com/drdisagree/iconify/xposed/modules/OpQsHeader.kt +++ b/app/src/main/java/com/drdisagree/iconify/xposed/modules/OpQsHeader.kt @@ -25,6 +25,7 @@ import android.graphics.drawable.GradientDrawable import android.graphics.drawable.TransitionDrawable import android.media.MediaMetadata import android.media.session.MediaController +import android.media.session.MediaSession import android.media.session.MediaSessionManager import android.media.session.PlaybackState import android.net.ConnectivityManager @@ -33,6 +34,7 @@ import android.net.NetworkCapabilities import android.net.wifi.WifiManager import android.os.Handler import android.os.Looper +import android.os.UserHandle import android.provider.Settings import android.telephony.SubscriptionManager import android.telephony.TelephonyManager @@ -68,6 +70,7 @@ import com.drdisagree.iconify.utils.color.monet.quantize.QuantizerCelebi import com.drdisagree.iconify.utils.color.monet.score.Score import com.drdisagree.iconify.xposed.ModPack import com.drdisagree.iconify.xposed.modules.utils.ActivityLauncherUtils +import com.drdisagree.iconify.xposed.modules.utils.Helpers import com.drdisagree.iconify.xposed.modules.utils.Helpers.findClassInArray import com.drdisagree.iconify.xposed.modules.utils.Helpers.isMethodAvailable import com.drdisagree.iconify.xposed.modules.utils.Helpers.isQsTileOverlayEnabled @@ -274,6 +277,10 @@ class OpQsHeader(context: Context?) : ModPack(context!!) { "$SYSTEMUI_PACKAGE.media.controls.ui.controller.MediaControlPanel", "$SYSTEMUI_PACKAGE.media.controls.ui.MediaControlPanel" ) + val volumeDialogImplClass = findClass( + "$SYSTEMUI_PACKAGE.volume.VolumeDialogImpl", + loadPackageParam.classLoader + ) launchableImageView = findClassIfExists( "$SYSTEMUI_PACKAGE.animation.view.LaunchableImageView", loadPackageParam.classLoader @@ -320,12 +327,25 @@ class OpQsHeader(context: Context?) : ModPack(context!!) { } }) - hookAllConstructors(mediaControlPanelClass, object : XC_MethodHook() { + val getMediaOutputDialog = object : XC_MethodHook() { override fun afterHookedMethod(param: MethodHookParam) { - mMediaOutputDialogFactory = - getObjectField(param.thisObject, "mMediaOutputDialogFactory") + if (mMediaOutputDialogFactory == null) { + mMediaOutputDialogFactory = try { + getObjectField(param.thisObject, "mMediaOutputDialogFactory") + } catch (ignored: Throwable) { + getObjectField(param.thisObject, "mMediaOutputDialogManager") + } + } } - }) + } + + hookAllConstructors(mediaControlPanelClass, getMediaOutputDialog) + hookAllConstructors(volumeDialogImplClass, getMediaOutputDialog) + + Helpers.findAndDumpClass( + "com.android.systemui.media.dialog.MediaOutputDialogManager", + loadPackageParam.classLoader + ) hookAllMethods(qsTileViewImplClass, "init", object : XC_MethodHook() { override fun beforeHookedMethod(param: MethodHookParam) { @@ -620,14 +640,25 @@ class OpQsHeader(context: Context?) : ModPack(context!!) { val qsPanel = getObjectField(param.thisObject, "mView") val qsPanelTag = callMethod(qsPanel, "getDumpableTag") - callMethod( - mQSLogger, - "logSwitchTileLayout", - horizontal, - mUsingHorizontalLayout, - force, - qsPanelTag - ) + try { + callMethod( + mQSLogger, + "logSwitchTileLayout", + horizontal, + mUsingHorizontalLayout, + force, + qsPanelTag + ) + } catch (ignored: Throwable) { + callMethod( + mQSLogger, + "logSwitchTileLayout", + qsPanelTag, + horizontal, + mUsingHorizontalLayout, + force + ) + } setObjectField( param.thisObject, @@ -2053,7 +2084,9 @@ class OpQsHeader(context: Context?) : ModPack(context!!) { } private fun launchMediaOutputSwitcher(packageName: String?, v: View) { - if (packageName != null && mMediaOutputDialogFactory != null) { + if (packageName == null) return + + if (mMediaOutputDialogFactory != null) { if (isMethodAvailable( mMediaOutputDialogFactory, "create", @@ -2073,25 +2106,46 @@ class OpQsHeader(context: Context?) : ModPack(context!!) { ) ) { callMethod(mMediaOutputDialogFactory, "create", v, packageName, true, true) + } else if (isMethodAvailable( + mMediaOutputDialogFactory, + "createAndShow", + String::class.java, + Boolean::class.java, + View::class.java, + UserHandle::class.java, + MediaSession.Token::class.java + ) + ) { + callMethod( + mMediaOutputDialogFactory, + "createAndShow", + packageName, + true, + v, + null, + null + ) } else { - log(TAG + "MediaOutputDialogFactory is not available") + log(TAG + "No method available to create MediaOutputDialog") } + } else { + log(TAG + "MediaOutputDialogFactory is not available") } } private fun launchMediaPlayer(packageName: String?) { - val appIntent = if (packageName != null) Intent( - mContext.packageManager.getLaunchIntentForPackage(packageName) + if (packageName == null) return + + mActivityLauncherUtils.launchApp( + Intent( + mContext.packageManager.getLaunchIntentForPackage(packageName) + ).apply { + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + setPackage(packageName) + }, + true ) - else null - - if (appIntent != null) { - appIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - appIntent.setPackage(packageName) - mActivityLauncherUtils.launchApp(appIntent, true) - vibrate() - return - } + vibrate() } private fun areDataEqual( diff --git a/app/src/main/java/com/drdisagree/iconify/xposed/modules/utils/Helpers.kt b/app/src/main/java/com/drdisagree/iconify/xposed/modules/utils/Helpers.kt index b7c69c44b..987e25d49 100644 --- a/app/src/main/java/com/drdisagree/iconify/xposed/modules/utils/Helpers.kt +++ b/app/src/main/java/com/drdisagree/iconify/xposed/modules/utils/Helpers.kt @@ -226,6 +226,15 @@ object Helpers { } } + fun isFieldAvailable(clazz: Class<*>, fieldName: String): Boolean { + return try { + clazz::class.java.getDeclaredField(fieldName) + true + } catch (ignored: NoSuchFieldException) { + false + } + } + val isQsTileOverlayEnabled: Boolean get() { val output = Shell.cmd(