Loading packages/SystemUI/multivalentTests/src/com/android/systemui/media/remedia/data/repository/MediaRepositoryTest.kt +1 −0 Original line number Diff line number Diff line Loading @@ -289,6 +289,7 @@ class MediaRepositoryTest : SysuiTestCase() { resumeAction = resumeAction, isExplicit = isExplicit, suggestionData = mediaModel.suggestionData, token = session.sessionToken, ) } Loading packages/SystemUI/src/com/android/systemui/media/remedia/data/model/MediaDataModel.kt +2 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.systemui.media.remedia.data.model import android.app.PendingIntent import android.media.session.MediaSession import com.android.internal.logging.InstanceId import com.android.systemui.common.shared.model.Icon import com.android.systemui.media.controls.shared.model.MediaButton Loading Loading @@ -71,4 +72,5 @@ data class MediaDataModel( val isExplicit: Boolean, /** Device suggestions data */ val suggestionData: SuggestionData?, val token: MediaSession.Token?, ) packages/SystemUI/src/com/android/systemui/media/remedia/data/repository/MediaRepository.kt +2 −4 Original line number Diff line number Diff line Loading @@ -147,10 +147,7 @@ constructor( applicationScope.launch { val controller = if ( currentModel != null && activeControllers[currentModel.instanceId]?.sessionToken == token ) { if (currentModel != null && currentModel.token == token) { activeControllers[currentModel.instanceId] } else { // Clear controller state if changed for the same media session. Loading Loading @@ -236,6 +233,7 @@ constructor( resumeAction = resumeAction, isExplicit = isExplicit, suggestionData = suggestionData, token = token, ) } } Loading packages/SystemUI/src/com/android/systemui/media/remedia/domain/interactor/MediaInteractor.kt +62 −8 Original line number Diff line number Diff line Loading @@ -16,9 +16,12 @@ package com.android.systemui.media.remedia.domain.interactor import android.app.ActivityOptions import android.app.BroadcastOptions import android.app.PendingIntent import android.content.Context import android.content.Intent import android.media.session.MediaSession import android.provider.Settings import android.util.Log import androidx.compose.ui.graphics.ImageBitmap Loading @@ -27,6 +30,8 @@ import com.android.internal.jank.Cuj import com.android.internal.logging.InstanceId import com.android.settingslib.media.LocalMediaManager.MediaDeviceState import com.android.systemui.ActivityIntentHelper import com.android.systemui.animation.DialogCuj import com.android.systemui.animation.DialogTransitionAnimator import com.android.systemui.animation.Expandable import com.android.systemui.biometrics.Utils.toBitmap import com.android.systemui.common.shared.model.ContentDescription Loading @@ -38,6 +43,7 @@ import com.android.systemui.media.controls.domain.pipeline.MediaDataProcessor import com.android.systemui.media.controls.domain.pipeline.getNotificationActions import com.android.systemui.media.controls.shared.model.MediaAction import com.android.systemui.media.controls.shared.model.SuggestionData import com.android.systemui.media.dialog.MediaOutputDialogManager import com.android.systemui.media.remedia.data.model.MediaDataModel import com.android.systemui.media.remedia.data.repository.MediaRepository import com.android.systemui.media.remedia.domain.model.MediaActionModel Loading Loading @@ -82,6 +88,7 @@ constructor( private val activityStarter: ActivityStarter, private val activityIntentHelper: ActivityIntentHelper, private val lockscreenUserManager: NotificationLockscreenUserManager, private val mediaOutputDialogManager: MediaOutputDialogManager, ) : MediaInteractor { override val sessions: List<MediaSessionModel> Loading Loading @@ -161,6 +168,9 @@ constructor( contentDescription = null, ), isInProgress = false, onClick = { expandable -> startOutputSwitcherClick(dataModel, expandable) }, ) } Loading Loading @@ -237,6 +247,7 @@ constructor( suggestedMediaDeviceData.name, suggestedMediaDeviceData.icon.asIcon(), suggestedMediaDeviceData.connectionState == MediaDeviceState.STATE_CONNECTING, onClick = { suggestedMediaDeviceData.connect() }, ) } Loading @@ -250,7 +261,7 @@ constructor( } private fun launchOverLockscreen( expandable: Expandable, expandable: Expandable?, pendingIntent: PendingIntent, ): Boolean { val showOverLockscreen = Loading @@ -261,6 +272,7 @@ constructor( ) if (showOverLockscreen) { try { if (expandable != null) { activityStarter.startPendingIntentMaybeDismissingKeyguard( pendingIntent, /* intentSentUiThreadCallback = */ null, Loading @@ -268,6 +280,13 @@ constructor( Cuj.CUJ_SHADE_APP_LAUNCH_FROM_MEDIA_PLAYER ), ) } else { val options = BroadcastOptions.makeBasic() options.isInteractive = true options.pendingIntentBackgroundActivityStartMode = ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS pendingIntent.send(options.toBundle()) } } catch (e: PendingIntent.CanceledException) { Log.e(TAG, "pending intent was canceled") } Loading @@ -276,6 +295,41 @@ constructor( return false } private fun startOutputSwitcherClick(dataModel: MediaDataModel, expandable: Expandable) { dataModel.outputDevice?.intent?.let { startDeviceIntent(dataModel.instanceId, it) } ?: startMediaOutputDialog(expandable, dataModel.packageName, dataModel.token) } private fun startMediaOutputDialog( expandable: Expandable, packageName: String, token: MediaSession.Token? = null, ) { mediaOutputDialogManager.createAndShowWithController( packageName, true, expandable.dialogController(), token = token, ) } private fun Expandable.dialogController(): DialogTransitionAnimator.Controller? { return dialogTransitionController( cuj = DialogCuj(Cuj.CUJ_SHADE_DIALOG_OPEN, MediaOutputDialogManager.INTERACTION_JANK_TAG) ) } private fun startDeviceIntent(instanceId: InstanceId, deviceIntent: PendingIntent) { if (deviceIntent.isActivity) { if (!launchOverLockscreen(expandable = null, deviceIntent)) { activityStarter.postStartActivityDismissingKeyguard(deviceIntent) } } else { Log.w(TAG, "Device pending intent of instanceId=$instanceId is not an activity.") } } companion object { private const val TAG = "MediaInteractor" private val settingsIntent: Intent = Intent(Settings.ACTION_MEDIA_CONTROLS_SETTINGS) Loading packages/SystemUI/src/com/android/systemui/media/remedia/domain/model/MediaOutputDeviceModel.kt +7 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,12 @@ package com.android.systemui.media.remedia.domain.model import com.android.systemui.animation.Expandable import com.android.systemui.common.shared.model.Icon data class MediaOutputDeviceModel(val name: String, val icon: Icon, val isInProgress: Boolean) data class MediaOutputDeviceModel( val name: String, val icon: Icon, val isInProgress: Boolean, val onClick: (Expandable) -> Unit, ) Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/media/remedia/data/repository/MediaRepositoryTest.kt +1 −0 Original line number Diff line number Diff line Loading @@ -289,6 +289,7 @@ class MediaRepositoryTest : SysuiTestCase() { resumeAction = resumeAction, isExplicit = isExplicit, suggestionData = mediaModel.suggestionData, token = session.sessionToken, ) } Loading
packages/SystemUI/src/com/android/systemui/media/remedia/data/model/MediaDataModel.kt +2 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.systemui.media.remedia.data.model import android.app.PendingIntent import android.media.session.MediaSession import com.android.internal.logging.InstanceId import com.android.systemui.common.shared.model.Icon import com.android.systemui.media.controls.shared.model.MediaButton Loading Loading @@ -71,4 +72,5 @@ data class MediaDataModel( val isExplicit: Boolean, /** Device suggestions data */ val suggestionData: SuggestionData?, val token: MediaSession.Token?, )
packages/SystemUI/src/com/android/systemui/media/remedia/data/repository/MediaRepository.kt +2 −4 Original line number Diff line number Diff line Loading @@ -147,10 +147,7 @@ constructor( applicationScope.launch { val controller = if ( currentModel != null && activeControllers[currentModel.instanceId]?.sessionToken == token ) { if (currentModel != null && currentModel.token == token) { activeControllers[currentModel.instanceId] } else { // Clear controller state if changed for the same media session. Loading Loading @@ -236,6 +233,7 @@ constructor( resumeAction = resumeAction, isExplicit = isExplicit, suggestionData = suggestionData, token = token, ) } } Loading
packages/SystemUI/src/com/android/systemui/media/remedia/domain/interactor/MediaInteractor.kt +62 −8 Original line number Diff line number Diff line Loading @@ -16,9 +16,12 @@ package com.android.systemui.media.remedia.domain.interactor import android.app.ActivityOptions import android.app.BroadcastOptions import android.app.PendingIntent import android.content.Context import android.content.Intent import android.media.session.MediaSession import android.provider.Settings import android.util.Log import androidx.compose.ui.graphics.ImageBitmap Loading @@ -27,6 +30,8 @@ import com.android.internal.jank.Cuj import com.android.internal.logging.InstanceId import com.android.settingslib.media.LocalMediaManager.MediaDeviceState import com.android.systemui.ActivityIntentHelper import com.android.systemui.animation.DialogCuj import com.android.systemui.animation.DialogTransitionAnimator import com.android.systemui.animation.Expandable import com.android.systemui.biometrics.Utils.toBitmap import com.android.systemui.common.shared.model.ContentDescription Loading @@ -38,6 +43,7 @@ import com.android.systemui.media.controls.domain.pipeline.MediaDataProcessor import com.android.systemui.media.controls.domain.pipeline.getNotificationActions import com.android.systemui.media.controls.shared.model.MediaAction import com.android.systemui.media.controls.shared.model.SuggestionData import com.android.systemui.media.dialog.MediaOutputDialogManager import com.android.systemui.media.remedia.data.model.MediaDataModel import com.android.systemui.media.remedia.data.repository.MediaRepository import com.android.systemui.media.remedia.domain.model.MediaActionModel Loading Loading @@ -82,6 +88,7 @@ constructor( private val activityStarter: ActivityStarter, private val activityIntentHelper: ActivityIntentHelper, private val lockscreenUserManager: NotificationLockscreenUserManager, private val mediaOutputDialogManager: MediaOutputDialogManager, ) : MediaInteractor { override val sessions: List<MediaSessionModel> Loading Loading @@ -161,6 +168,9 @@ constructor( contentDescription = null, ), isInProgress = false, onClick = { expandable -> startOutputSwitcherClick(dataModel, expandable) }, ) } Loading Loading @@ -237,6 +247,7 @@ constructor( suggestedMediaDeviceData.name, suggestedMediaDeviceData.icon.asIcon(), suggestedMediaDeviceData.connectionState == MediaDeviceState.STATE_CONNECTING, onClick = { suggestedMediaDeviceData.connect() }, ) } Loading @@ -250,7 +261,7 @@ constructor( } private fun launchOverLockscreen( expandable: Expandable, expandable: Expandable?, pendingIntent: PendingIntent, ): Boolean { val showOverLockscreen = Loading @@ -261,6 +272,7 @@ constructor( ) if (showOverLockscreen) { try { if (expandable != null) { activityStarter.startPendingIntentMaybeDismissingKeyguard( pendingIntent, /* intentSentUiThreadCallback = */ null, Loading @@ -268,6 +280,13 @@ constructor( Cuj.CUJ_SHADE_APP_LAUNCH_FROM_MEDIA_PLAYER ), ) } else { val options = BroadcastOptions.makeBasic() options.isInteractive = true options.pendingIntentBackgroundActivityStartMode = ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS pendingIntent.send(options.toBundle()) } } catch (e: PendingIntent.CanceledException) { Log.e(TAG, "pending intent was canceled") } Loading @@ -276,6 +295,41 @@ constructor( return false } private fun startOutputSwitcherClick(dataModel: MediaDataModel, expandable: Expandable) { dataModel.outputDevice?.intent?.let { startDeviceIntent(dataModel.instanceId, it) } ?: startMediaOutputDialog(expandable, dataModel.packageName, dataModel.token) } private fun startMediaOutputDialog( expandable: Expandable, packageName: String, token: MediaSession.Token? = null, ) { mediaOutputDialogManager.createAndShowWithController( packageName, true, expandable.dialogController(), token = token, ) } private fun Expandable.dialogController(): DialogTransitionAnimator.Controller? { return dialogTransitionController( cuj = DialogCuj(Cuj.CUJ_SHADE_DIALOG_OPEN, MediaOutputDialogManager.INTERACTION_JANK_TAG) ) } private fun startDeviceIntent(instanceId: InstanceId, deviceIntent: PendingIntent) { if (deviceIntent.isActivity) { if (!launchOverLockscreen(expandable = null, deviceIntent)) { activityStarter.postStartActivityDismissingKeyguard(deviceIntent) } } else { Log.w(TAG, "Device pending intent of instanceId=$instanceId is not an activity.") } } companion object { private const val TAG = "MediaInteractor" private val settingsIntent: Intent = Intent(Settings.ACTION_MEDIA_CONTROLS_SETTINGS) Loading
packages/SystemUI/src/com/android/systemui/media/remedia/domain/model/MediaOutputDeviceModel.kt +7 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,12 @@ package com.android.systemui.media.remedia.domain.model import com.android.systemui.animation.Expandable import com.android.systemui.common.shared.model.Icon data class MediaOutputDeviceModel(val name: String, val icon: Icon, val isInProgress: Boolean) data class MediaOutputDeviceModel( val name: String, val icon: Icon, val isInProgress: Boolean, val onClick: (Expandable) -> Unit, )