Loading packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModelTest.kt +139 −1 Original line number Diff line number Diff line Loading @@ -21,9 +21,12 @@ import android.content.pm.ApplicationInfo import android.media.MediaMetadata import android.media.session.MediaSession import android.media.session.PlaybackState import android.platform.test.annotations.EnableFlags import androidx.constraintlayout.widget.ConstraintSet import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.settingslib.media.LocalMediaManager.MediaDeviceState import com.android.systemui.Flags.FLAG_ENABLE_SUGGESTED_DEVICE_UI import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.kosmos.testScope Loading @@ -31,6 +34,8 @@ import com.android.systemui.media.controls.domain.pipeline.mediaDataFilter import com.android.systemui.media.controls.shared.model.MediaButton import com.android.systemui.media.controls.shared.model.MediaData import com.android.systemui.media.controls.shared.model.MediaDeviceData import com.android.systemui.media.controls.shared.model.SuggestedMediaDeviceData import com.android.systemui.media.controls.shared.model.SuggestionData import com.android.systemui.media.controls.util.mediaInstanceId import com.android.systemui.res.R import com.android.systemui.statusbar.notificationLockscreenUserManager Loading Loading @@ -159,7 +164,127 @@ class MediaControlViewModelTest : SysuiTestCase() { assertThat(nextButton.isVisibleWhenScrubbing).isEqualTo(false) } private fun initMediaData(artist: String, title: String): MediaData { @EnableFlags(FLAG_ENABLE_SUGGESTED_DEVICE_UI) @Test fun onMediaDataLoadedWithNoSuggestionData() = testScope.runTest { val playerModel by collectLastValue(underTest.player) val mediaData = initMediaData(artist = ARTIST, title = TITLE, suggestionData = null) mediaDataFilter.onMediaDataLoaded(KEY, KEY, mediaData) val suggestionModel = playerModel!!.deviceSuggestion assertThat(suggestionModel.isValidSuggestion).isFalse() assertThat(suggestionModel.buttonText).isNull() assertThat(suggestionModel.onClicked).isNull() assertThat(suggestionModel.isConnecting).isFalse() assertThat(suggestionModel.icon).isNull() } @EnableFlags(FLAG_ENABLE_SUGGESTED_DEVICE_UI) @Test fun onMediaDataLoadedWithConnectingSuggestionData() = testScope.runTest { val playerModel by collectLastValue(underTest.player) val mediaData = initMediaData( artist = ARTIST, title = TITLE, suggestionData = createSuggestionData(DEVICE_NAME, MediaDeviceState.STATE_CONNECTING), ) mediaDataFilter.onMediaDataLoaded(KEY, KEY, mediaData) val suggestionModel = playerModel!!.deviceSuggestion assertThat(suggestionModel.isValidSuggestion).isTrue() assertThat(suggestionModel.buttonText) .isEqualTo( context.getString(R.string.media_suggestion_disconnected_text, DEVICE_NAME) ) assertThat(suggestionModel.onClicked).isNull() assertThat(suggestionModel.isConnecting).isTrue() assertThat(suggestionModel.icon).isNotNull() } @EnableFlags(FLAG_ENABLE_SUGGESTED_DEVICE_UI) @Test fun onMediaDataLoadedWithDisconnectedSuggestionData() = testScope.runTest { val playerModel by collectLastValue(underTest.player) val mediaData = initMediaData( artist = ARTIST, title = TITLE, suggestionData = createSuggestionData(DEVICE_NAME, MediaDeviceState.STATE_DISCONNECTED), ) mediaDataFilter.onMediaDataLoaded(KEY, KEY, mediaData) val suggestionModel = playerModel!!.deviceSuggestion assertThat(suggestionModel.isValidSuggestion).isTrue() assertThat(suggestionModel.buttonText) .isEqualTo( context.getString(R.string.media_suggestion_disconnected_text, DEVICE_NAME) ) assertThat(suggestionModel.onClicked).isNotNull() assertThat(suggestionModel.isConnecting).isFalse() assertThat(suggestionModel.icon).isNotNull() } @EnableFlags(FLAG_ENABLE_SUGGESTED_DEVICE_UI) @Test fun onMediaDataLoadedWithErrorSuggestionData() = testScope.runTest { val playerModel by collectLastValue(underTest.player) val mediaData = initMediaData( artist = ARTIST, title = TITLE, suggestionData = createSuggestionData(DEVICE_NAME, MediaDeviceState.STATE_CONNECTING_FAILED), ) mediaDataFilter.onMediaDataLoaded(KEY, KEY, mediaData) val suggestionModel = playerModel!!.deviceSuggestion assertThat(suggestionModel.isValidSuggestion).isTrue() assertThat(suggestionModel.buttonText) .isEqualTo(context.getString(R.string.media_suggestion_failure_text)) assertThat(suggestionModel.onClicked).isNotNull() assertThat(suggestionModel.isConnecting).isFalse() assertThat(suggestionModel.icon).isNotNull() } @EnableFlags(FLAG_ENABLE_SUGGESTED_DEVICE_UI) @Test fun onMediaDataLoadedWithConnectedSuggestionData() = testScope.runTest { val playerModel by collectLastValue(underTest.player) val mediaData = initMediaData( artist = ARTIST, title = TITLE, suggestionData = createSuggestionData(DEVICE_NAME, MediaDeviceState.STATE_CONNECTED), ) mediaDataFilter.onMediaDataLoaded(KEY, KEY, mediaData) val suggestionModel = playerModel!!.deviceSuggestion assertThat(suggestionModel.isValidSuggestion).isFalse() assertThat(suggestionModel.buttonText).isNull() assertThat(suggestionModel.onClicked).isNull() assertThat(suggestionModel.isConnecting).isFalse() assertThat(suggestionModel.icon).isNull() } private fun initMediaData( artist: String, title: String, suggestionData: SuggestionData? = null, ): MediaData { val device = MediaDeviceData(true, null, DEVICE_NAME, null, showBroadcastButton = true) // Create media session Loading Loading @@ -187,10 +312,23 @@ class MediaControlViewModelTest : SysuiTestCase() { packageName = PACKAGE, token = session.sessionToken, device = device, suggestionData = suggestionData, instanceId = instanceId, ) } private fun createSuggestionData(deviceName: String, state: Int) = SuggestionData( suggestedMediaDeviceData = SuggestedMediaDeviceData( name = deviceName, icon = drawable!!, connectionState = state, connect = {}, ), onSuggestionSpaceVisible = Runnable {}, ) companion object { private const val USER_ID = 0 private const val KEY = "key" Loading packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt +1 −0 Original line number Diff line number Diff line Loading @@ -98,6 +98,7 @@ constructor( showExplicit = isExplicit, artwork = artwork, deviceData = device, suggestionData = suggestionData, semanticActionButtons = semanticActions, notificationActionButtons = getNotificationActions(data.actions, activityStarter), actionsToShowInCollapsed = actionsToShowInCompact, Loading packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaControlModel.kt +1 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ data class MediaControlModel( val showExplicit: Boolean, val artwork: Icon?, val deviceData: MediaDeviceData?, val suggestionData: SuggestionData?, /** [MediaButton] contains [MediaAction] objects which represent specific buttons in the UI */ val semanticActionButtons: MediaButton?, val notificationActionButtons: List<MediaAction>, Loading packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaControlViewBinder.kt +33 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle import com.android.app.tracing.coroutines.launchTraced as launch import com.android.settingslib.widget.AdaptiveIcon import com.android.systemui.Flags.enableSuggestedDeviceUi import com.android.systemui.animation.Expandable import com.android.systemui.common.shared.model.Icon import com.android.systemui.dagger.qualifiers.Background Loading @@ -54,6 +55,7 @@ import com.android.systemui.media.controls.ui.viewmodel.MediaControlViewModel.Co import com.android.systemui.media.controls.ui.viewmodel.MediaControlViewModel.Companion.SEMANTIC_ACTIONS_COMPACT import com.android.systemui.media.controls.ui.viewmodel.MediaOutputSwitcherViewModel import com.android.systemui.media.controls.ui.viewmodel.MediaPlayerViewModel import com.android.systemui.media.controls.ui.viewmodel.MediaSuggestionViewModel import com.android.systemui.media.controls.util.MediaDataUtils import com.android.systemui.monet.ColorScheme import com.android.systemui.monet.Style Loading Loading @@ -154,6 +156,7 @@ object MediaControlViewBinder { bindGutsViewModel(viewHolder, viewModel, viewController, falsingManager) bindActionButtons(viewHolder, viewModel, viewController, falsingManager) bindScrubbingTime(viewHolder, viewModel, viewController) bindSuggestionModel(viewHolder, viewModel.deviceSuggestion) val isSongUpdated = bindSongMetadata(viewHolder, viewModel, viewController) Loading Loading @@ -210,6 +213,36 @@ object MediaControlViewBinder { viewHolder.seamlessText.text = viewModel.deviceString } private fun bindSuggestionModel( viewHolder: MediaViewHolder, viewModel: MediaSuggestionViewModel, ) { if (!enableSuggestedDeviceUi()) { return } with(viewHolder) { if (!viewModel.isValidSuggestion) { deviceSuggestionButton.visibility = View.GONE seamlessText.visibility = View.VISIBLE return } seamlessText.visibility = View.GONE deviceSuggestionButton.visibility = View.VISIBLE deviceSuggestionButton.setClickable(viewModel.onClicked != null) deviceSuggestionButton.setOnClickListener { viewModel.onClicked?.invoke() } deviceSuggestionText.text = viewModel.buttonText if (viewModel.isConnecting) { deviceSuggestionConnectingIcon.visibility = View.VISIBLE deviceSuggestionIcon.visibility = View.GONE } else { deviceSuggestionIcon.setImageDrawable(viewModel.icon?.drawable) deviceSuggestionConnectingIcon.visibility = View.GONE deviceSuggestionIcon.visibility = View.VISIBLE } } } private fun bindGutsViewModel( viewHolder: MediaViewHolder, viewModel: MediaPlayerViewModel, Loading packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt +60 −0 Original line number Diff line number Diff line Loading @@ -26,7 +26,10 @@ import android.util.Log import androidx.constraintlayout.widget.ConstraintSet import com.android.internal.logging.InstanceId import com.android.settingslib.flags.Flags.legacyLeAudioSharing import com.android.settingslib.media.LocalMediaManager.MediaDeviceState import com.android.systemui.Flags.enableSuggestedDeviceUi import com.android.systemui.common.shared.model.Icon import com.android.systemui.common.shared.model.asIcon import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.media.controls.domain.pipeline.interactor.MediaControlInteractor Loading Loading @@ -134,6 +137,7 @@ data class MediaControlViewModel( useSemanticActions = model.semanticActionButtons != null, actionButtons = toActionViewModels(model), outputSwitcher = toOutputSwitcherViewModel(model), deviceSuggestion = toSuggestionViewModel(model), gutsMenu = gutsViewModel, onClicked = { expandable -> model.clickIntent?.let { clickIntent -> Loading Loading @@ -241,6 +245,62 @@ data class MediaControlViewModel( ) } private fun toSuggestionViewModel(model: MediaControlModel): MediaSuggestionViewModel { if (!enableSuggestedDeviceUi()) { return MediaSuggestionViewModel(isValidSuggestion = false) } val suggestionData = model.suggestionData ?: return MediaSuggestionViewModel(isValidSuggestion = false) suggestionData.onSuggestionSpaceVisible.run() val suggestedDeviceData = suggestionData.suggestedMediaDeviceData ?: return MediaSuggestionViewModel(isValidSuggestion = false) with(suggestedDeviceData) { // Don't show the device as suggested if we're already connected to it if ( !(connectionState == MediaDeviceState.STATE_DISCONNECTED || connectionState == MediaDeviceState.STATE_CONNECTING || connectionState == MediaDeviceState.STATE_GROUPING || connectionState == MediaDeviceState.STATE_CONNECTING_FAILED) ) { return MediaSuggestionViewModel(isValidSuggestion = false) } val onClick = if ( connectionState == MediaDeviceState.STATE_DISCONNECTED || connectionState == MediaDeviceState.STATE_CONNECTING_FAILED ) ({ connect() }) else null val buttonText = when (connectionState) { MediaDeviceState.STATE_DISCONNECTED, MediaDeviceState.STATE_CONNECTING, MediaDeviceState.STATE_GROUPING -> applicationContext.getString( R.string.media_suggestion_disconnected_text, name, ) MediaDeviceState.STATE_CONNECTING_FAILED -> applicationContext.getString(R.string.media_suggestion_failure_text) else -> { Log.wtf(TAG, "Invalid media device state for suggestion: $connectionState") null } } val isConnecting = connectionState == MediaDeviceState.STATE_CONNECTING || connectionState == MediaDeviceState.STATE_GROUPING return MediaSuggestionViewModel( isValidSuggestion = true, onClicked = onClick, buttonText = buttonText, isConnecting = isConnecting, icon = icon?.asIcon(), ) } } private fun toGutsViewModel(model: MediaControlModel): GutsViewModel { return GutsViewModel( gutsText = Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModelTest.kt +139 −1 Original line number Diff line number Diff line Loading @@ -21,9 +21,12 @@ import android.content.pm.ApplicationInfo import android.media.MediaMetadata import android.media.session.MediaSession import android.media.session.PlaybackState import android.platform.test.annotations.EnableFlags import androidx.constraintlayout.widget.ConstraintSet import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.settingslib.media.LocalMediaManager.MediaDeviceState import com.android.systemui.Flags.FLAG_ENABLE_SUGGESTED_DEVICE_UI import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.kosmos.testScope Loading @@ -31,6 +34,8 @@ import com.android.systemui.media.controls.domain.pipeline.mediaDataFilter import com.android.systemui.media.controls.shared.model.MediaButton import com.android.systemui.media.controls.shared.model.MediaData import com.android.systemui.media.controls.shared.model.MediaDeviceData import com.android.systemui.media.controls.shared.model.SuggestedMediaDeviceData import com.android.systemui.media.controls.shared.model.SuggestionData import com.android.systemui.media.controls.util.mediaInstanceId import com.android.systemui.res.R import com.android.systemui.statusbar.notificationLockscreenUserManager Loading Loading @@ -159,7 +164,127 @@ class MediaControlViewModelTest : SysuiTestCase() { assertThat(nextButton.isVisibleWhenScrubbing).isEqualTo(false) } private fun initMediaData(artist: String, title: String): MediaData { @EnableFlags(FLAG_ENABLE_SUGGESTED_DEVICE_UI) @Test fun onMediaDataLoadedWithNoSuggestionData() = testScope.runTest { val playerModel by collectLastValue(underTest.player) val mediaData = initMediaData(artist = ARTIST, title = TITLE, suggestionData = null) mediaDataFilter.onMediaDataLoaded(KEY, KEY, mediaData) val suggestionModel = playerModel!!.deviceSuggestion assertThat(suggestionModel.isValidSuggestion).isFalse() assertThat(suggestionModel.buttonText).isNull() assertThat(suggestionModel.onClicked).isNull() assertThat(suggestionModel.isConnecting).isFalse() assertThat(suggestionModel.icon).isNull() } @EnableFlags(FLAG_ENABLE_SUGGESTED_DEVICE_UI) @Test fun onMediaDataLoadedWithConnectingSuggestionData() = testScope.runTest { val playerModel by collectLastValue(underTest.player) val mediaData = initMediaData( artist = ARTIST, title = TITLE, suggestionData = createSuggestionData(DEVICE_NAME, MediaDeviceState.STATE_CONNECTING), ) mediaDataFilter.onMediaDataLoaded(KEY, KEY, mediaData) val suggestionModel = playerModel!!.deviceSuggestion assertThat(suggestionModel.isValidSuggestion).isTrue() assertThat(suggestionModel.buttonText) .isEqualTo( context.getString(R.string.media_suggestion_disconnected_text, DEVICE_NAME) ) assertThat(suggestionModel.onClicked).isNull() assertThat(suggestionModel.isConnecting).isTrue() assertThat(suggestionModel.icon).isNotNull() } @EnableFlags(FLAG_ENABLE_SUGGESTED_DEVICE_UI) @Test fun onMediaDataLoadedWithDisconnectedSuggestionData() = testScope.runTest { val playerModel by collectLastValue(underTest.player) val mediaData = initMediaData( artist = ARTIST, title = TITLE, suggestionData = createSuggestionData(DEVICE_NAME, MediaDeviceState.STATE_DISCONNECTED), ) mediaDataFilter.onMediaDataLoaded(KEY, KEY, mediaData) val suggestionModel = playerModel!!.deviceSuggestion assertThat(suggestionModel.isValidSuggestion).isTrue() assertThat(suggestionModel.buttonText) .isEqualTo( context.getString(R.string.media_suggestion_disconnected_text, DEVICE_NAME) ) assertThat(suggestionModel.onClicked).isNotNull() assertThat(suggestionModel.isConnecting).isFalse() assertThat(suggestionModel.icon).isNotNull() } @EnableFlags(FLAG_ENABLE_SUGGESTED_DEVICE_UI) @Test fun onMediaDataLoadedWithErrorSuggestionData() = testScope.runTest { val playerModel by collectLastValue(underTest.player) val mediaData = initMediaData( artist = ARTIST, title = TITLE, suggestionData = createSuggestionData(DEVICE_NAME, MediaDeviceState.STATE_CONNECTING_FAILED), ) mediaDataFilter.onMediaDataLoaded(KEY, KEY, mediaData) val suggestionModel = playerModel!!.deviceSuggestion assertThat(suggestionModel.isValidSuggestion).isTrue() assertThat(suggestionModel.buttonText) .isEqualTo(context.getString(R.string.media_suggestion_failure_text)) assertThat(suggestionModel.onClicked).isNotNull() assertThat(suggestionModel.isConnecting).isFalse() assertThat(suggestionModel.icon).isNotNull() } @EnableFlags(FLAG_ENABLE_SUGGESTED_DEVICE_UI) @Test fun onMediaDataLoadedWithConnectedSuggestionData() = testScope.runTest { val playerModel by collectLastValue(underTest.player) val mediaData = initMediaData( artist = ARTIST, title = TITLE, suggestionData = createSuggestionData(DEVICE_NAME, MediaDeviceState.STATE_CONNECTED), ) mediaDataFilter.onMediaDataLoaded(KEY, KEY, mediaData) val suggestionModel = playerModel!!.deviceSuggestion assertThat(suggestionModel.isValidSuggestion).isFalse() assertThat(suggestionModel.buttonText).isNull() assertThat(suggestionModel.onClicked).isNull() assertThat(suggestionModel.isConnecting).isFalse() assertThat(suggestionModel.icon).isNull() } private fun initMediaData( artist: String, title: String, suggestionData: SuggestionData? = null, ): MediaData { val device = MediaDeviceData(true, null, DEVICE_NAME, null, showBroadcastButton = true) // Create media session Loading Loading @@ -187,10 +312,23 @@ class MediaControlViewModelTest : SysuiTestCase() { packageName = PACKAGE, token = session.sessionToken, device = device, suggestionData = suggestionData, instanceId = instanceId, ) } private fun createSuggestionData(deviceName: String, state: Int) = SuggestionData( suggestedMediaDeviceData = SuggestedMediaDeviceData( name = deviceName, icon = drawable!!, connectionState = state, connect = {}, ), onSuggestionSpaceVisible = Runnable {}, ) companion object { private const val USER_ID = 0 private const val KEY = "key" Loading
packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt +1 −0 Original line number Diff line number Diff line Loading @@ -98,6 +98,7 @@ constructor( showExplicit = isExplicit, artwork = artwork, deviceData = device, suggestionData = suggestionData, semanticActionButtons = semanticActions, notificationActionButtons = getNotificationActions(data.actions, activityStarter), actionsToShowInCollapsed = actionsToShowInCompact, Loading
packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaControlModel.kt +1 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ data class MediaControlModel( val showExplicit: Boolean, val artwork: Icon?, val deviceData: MediaDeviceData?, val suggestionData: SuggestionData?, /** [MediaButton] contains [MediaAction] objects which represent specific buttons in the UI */ val semanticActionButtons: MediaButton?, val notificationActionButtons: List<MediaAction>, Loading
packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaControlViewBinder.kt +33 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle import com.android.app.tracing.coroutines.launchTraced as launch import com.android.settingslib.widget.AdaptiveIcon import com.android.systemui.Flags.enableSuggestedDeviceUi import com.android.systemui.animation.Expandable import com.android.systemui.common.shared.model.Icon import com.android.systemui.dagger.qualifiers.Background Loading @@ -54,6 +55,7 @@ import com.android.systemui.media.controls.ui.viewmodel.MediaControlViewModel.Co import com.android.systemui.media.controls.ui.viewmodel.MediaControlViewModel.Companion.SEMANTIC_ACTIONS_COMPACT import com.android.systemui.media.controls.ui.viewmodel.MediaOutputSwitcherViewModel import com.android.systemui.media.controls.ui.viewmodel.MediaPlayerViewModel import com.android.systemui.media.controls.ui.viewmodel.MediaSuggestionViewModel import com.android.systemui.media.controls.util.MediaDataUtils import com.android.systemui.monet.ColorScheme import com.android.systemui.monet.Style Loading Loading @@ -154,6 +156,7 @@ object MediaControlViewBinder { bindGutsViewModel(viewHolder, viewModel, viewController, falsingManager) bindActionButtons(viewHolder, viewModel, viewController, falsingManager) bindScrubbingTime(viewHolder, viewModel, viewController) bindSuggestionModel(viewHolder, viewModel.deviceSuggestion) val isSongUpdated = bindSongMetadata(viewHolder, viewModel, viewController) Loading Loading @@ -210,6 +213,36 @@ object MediaControlViewBinder { viewHolder.seamlessText.text = viewModel.deviceString } private fun bindSuggestionModel( viewHolder: MediaViewHolder, viewModel: MediaSuggestionViewModel, ) { if (!enableSuggestedDeviceUi()) { return } with(viewHolder) { if (!viewModel.isValidSuggestion) { deviceSuggestionButton.visibility = View.GONE seamlessText.visibility = View.VISIBLE return } seamlessText.visibility = View.GONE deviceSuggestionButton.visibility = View.VISIBLE deviceSuggestionButton.setClickable(viewModel.onClicked != null) deviceSuggestionButton.setOnClickListener { viewModel.onClicked?.invoke() } deviceSuggestionText.text = viewModel.buttonText if (viewModel.isConnecting) { deviceSuggestionConnectingIcon.visibility = View.VISIBLE deviceSuggestionIcon.visibility = View.GONE } else { deviceSuggestionIcon.setImageDrawable(viewModel.icon?.drawable) deviceSuggestionConnectingIcon.visibility = View.GONE deviceSuggestionIcon.visibility = View.VISIBLE } } } private fun bindGutsViewModel( viewHolder: MediaViewHolder, viewModel: MediaPlayerViewModel, Loading
packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaControlViewModel.kt +60 −0 Original line number Diff line number Diff line Loading @@ -26,7 +26,10 @@ import android.util.Log import androidx.constraintlayout.widget.ConstraintSet import com.android.internal.logging.InstanceId import com.android.settingslib.flags.Flags.legacyLeAudioSharing import com.android.settingslib.media.LocalMediaManager.MediaDeviceState import com.android.systemui.Flags.enableSuggestedDeviceUi import com.android.systemui.common.shared.model.Icon import com.android.systemui.common.shared.model.asIcon import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.media.controls.domain.pipeline.interactor.MediaControlInteractor Loading Loading @@ -134,6 +137,7 @@ data class MediaControlViewModel( useSemanticActions = model.semanticActionButtons != null, actionButtons = toActionViewModels(model), outputSwitcher = toOutputSwitcherViewModel(model), deviceSuggestion = toSuggestionViewModel(model), gutsMenu = gutsViewModel, onClicked = { expandable -> model.clickIntent?.let { clickIntent -> Loading Loading @@ -241,6 +245,62 @@ data class MediaControlViewModel( ) } private fun toSuggestionViewModel(model: MediaControlModel): MediaSuggestionViewModel { if (!enableSuggestedDeviceUi()) { return MediaSuggestionViewModel(isValidSuggestion = false) } val suggestionData = model.suggestionData ?: return MediaSuggestionViewModel(isValidSuggestion = false) suggestionData.onSuggestionSpaceVisible.run() val suggestedDeviceData = suggestionData.suggestedMediaDeviceData ?: return MediaSuggestionViewModel(isValidSuggestion = false) with(suggestedDeviceData) { // Don't show the device as suggested if we're already connected to it if ( !(connectionState == MediaDeviceState.STATE_DISCONNECTED || connectionState == MediaDeviceState.STATE_CONNECTING || connectionState == MediaDeviceState.STATE_GROUPING || connectionState == MediaDeviceState.STATE_CONNECTING_FAILED) ) { return MediaSuggestionViewModel(isValidSuggestion = false) } val onClick = if ( connectionState == MediaDeviceState.STATE_DISCONNECTED || connectionState == MediaDeviceState.STATE_CONNECTING_FAILED ) ({ connect() }) else null val buttonText = when (connectionState) { MediaDeviceState.STATE_DISCONNECTED, MediaDeviceState.STATE_CONNECTING, MediaDeviceState.STATE_GROUPING -> applicationContext.getString( R.string.media_suggestion_disconnected_text, name, ) MediaDeviceState.STATE_CONNECTING_FAILED -> applicationContext.getString(R.string.media_suggestion_failure_text) else -> { Log.wtf(TAG, "Invalid media device state for suggestion: $connectionState") null } } val isConnecting = connectionState == MediaDeviceState.STATE_CONNECTING || connectionState == MediaDeviceState.STATE_GROUPING return MediaSuggestionViewModel( isValidSuggestion = true, onClicked = onClick, buttonText = buttonText, isConnecting = isConnecting, icon = icon?.asIcon(), ) } } private fun toGutsViewModel(model: MediaControlModel): GutsViewModel { return GutsViewModel( gutsText = Loading