diff --git a/packages/SystemUI/res/layout/media_session_view.xml b/packages/SystemUI/res/layout/media_session_view.xml
index 51d160892a013..978998d6ca2c7 100644
--- a/packages/SystemUI/res/layout/media_session_view.xml
+++ b/packages/SystemUI/res/layout/media_session_view.xml
@@ -29,14 +29,14 @@
android:theme="@style/MediaPlayer">
+ android:layout_marginBottom="0dp" />
+ app:layout_constraintHorizontal_bias="1"
+ app:layout_constraintHorizontal_chainStyle="packed" />
@@ -188,11 +182,7 @@
android:layout_marginBottom="0dp"
android:layout_marginTop="0dp"
android:layout_marginStart="0dp"
- android:layout_marginEnd="0dp"
- app:layout_constraintStart_toEndOf="@id/actionPrev"
- app:layout_constraintEnd_toStartOf="@id/actionNext"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+ android:layout_marginEnd="0dp" />
+ android:layout_marginTop="0dp" />
+ android:layout_marginTop="0dp" />
+ app:layout_constraintHorizontal_chainStyle="packed" />
4
+
+ false
+
left;back,home,recent;right
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 079f5d0a28051..1ae3d362cd6e2 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -102,6 +102,9 @@
- one_handed_mode_enabled:onehanded
+
+ true
+
false
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index dba7290dba09c..fdb56314bcaad 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -990,6 +990,8 @@
15dp
16dp
+ 184dp
+ 128dp
72dp
diff --git a/packages/SystemUI/res/xml/media_session_collapsed.xml b/packages/SystemUI/res/xml/media_session_collapsed.xml
new file mode 100644
index 0000000000000..c6e18a6f8740c
--- /dev/null
+++ b/packages/SystemUI/res/xml/media_session_collapsed.xml
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/SystemUI/res/xml/media_session_expanded.xml b/packages/SystemUI/res/xml/media_session_expanded.xml
new file mode 100644
index 0000000000000..18ec7aa4cab4c
--- /dev/null
+++ b/packages/SystemUI/res/xml/media_session_expanded.xml
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt b/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
index 48f48266fda57..c3f4ce9865969 100644
--- a/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
@@ -45,7 +45,8 @@ class KeyguardMediaController @Inject constructor(
private val statusBarStateController: SysuiStatusBarStateController,
private val notifLockscreenUserManager: NotificationLockscreenUserManager,
private val context: Context,
- configurationController: ConfigurationController
+ configurationController: ConfigurationController,
+ private val mediaFlags: MediaFlags
) {
init {
@@ -61,7 +62,11 @@ class KeyguardMediaController @Inject constructor(
})
// First let's set the desired state that we want for this host
- mediaHost.expansion = MediaHostState.COLLAPSED
+ mediaHost.expansion = if (mediaFlags.useMediaSessionLayout()) {
+ MediaHostState.EXPANDED
+ } else {
+ MediaHostState.COLLAPSED
+ }
mediaHost.showsOnlyActiveMedia = true
mediaHost.falsingProtectionNeeded = true
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
index 791a312f341e4..591aad1014bd0 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
@@ -471,14 +471,16 @@ class MediaViewController @Inject constructor(
private fun updateMediaViewControllerType(type: TYPE) {
this.type = type
+
+ // These XML resources contain ConstraintSets that will apply to this player type's layout
when (type) {
TYPE.PLAYER -> {
collapsedLayout.load(context, R.xml.media_collapsed)
expandedLayout.load(context, R.xml.media_expanded)
}
TYPE.PLAYER_SESSION -> {
- collapsedLayout.clone(context, R.layout.media_session_view)
- expandedLayout.clone(context, R.layout.media_session_view)
+ collapsedLayout.load(context, R.xml.media_session_collapsed)
+ expandedLayout.load(context, R.xml.media_session_expanded)
}
TYPE.RECOMMENDATION -> {
collapsedLayout.load(context, R.xml.media_recommendation_collapsed)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
index 2d2fa1f08452e..a3af0e58c43d7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
@@ -17,12 +17,16 @@
package com.android.systemui.qs;
import static com.android.systemui.media.dagger.MediaModule.QUICK_QS_PANEL;
+import static com.android.systemui.qs.dagger.QSFragmentModule.QS_USING_COLLAPSED_LANDSCAPE_MEDIA;
import static com.android.systemui.qs.dagger.QSFragmentModule.QS_USING_MEDIA_PLAYER;
+import androidx.annotation.VisibleForTesting;
+
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
import com.android.systemui.dump.DumpManager;
+import com.android.systemui.media.MediaFlags;
import com.android.systemui.media.MediaHierarchyManager;
import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.qs.QSTile;
@@ -31,6 +35,7 @@ import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.settings.brightness.BrightnessMirrorHandler;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
+import com.android.systemui.util.leak.RotationUtils;
import java.util.ArrayList;
import java.util.List;
@@ -54,11 +59,16 @@ public class QuickQSPanelController extends QSPanelControllerBase
private final QuickQSBrightnessController mBrightnessController;
private final BrightnessMirrorHandler mBrightnessMirrorHandler;
+ private final MediaFlags mMediaFlags;
+ private final boolean mUsingCollapsedLandscapeMedia;
+
@Inject
QuickQSPanelController(QuickQSPanel view, QSTileHost qsTileHost,
QSCustomizerController qsCustomizerController,
@Named(QS_USING_MEDIA_PLAYER) boolean usingMediaPlayer,
@Named(QUICK_QS_PANEL) MediaHost mediaHost,
+ @Named(QS_USING_COLLAPSED_LANDSCAPE_MEDIA) boolean usingCollapsedLandscapeMedia,
+ MediaFlags mediaFlags,
MetricsLogger metricsLogger, UiEventLogger uiEventLogger, QSLogger qsLogger,
DumpManager dumpManager,
QuickQSBrightnessController quickQSBrightnessController
@@ -67,17 +77,36 @@ public class QuickQSPanelController extends QSPanelControllerBase
uiEventLogger, qsLogger, dumpManager);
mBrightnessController = quickQSBrightnessController;
mBrightnessMirrorHandler = new BrightnessMirrorHandler(mBrightnessController);
+ mUsingCollapsedLandscapeMedia = usingCollapsedLandscapeMedia;
+ mMediaFlags = mediaFlags;
}
@Override
protected void onInit() {
super.onInit();
- mMediaHost.setExpansion(0.0f);
+ updateMediaExpansion();
mMediaHost.setShowsOnlyActiveMedia(true);
mMediaHost.init(MediaHierarchyManager.LOCATION_QQS);
mBrightnessController.init(mShouldUseSplitNotificationShade);
}
+ private void updateMediaExpansion() {
+ int rotation = getRotation();
+ boolean isLandscape = rotation == RotationUtils.ROTATION_LANDSCAPE
+ || rotation == RotationUtils.ROTATION_SEASCAPE;
+ if (mMediaFlags.useMediaSessionLayout()
+ && (!mUsingCollapsedLandscapeMedia || !isLandscape)) {
+ mMediaHost.setExpansion(MediaHost.EXPANDED);
+ } else {
+ mMediaHost.setExpansion(MediaHost.COLLAPSED);
+ }
+ }
+
+ @VisibleForTesting
+ protected int getRotation() {
+ return RotationUtils.getRotation(getContext());
+ }
+
@Override
protected void onViewAttached() {
super.onViewAttached();
@@ -116,6 +145,7 @@ public class QuickQSPanelController extends QSPanelControllerBase
@Override
protected void onConfigurationChanged() {
mBrightnessController.refreshVisibility(mShouldUseSplitNotificationShade);
+ updateMediaExpansion();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
index 776ee1021db28..fdf9ae0d4b635 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
@@ -16,6 +16,7 @@
package com.android.systemui.qs.dagger;
+import static com.android.systemui.util.Utils.useCollapsedMediaInLandscape;
import static com.android.systemui.util.Utils.useQsMediaPlayer;
import android.content.Context;
@@ -56,6 +57,7 @@ public interface QSFragmentModule {
String QS_FGS_MANAGER_FOOTER_VIEW = "qs_fgs_manager_footer";
String QS_SECURITY_FOOTER_VIEW = "qs_security_footer";
String QS_USING_MEDIA_PLAYER = "qs_using_media_player";
+ String QS_USING_COLLAPSED_LANDSCAPE_MEDIA = "qs_using_collapsed_landscape_media";
/**
* Provide a context themed using the QS theme
@@ -171,6 +173,13 @@ public interface QSFragmentModule {
return useQsMediaPlayer(context);
}
+ /** */
+ @Provides
+ @Named(QS_USING_COLLAPSED_LANDSCAPE_MEDIA)
+ static boolean providesQSUsingCollapsedLandscapeMedia(Context context) {
+ return useCollapsedMediaInLandscape(context.getResources());
+ }
+
/** */
@Provides
@QSScope
diff --git a/packages/SystemUI/src/com/android/systemui/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java
index 407dc5e2787a7..71d8e33449377 100644
--- a/packages/SystemUI/src/com/android/systemui/util/Utils.java
+++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java
@@ -161,6 +161,14 @@ public class Utils {
return useQsMediaPlayer(context) && flag > 0;
}
+ /**
+ * Returns true if the device should use the collapsed layout for the media player when in
+ * landscape (or seascape) orientation
+ */
+ public static boolean useCollapsedMediaInLandscape(Resources resources) {
+ return resources.getBoolean(R.bool.config_quickSettingsMediaLandscapeCollapsed);
+ }
+
/**
* Returns true if the device should use the split notification shade, based on orientation and
* screen width.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
index dc7026da21946..1484c9d11ba61 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
@@ -36,6 +36,7 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
+import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
@@ -51,6 +52,8 @@ class KeyguardMediaControllerTest : SysuiTestCase() {
private lateinit var statusBarStateController: SysuiStatusBarStateController
@Mock
private lateinit var configurationController: ConfigurationController
+ @Mock
+ private lateinit var mediaFlags: MediaFlags
@Mock
private lateinit var notificationLockscreenUserManager: NotificationLockscreenUserManager
@@ -70,13 +73,15 @@ class KeyguardMediaControllerTest : SysuiTestCase() {
.thenReturn(true)
whenever(mediaHost.hostView).thenReturn(hostView)
hostView.layoutParams = FrameLayout.LayoutParams(100, 100)
+ whenever(mediaFlags.useMediaSessionLayout()).thenReturn(false)
keyguardMediaController = KeyguardMediaController(
mediaHost,
bypassController,
statusBarStateController,
notificationLockscreenUserManager,
context,
- configurationController
+ configurationController,
+ mediaFlags
)
keyguardMediaController.attachSinglePaneContainer(mediaContainerView)
keyguardMediaController.useSplitShade = false
@@ -150,4 +155,24 @@ class KeyguardMediaControllerTest : SysuiTestCase() {
assertTrue("HostView wasn't attached to the single pane container",
mediaContainerView.childCount == 1)
}
+
+ @Test
+ fun testNotificationLayout_collapsedPlayer() {
+ verify(mediaHost).expansion = MediaHostState.COLLAPSED
+ }
+
+ @Test
+ fun testSessionLayout_expandedPlayer() {
+ whenever(mediaFlags.useMediaSessionLayout()).thenReturn(true)
+ keyguardMediaController = KeyguardMediaController(
+ mediaHost,
+ bypassController,
+ statusBarStateController,
+ notificationLockscreenUserManager,
+ context,
+ configurationController,
+ mediaFlags
+ )
+ verify(mediaHost).expansion = MediaHostState.EXPANDED
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
index 09c6d9e86a440..1eb16fd64b854 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
@@ -23,11 +23,14 @@ import com.android.internal.logging.MetricsLogger
import com.android.internal.logging.testing.UiEventLoggerFake
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
+import com.android.systemui.media.MediaFlags
import com.android.systemui.media.MediaHost
+import com.android.systemui.media.MediaHostState
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.plugins.qs.QSTileView
import com.android.systemui.qs.customize.QSCustomizerController
import com.android.systemui.qs.logging.QSLogger
+import com.android.systemui.util.leak.RotationUtils
import org.junit.After
import org.junit.Before
import org.junit.Test
@@ -55,6 +58,8 @@ class QuickQSPanelControllerTest : SysuiTestCase() {
@Mock
private lateinit var mediaHost: MediaHost
@Mock
+ private lateinit var mediaFlags: MediaFlags
+ @Mock
private lateinit var metricsLogger: MetricsLogger
private val uiEventLogger = UiEventLoggerFake()
@Mock
@@ -71,7 +76,7 @@ class QuickQSPanelControllerTest : SysuiTestCase() {
@Captor
private lateinit var captor: ArgumentCaptor
- private lateinit var controller: QuickQSPanelController
+ private lateinit var controller: TestQuickQSPanelController
@Before
fun setUp() {
@@ -82,13 +87,16 @@ class QuickQSPanelControllerTest : SysuiTestCase() {
`when`(quickQSPanel.dumpableTag).thenReturn("")
`when`(quickQSPanel.resources).thenReturn(mContext.resources)
`when`(qsTileHost.createTileView(any(), any(), anyBoolean())).thenReturn(tileView)
+ `when`(mediaFlags.useMediaSessionLayout()).thenReturn(false)
- controller = QuickQSPanelController(
+ controller = TestQuickQSPanelController(
quickQSPanel,
qsTileHost,
qsCustomizerController,
false,
mediaHost,
+ true,
+ mediaFlags,
metricsLogger,
uiEventLogger,
qsLogger,
@@ -133,4 +141,49 @@ class QuickQSPanelControllerTest : SysuiTestCase() {
verify(quickQsBrightnessController).refreshVisibility(anyBoolean())
}
+
+ @Test
+ fun testMediaExpansionUpdatedWhenConfigurationChanged() {
+ `when`(mediaFlags.useMediaSessionLayout()).thenReturn(true)
+
+ // times(2) because both controller and base controller are registering their listeners
+ verify(quickQSPanel, times(2)).addOnConfigurationChangedListener(captor.capture())
+
+ captor.allValues.forEach { it.onConfigurationChange(Configuration.EMPTY) }
+ verify(mediaHost).expansion = MediaHostState.EXPANDED
+
+ // Rotate device, verify media size updated
+ controller.setRotation(RotationUtils.ROTATION_LANDSCAPE)
+ captor.allValues.forEach { it.onConfigurationChange(Configuration.EMPTY) }
+
+ // times(2) because init will have set to collapsed because the flag was off
+ verify(mediaHost, times(2)).expansion = MediaHostState.COLLAPSED
+ }
+
+ class TestQuickQSPanelController(
+ view: QuickQSPanel,
+ qsTileHost: QSTileHost,
+ qsCustomizerController: QSCustomizerController,
+ usingMediaPlayer: Boolean,
+ mediaHost: MediaHost,
+ usingCollapsedLandscapeMedia: Boolean,
+ mediaFlags: MediaFlags,
+ metricsLogger: MetricsLogger,
+ uiEventLogger: UiEventLoggerFake,
+ qsLogger: QSLogger,
+ dumpManager: DumpManager,
+ quickQSBrightnessController: QuickQSBrightnessController
+ ) : QuickQSPanelController(view, qsTileHost, qsCustomizerController, usingMediaPlayer,
+ mediaHost, usingCollapsedLandscapeMedia, mediaFlags, metricsLogger, uiEventLogger, qsLogger,
+ dumpManager, quickQSBrightnessController) {
+
+ private var rotation = RotationUtils.ROTATION_NONE
+
+ @Override
+ override fun getRotation(): Int = rotation
+
+ fun setRotation(newRotation: Int) {
+ rotation = newRotation
+ }
+ }
}