summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/res/layout/media_session_view.xml109
-rw-r--r--packages/SystemUI/res/values/dimens.xml1
-rw-r--r--packages/SystemUI/res/xml/media_session_collapsed.xml120
-rw-r--r--packages/SystemUI/res/xml/media_session_expanded.xml101
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java80
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaData.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/PlayerSessionViewHolder.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt17
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt212
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt24
13 files changed, 504 insertions, 202 deletions
diff --git a/packages/SystemUI/res/layout/media_session_view.xml b/packages/SystemUI/res/layout/media_session_view.xml
index 9ad01528686e..f030f3130be4 100644
--- a/packages/SystemUI/res/layout/media_session_view.xml
+++ b/packages/SystemUI/res/layout/media_session_view.xml
@@ -44,6 +44,7 @@
android:background="@drawable/qs_media_scrim"
/>
+ <!-- Guideline for output switcher -->
<androidx.constraintlayout.widget.Guideline
android:id="@+id/center_vertical_guideline"
android:layout_width="wrap_content"
@@ -51,6 +52,14 @@
android:orientation="vertical"
app:layout_constraintGuide_percent="0.6" />
+ <!-- Guideline for action buttons (collapsed view only) -->
+ <androidx.constraintlayout.widget.Guideline
+ android:id="@+id/action_button_guideline"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:orientation="vertical"
+ app:layout_constraintGuide_end="@dimen/qs_media_session_collapsed_guideline" />
+
<!-- App icon -->
<com.android.internal.widget.CachingIconView
android:id="@+id/icon"
@@ -118,15 +127,7 @@
android:singleLine="true"
android:textSize="16sp"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="20dp"
- android:layout_marginStart="@dimen/qs_media_padding"
- android:layout_marginEnd="@dimen/qs_media_padding"
- app:layout_constrainedWidth="true"
- app:layout_constraintTop_toBottomOf="@id/icon"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toStartOf="@id/actionPlayPause"
- app:layout_constraintHorizontal_bias="0" />
+ android:layout_height="wrap_content" />
<!-- Artist name -->
<TextView
@@ -136,15 +137,7 @@
style="@style/MediaPlayer.Subtitle"
android:textSize="14sp"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginEnd="@dimen/qs_media_padding"
- app:layout_constrainedWidth="true"
- android:layout_marginTop="0dp"
- app:layout_constraintTop_toBottomOf="@id/header_title"
- app:layout_constraintStart_toStartOf="@id/header_title"
- app:layout_constraintEnd_toStartOf="@id/actionPlayPause"
- app:layout_constraintBottom_toBottomOf="@id/actionPlayPause"
- app:layout_constraintHorizontal_bias="0" />
+ android:layout_height="wrap_content" />
<ImageButton
android:id="@+id/actionPlayPause"
@@ -153,9 +146,33 @@
android:layout_height="48dp"
android:layout_marginStart="@dimen/qs_media_padding"
android:layout_marginEnd="@dimen/qs_media_padding"
- android:layout_marginTop="0dp"
- android:layout_marginBottom="0dp" />
+ />
+
+ <!-- See comment in media_session_collapsed.xml for how these barriers are used -->
+ <androidx.constraintlayout.widget.Barrier
+ android:id="@+id/media_action_barrier"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:orientation="vertical"
+ app:layout_constraintTop_toBottomOf="@id/header_title"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:barrierDirection="start"
+ app:constraint_referenced_ids="actionPrev,media_progress_bar,actionNext,action0,action1,action2,action3,action4"
+ />
+ <androidx.constraintlayout.widget.Barrier
+ android:id="@+id/media_action_barrier_end"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:orientation="vertical"
+ app:layout_constraintTop_toBottomOf="@id/media_seamless"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:barrierDirection="end"
+ app:constraint_referenced_ids="actionPrev,media_progress_bar,actionNext,action0,action1,action2,action3,action4"
+ app:layout_constraintStart_toStartOf="parent"
+ />
+ <!-- Button visibility will be controlled in code -->
<ImageButton
android:id="@+id/actionPrev"
style="@style/MediaPlayer.SessionAction"
@@ -163,10 +180,9 @@
android:layout_height="48dp"
android:layout_marginStart="4dp"
android:layout_marginEnd="0dp"
- android:layout_marginBottom="0dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
android:layout_marginTop="0dp"
- app:layout_constraintHorizontal_bias="1"
- app:layout_constraintHorizontal_chainStyle="packed" />
+ />
<!-- Seek Bar -->
<!-- As per Material Design on Bidirectionality, this is forced to LTR in code -->
@@ -174,12 +190,12 @@
android:id="@+id/media_progress_bar"
style="@style/MediaPlayer.ProgressBar"
android:layout_width="0dp"
- android:layout_height="wrap_content"
+ android:layout_height="48dp"
android:paddingTop="@dimen/qs_media_session_enabled_seekbar_vertical_padding"
android:paddingBottom="12dp"
android:maxHeight="@dimen/qs_media_enabled_seekbar_height"
android:splitTrack="false"
- android:layout_marginBottom="0dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
android:layout_marginTop="0dp"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp" />
@@ -191,29 +207,58 @@
android:layout_height="48dp"
android:layout_marginStart="0dp"
android:layout_marginEnd="@dimen/qs_media_action_spacing"
- android:layout_marginBottom="0dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
android:layout_marginTop="0dp" />
<ImageButton
- android:id="@+id/actionStart"
+ android:id="@+id/action0"
style="@style/MediaPlayer.SessionAction"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginStart="@dimen/qs_media_action_spacing"
android:layout_marginEnd="@dimen/qs_media_action_spacing"
- android:layout_marginBottom="0dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ android:layout_marginTop="0dp"/>
+
+ <ImageButton
+ android:id="@+id/action1"
+ style="@style/MediaPlayer.SessionAction"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginStart="@dimen/qs_media_action_spacing"
+ android:layout_marginEnd="4dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
android:layout_marginTop="0dp" />
<ImageButton
- android:id="@+id/actionEnd"
+ android:id="@+id/action2"
style="@style/MediaPlayer.SessionAction"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginStart="@dimen/qs_media_action_spacing"
android:layout_marginEnd="4dp"
- android:layout_marginBottom="0dp"
- android:layout_marginTop="0dp"
- app:layout_constraintHorizontal_chainStyle="packed" />
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ android:layout_marginTop="0dp" />
+
+ <ImageButton
+ android:id="@+id/action3"
+ style="@style/MediaPlayer.SessionAction"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginStart="@dimen/qs_media_action_spacing"
+ android:layout_marginEnd="4dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ android:layout_marginTop="0dp" />
+
+ <ImageButton
+ android:id="@+id/action4"
+ style="@style/MediaPlayer.SessionAction"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginStart="@dimen/qs_media_action_spacing"
+ android:layout_marginEnd="4dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ android:layout_marginTop="0dp" />
<!-- Long press menu -->
<TextView
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 00ab9760afbe..512f9160162c 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -983,6 +983,7 @@
<dimen name="qs_media_seekbar_progress_amplitude">1.5dp</dimen>
<dimen name="qs_media_seekbar_progress_phase">8dp</dimen>
<dimen name="qs_media_seekbar_progress_stroke_width">2dp</dimen>
+ <dimen name="qs_media_session_collapsed_guideline">144dp</dimen>
<!-- Size of Smartspace media recommendations cards in the QSPanel carousel -->
<dimen name="qs_aa_media_rec_album_size_collapsed">72dp</dimen>
diff --git a/packages/SystemUI/res/xml/media_session_collapsed.xml b/packages/SystemUI/res/xml/media_session_collapsed.xml
index c6e18a6f8740..f00e03116337 100644
--- a/packages/SystemUI/res/xml/media_session_collapsed.xml
+++ b/packages/SystemUI/res/xml/media_session_collapsed.xml
@@ -19,6 +19,13 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<Constraint
+ android:id="@+id/media_action_barrier"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ app:layout_constraintTop_toBottomOf="@id/media_seamless"
+ app:layout_constraintStart_toEndOf="@id/action_button_guideline" />
+
+ <Constraint
android:id="@+id/album_art"
android:layout_width="match_parent"
android:layout_height="@dimen/qs_media_session_height_collapsed"
@@ -28,33 +35,73 @@
app:layout_constraintBottom_toBottomOf="parent" />
<Constraint
+ android:id="@+id/header_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="20dp"
+ android:layout_marginStart="@dimen/qs_media_padding"
+ android:layout_marginEnd="@dimen/qs_media_padding"
+ app:layout_constraintEnd_toStartOf="@id/action_button_guideline"
+ app:layout_constrainedWidth="true"
+ app:layout_constraintTop_toBottomOf="@id/icon"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintHorizontal_bias="0" />
+ <Constraint
+ android:id="@+id/header_artist"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/qs_media_padding"
+ android:layout_marginTop="0dp"
+ app:layout_constraintEnd_toStartOf="@id/action_button_guideline"
+ app:layout_constrainedWidth="true"
+ app:layout_constraintTop_toBottomOf="@id/header_title"
+ app:layout_constraintStart_toStartOf="@id/header_title"
+ app:layout_constraintVertical_bias="0"
+ app:layout_constraintHorizontal_bias="0" />
+
+ <Constraint
android:id="@+id/actionPlayPause"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginEnd="@dimen/qs_media_padding"
- app:layout_constraintStart_toEndOf="@id/actionEnd"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ app:layout_constraintVertical_bias="1"
app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/media_seamless"
- app:layout_constraintBottom_toBottomOf="parent" />
+ app:layout_constraintStart_toEndOf="@id/media_action_barrier_end" />
+ <!--
+ There will only be 3 action buttons shown at most in this layout (controlled in code).
+ Play/Pause should always be at the end, but the other buttons should remain in the same order
+ when in RTL.
+ This is accomplished by setting two barriers at the start and end of the small buttons,
+ anchored to a guideline set at 3x button width from the end. The text and play/pause button are
+ positioned relative to the barriers, and the small buttons use right/left constraints to stay
+ in the correct order inside the barriers.
+ -->
<Constraint
android:id="@+id/actionPrev"
android:layout_width="48dp"
android:layout_height="48dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
app:layout_constraintHorizontal_bias="1"
+ app:layout_constraintVertical_bias="1"
app:layout_constraintHorizontal_chainStyle="packed"
- app:layout_constraintStart_toEndOf="@id/header_artist"
- app:layout_constraintEnd_toStartOf="@id/media_progress_bar"
+ app:layout_constraintRight_toLeftOf="@id/media_progress_bar"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintTop_toBottomOf="@id/media_seamless" />
+ app:layout_constraintTop_toBottomOf="@id/media_seamless"
+ app:layout_constraintLeft_toRightOf="@id/media_action_barrier" />
<Constraint
android:id="@+id/media_progress_bar"
android:layout_width="0dp"
android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/qs_media_padding"
android:visibility="gone"
- app:layout_constraintStart_toEndOf="@id/actionPrev"
- app:layout_constraintEnd_toStartOf="@id/actionNext"
+ app:layout_constraintVertical_bias="1"
+ app:layout_constraintLeft_toRightOf="@id/actionPrev"
+ app:layout_constraintRight_toLeftOf="@id/actionNext"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/media_seamless" />
@@ -62,29 +109,70 @@
android:id="@+id/actionNext"
android:layout_width="48dp"
android:layout_height="48dp"
- app:layout_constraintStart_toEndOf="@id/media_progress_bar"
- app:layout_constraintEnd_toStartOf="@id/actionStart"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ app:layout_constraintVertical_bias="1"
+ app:layout_constraintLeft_toRightOf="@id/media_progress_bar"
+ app:layout_constraintRight_toLeftOf="@id/action0"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/media_seamless" />
+
+ <Constraint
+ android:id="@+id/action0"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ android:visibility="gone"
+ app:layout_constraintVertical_bias="1"
+ app:layout_constraintLeft_toRightOf="@id/actionNext"
+ app:layout_constraintRight_toLeftOf="@id/action1"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/media_seamless" />
+
+ <Constraint
+ android:id="@+id/action1"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ android:visibility="gone"
+ app:layout_constraintVertical_bias="1"
+ app:layout_constraintLeft_toRightOf="@id/action0"
+ app:layout_constraintRight_toLeftOf="@id/action2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/media_seamless" />
<Constraint
- android:id="@+id/actionStart"
+ android:id="@+id/action2"
android:layout_width="48dp"
android:layout_height="48dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
android:visibility="gone"
- app:layout_constraintStart_toEndOf="@id/actionNext"
- app:layout_constraintEnd_toStartOf="@id/actionEnd"
+ app:layout_constraintVertical_bias="1"
+ app:layout_constraintLeft_toRightOf="@id/action1"
+ app:layout_constraintRight_toLeftOf="@id/action3"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/media_seamless" />
<Constraint
- android:id="@+id/actionEnd"
+ android:id="@+id/action3"
android:layout_width="48dp"
android:layout_height="48dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
android:visibility="gone"
- app:layout_constraintStart_toEndOf="@id/actionStart"
- app:layout_constraintEnd_toStartOf="@id/actionPlayPause"
+ app:layout_constraintVertical_bias="1"
+ app:layout_constraintLeft_toRightOf="@id/action2"
+ app:layout_constraintRight_toLeftOf="@id/action4"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/media_seamless" />
-</ConstraintSet> \ No newline at end of file
+ <Constraint
+ android:id="@+id/action4"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:layout_marginBottom="@dimen/qs_media_padding"
+ android:visibility="gone"
+ app:layout_constraintVertical_bias="1"
+ app:layout_constraintLeft_toRightOf="@id/action3"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/media_seamless"
+ app:layout_constraintRight_toLeftOf="@id/media_action_barrier_end" />
+</ConstraintSet>
diff --git a/packages/SystemUI/res/xml/media_session_expanded.xml b/packages/SystemUI/res/xml/media_session_expanded.xml
index 18ec7aa4cab4..10da70447ec0 100644
--- a/packages/SystemUI/res/xml/media_session_expanded.xml
+++ b/packages/SystemUI/res/xml/media_session_expanded.xml
@@ -28,57 +28,118 @@
app:layout_constraintBottom_toBottomOf="parent" />
<Constraint
+ android:id="@+id/header_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="20dp"
+ android:layout_marginStart="@dimen/qs_media_padding"
+ android:layout_marginEnd="@dimen/qs_media_padding"
+ app:layout_constraintEnd_toStartOf="@id/actionPlayPause"
+ app:layout_constrainedWidth="true"
+ app:layout_constraintTop_toBottomOf="@id/icon"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintHorizontal_bias="0" />
+ <Constraint
+ android:id="@+id/header_artist"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/qs_media_padding"
+ android:layout_marginTop="0dp"
+ app:layout_constrainedWidth="true"
+ app:layout_constraintEnd_toStartOf="@id/actionPlayPause"
+ app:layout_constraintBottom_toTopOf="@id/media_action_barrier"
+ app:layout_constraintTop_toBottomOf="@id/header_title"
+ app:layout_constraintStart_toStartOf="@id/header_title"
+ app:layout_constraintVertical_bias="0"
+ app:layout_constraintHorizontal_bias="0" />
+
+ <Constraint
android:id="@+id/actionPlayPause"
android:layout_width="48dp"
android:layout_height="48dp"
+ android:layout_marginStart="@dimen/qs_media_padding"
android:layout_marginEnd="@dimen/qs_media_padding"
+ android:layout_marginBottom="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/media_seamless"
- app:layout_constraintBottom_toTopOf="@id/actionEnd" />
+ app:layout_constraintBottom_toBottomOf="@id/header_artist" />
+ <!--
+ The bottom row of action buttons should remain in the same order when RTL, so their constraints
+ are set with right/left instead of start/end.
+ The chain is set to "spread" so that the progress bar can be weighted to fill any empty space.
+ -->
<Constraint
android:id="@+id/actionPrev"
android:layout_width="48dp"
android:layout_height="48dp"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toStartOf="@id/media_progress_bar"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintRight_toLeftOf="@id/media_progress_bar"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+ app:layout_constraintTop_toBottomOf="@id/header_artist"
+ app:layout_constraintHorizontal_chainStyle="spread" />
<Constraint
android:id="@+id/media_progress_bar"
android:layout_width="0dp"
- android:layout_height="wrap_content"
- app:layout_constraintStart_toEndOf="@id/actionPrev"
- app:layout_constraintEnd_toStartOf="@id/actionNext"
+ android:layout_height="48dp"
+ app:layout_constraintLeft_toRightOf="@id/actionPrev"
+ app:layout_constraintRight_toLeftOf="@id/actionNext"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+ app:layout_constraintTop_toBottomOf="@id/header_artist"
+ app:layout_constraintHorizontal_weight="1" />
<Constraint
android:id="@+id/actionNext"
android:layout_width="48dp"
android:layout_height="48dp"
- app:layout_constraintStart_toEndOf="@id/media_progress_bar"
- app:layout_constraintEnd_toStartOf="@id/actionStart"
+ app:layout_constraintLeft_toRightOf="@id/media_progress_bar"
+ app:layout_constraintRight_toLeftOf="@id/action0"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+ app:layout_constraintTop_toBottomOf="@id/header_artist" />
<Constraint
- android:id="@+id/actionStart"
+ android:id="@+id/action0"
android:layout_width="48dp"
android:layout_height="48dp"
- app:layout_constraintStart_toEndOf="@id/actionNext"
- app:layout_constraintEnd_toStartOf="@id/actionEnd"
+ app:layout_constraintLeft_toRightOf="@id/actionNext"
+ app:layout_constraintRight_toLeftOf="@id/action1"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+ app:layout_constraintTop_toBottomOf="@id/header_artist" />
<Constraint
- android:id="@+id/actionEnd"
+ android:id="@+id/action1"
android:layout_width="48dp"
android:layout_height="48dp"
- app:layout_constraintStart_toEndOf="@id/actionStart"
- app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintLeft_toRightOf="@id/action0"
+ app:layout_constraintRight_toLeftOf="@id/action2"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/header_artist" />
+
+ <Constraint
+ android:id="@+id/action2"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ app:layout_constraintLeft_toRightOf="@id/action1"
+ app:layout_constraintRight_toLeftOf="@id/action3"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintTop_toBottomOf="@id/actionPlayPause" />
+ app:layout_constraintTop_toBottomOf="@id/header_artist" />
-</ConstraintSet> \ No newline at end of file
+ <Constraint
+ android:id="@+id/action3"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ app:layout_constraintLeft_toRightOf="@id/action2"
+ app:layout_constraintRight_toLeftOf="@id/action4"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/header_artist" />
+
+ <Constraint
+ android:id="@+id/action4"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ app:layout_constraintLeft_toRightOf="@id/action3"
+ app:layout_constraintRight_toRightOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/header_artist" />
+</ConstraintSet>
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 831a606e95b2..4a5b6f17af84 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -104,6 +104,13 @@ public class MediaControlPanel {
R.id.action4
};
+ // Buttons to show in small player when using semantic actions
+ private static final List<Integer> SEMANTIC_ACTION_IDS = List.of(
+ R.id.actionPlayPause,
+ R.id.actionPrev,
+ R.id.actionNext
+ );
+
private final SeekBarViewModel mSeekBarViewModel;
private SeekBarObserver mSeekBarObserver;
protected final Executor mBackgroundExecutor;
@@ -501,11 +508,11 @@ public class MediaControlPanel {
MediaButton semanticActions = data.getSemanticActions();
actionIcons = new ArrayList<MediaAction>();
- actionIcons.add(semanticActions.getStartCustom());
+ actionIcons.add(semanticActions.getCustom0());
actionIcons.add(semanticActions.getPrevOrCustom());
actionIcons.add(semanticActions.getPlayOrPause());
actionIcons.add(semanticActions.getNextOrCustom());
- actionIcons.add(semanticActions.getEndCustom());
+ actionIcons.add(semanticActions.getCustom1());
actionsWhenCollapsed = new ArrayList<Integer>();
actionsWhenCollapsed.add(1);
@@ -562,6 +569,9 @@ public class MediaControlPanel {
/** Bind elements specific to PlayerSessionViewHolder */
private void bindSessionPlayer(@NonNull MediaData data, String key) {
+ ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();
+ ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout();
+
// Default colors
int surfaceColor = mBackgroundColor;
int accentPrimary = com.android.settingslib.Utils.getColorAttr(mContext,
@@ -660,26 +670,68 @@ public class MediaControlPanel {
// Media action buttons
MediaButton semanticActions = data.getSemanticActions();
+ PlayerSessionViewHolder sessionHolder = (PlayerSessionViewHolder) mMediaViewHolder;
+ ImageButton[] genericButtons = new ImageButton[]{
+ sessionHolder.getAction0(),
+ sessionHolder.getAction1(),
+ sessionHolder.getAction2(),
+ sessionHolder.getAction3(),
+ sessionHolder.getAction4()};
+
+ ImageButton[] semanticButtons = new ImageButton[]{
+ sessionHolder.getActionPlayPause(),
+ sessionHolder.getActionNext(),
+ sessionHolder.getActionPrev()};
+
if (semanticActions != null) {
- PlayerSessionViewHolder sessionHolder = (PlayerSessionViewHolder) mMediaViewHolder;
+ // Hide all the generic buttons
+ for (ImageButton b: genericButtons) {
+ setVisibleAndAlpha(collapsedSet, b.getId(), false);
+ setVisibleAndAlpha(expandedSet, b.getId(), false);
+ }
// Play/pause button has a background
sessionHolder.getActionPlayPause().setBackgroundTintList(accentColorList);
setSemanticButton(sessionHolder.getActionPlayPause(), semanticActions.getPlayOrPause(),
- ColorStateList.valueOf(textPrimaryInverse));
+ ColorStateList.valueOf(textPrimaryInverse), collapsedSet, expandedSet, true);
setSemanticButton(sessionHolder.getActionNext(), semanticActions.getNextOrCustom(),
- textColorList);
+ textColorList, collapsedSet, expandedSet, true);
setSemanticButton(sessionHolder.getActionPrev(), semanticActions.getPrevOrCustom(),
- textColorList);
- setSemanticButton(sessionHolder.getActionStart(), semanticActions.getStartCustom(),
- textColorList);
- setSemanticButton(sessionHolder.getActionEnd(), semanticActions.getEndCustom(),
- textColorList);
+ textColorList, collapsedSet, expandedSet, true);
+ setSemanticButton(sessionHolder.getAction0(), semanticActions.getCustom0(),
+ textColorList, collapsedSet, expandedSet, false);
+ setSemanticButton(sessionHolder.getAction1(), semanticActions.getCustom1(),
+ textColorList, collapsedSet, expandedSet, false);
} else {
- Log.w(TAG, "Using semantic player, but did not get buttons");
+ // Hide all the semantic buttons
+ for (int id : SEMANTIC_ACTION_IDS) {
+ setVisibleAndAlpha(collapsedSet, id, false);
+ setVisibleAndAlpha(expandedSet, id, false);
+ }
+
+ // Set all the generic buttons
+ List<Integer> actionsWhenCollapsed = data.getActionsToShowInCompact();
+ List<MediaAction> actions = data.getActions();
+ int i = 0;
+ for (; i < actions.size(); i++) {
+ boolean showInCompact = actionsWhenCollapsed.contains(i);
+ setSemanticButton(genericButtons[i], actions.get(i), textColorList, collapsedSet,
+ expandedSet, showInCompact);
+ }
+ for (; i < 5; i++) {
+ // Hide any unused buttons
+ setSemanticButton(genericButtons[i], null, textColorList, collapsedSet,
+ expandedSet, false);
+ }
}
+ // If disabled, set progress bar to INVISIBLE instead of GONE so layout weights still work
+ boolean seekbarEnabled = mSeekBarViewModel.getEnabled();
+ expandedSet.setVisibility(R.id.media_progress_bar,
+ seekbarEnabled ? ConstraintSet.VISIBLE : ConstraintSet.INVISIBLE);
+ expandedSet.setAlpha(R.id.media_progress_bar, seekbarEnabled ? 1.0f : 0.0f);
+
// Long press buttons
mMediaViewHolder.getLongPressText().setTextColor(textColorList);
mMediaViewHolder.getSettingsText().setTextColor(textColorList);
@@ -692,7 +744,8 @@ public class MediaControlPanel {
}
private void setSemanticButton(final ImageButton button, MediaAction mediaAction,
- ColorStateList fgColor) {
+ ColorStateList fgColor, ConstraintSet collapsedSet, ConstraintSet expandedSet,
+ boolean showInCompact) {
button.setImageTintList(fgColor);
if (mediaAction != null) {
button.setImageIcon(mediaAction.getIcon());
@@ -716,6 +769,9 @@ public class MediaControlPanel {
button.setContentDescription(null);
button.setEnabled(false);
}
+
+ setVisibleAndAlpha(collapsedSet, button.getId(), mediaAction != null && showInCompact);
+ setVisibleAndAlpha(expandedSet, button.getId(), mediaAction != null);
}
@Nullable
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
index 500e82efdb0a..4cf6291fe35b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
@@ -149,11 +149,11 @@ data class MediaButton(
/**
* First custom action space
*/
- var startCustom: MediaAction? = null,
+ var custom0: MediaAction? = null,
/**
- * Last custom action space
+ * Second custom action space
*/
- var endCustom: MediaAction? = null
+ var custom1: MediaAction? = null
)
/** State of a media action. */
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index fab06c288ce1..9e14fe91f21d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -752,8 +752,8 @@ class MediaDataManager(
null
}
- actions.startCustom = customActions[customIdx++]
- actions.endCustom = customActions[customIdx++]
+ actions.custom0 = customActions[customIdx++]
+ actions.custom1 = customActions[customIdx++]
}
return actions
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt
index e57b247da055..5f606969153c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt
@@ -60,12 +60,24 @@ abstract class MediaViewHolder constructor(itemView: View) {
val settings = itemView.requireViewById<View>(R.id.settings)
val settingsText = itemView.requireViewById<TextView>(R.id.settings_text)
+ // Action Buttons
+ val action0 = itemView.requireViewById<ImageButton>(R.id.action0)
+ val action1 = itemView.requireViewById<ImageButton>(R.id.action1)
+ val action2 = itemView.requireViewById<ImageButton>(R.id.action2)
+ val action3 = itemView.requireViewById<ImageButton>(R.id.action3)
+ val action4 = itemView.requireViewById<ImageButton>(R.id.action4)
+
init {
(player.background as IlluminationDrawable).let {
it.registerLightSource(seamless)
it.registerLightSource(cancel)
it.registerLightSource(dismiss)
it.registerLightSource(settings)
+ it.registerLightSource(action0)
+ it.registerLightSource(action1)
+ it.registerLightSource(action2)
+ it.registerLightSource(action3)
+ it.registerLightSource(action4)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/PlayerSessionViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/PlayerSessionViewHolder.kt
index 87d2cffea257..6928ebb8bb32 100644
--- a/packages/SystemUI/src/com/android/systemui/media/PlayerSessionViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/PlayerSessionViewHolder.kt
@@ -31,16 +31,12 @@ class PlayerSessionViewHolder private constructor(itemView: View) : MediaViewHol
val actionPlayPause = itemView.requireViewById<ImageButton>(R.id.actionPlayPause)
val actionNext = itemView.requireViewById<ImageButton>(R.id.actionNext)
val actionPrev = itemView.requireViewById<ImageButton>(R.id.actionPrev)
- val actionStart = itemView.requireViewById<ImageButton>(R.id.actionStart)
- val actionEnd = itemView.requireViewById<ImageButton>(R.id.actionEnd)
init {
(player.background as IlluminationDrawable).let {
it.registerLightSource(actionPlayPause)
it.registerLightSource(actionNext)
it.registerLightSource(actionPrev)
- it.registerLightSource(actionStart)
- it.registerLightSource(actionEnd)
}
}
@@ -49,8 +45,11 @@ class PlayerSessionViewHolder private constructor(itemView: View) : MediaViewHol
R.id.actionPlayPause -> actionPlayPause
R.id.actionNext -> actionNext
R.id.actionPrev -> actionPrev
- R.id.actionStart -> actionStart
- R.id.actionEnd -> actionEnd
+ R.id.action0 -> action0
+ R.id.action1 -> action1
+ R.id.action2 -> action2
+ R.id.action3 -> action3
+ R.id.action4 -> action4
else -> {
throw IllegalArgumentException()
}
@@ -90,8 +89,11 @@ class PlayerSessionViewHolder private constructor(itemView: View) : MediaViewHol
R.id.actionPlayPause,
R.id.actionNext,
R.id.actionPrev,
- R.id.actionStart,
- R.id.actionEnd,
+ R.id.action0,
+ R.id.action1,
+ R.id.action2,
+ R.id.action3,
+ R.id.action4,
R.id.icon
)
val gutsIds = setOf(
diff --git a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
index 20b2d4a452f5..dd3fa89dea66 100644
--- a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
@@ -33,23 +33,6 @@ class PlayerViewHolder private constructor(itemView: View) : MediaViewHolder(ite
override val elapsedTimeView = itemView.requireViewById<TextView>(R.id.media_elapsed_time)
override val totalTimeView = itemView.requireViewById<TextView>(R.id.media_total_time)
- // Action Buttons
- val action0 = itemView.requireViewById<ImageButton>(R.id.action0)
- val action1 = itemView.requireViewById<ImageButton>(R.id.action1)
- val action2 = itemView.requireViewById<ImageButton>(R.id.action2)
- val action3 = itemView.requireViewById<ImageButton>(R.id.action3)
- val action4 = itemView.requireViewById<ImageButton>(R.id.action4)
-
- init {
- (player.background as IlluminationDrawable).let {
- it.registerLightSource(action0)
- it.registerLightSource(action1)
- it.registerLightSource(action2)
- it.registerLightSource(action3)
- it.registerLightSource(action4)
- }
- }
-
override fun getAction(id: Int): ImageButton {
return when (id) {
R.id.action0 -> action0
diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
index 329dec24a5c3..49cd16175f0a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
@@ -132,6 +132,8 @@ class SeekBarViewModel @Inject constructor(
lateinit var logSmartspaceClick: () -> Unit
+ fun getEnabled() = _data.enabled
+
/**
* Event indicating that the user has started interacting with the seek bar.
*/
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index 708fc915410c..c024087a22ea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -59,6 +59,7 @@ import org.mockito.ArgumentMatchers.anyLong
import org.mockito.Mock
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
+import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
@@ -119,8 +120,6 @@ public class MediaControlPanelTest : SysuiTestCase() {
private lateinit var actionPlayPause: ImageButton
private lateinit var actionNext: ImageButton
private lateinit var actionPrev: ImageButton
- private lateinit var actionStart: ImageButton
- private lateinit var actionEnd: ImageButton
@Mock private lateinit var longPressText: TextView
@Mock private lateinit var handler: Handler
private lateinit var settings: View
@@ -168,6 +167,17 @@ public class MediaControlPanelTest : SysuiTestCase() {
cancelText = TextView(context)
dismiss = FrameLayout(context)
dismissText = TextView(context)
+
+ action0 = ImageButton(context).also { it.setId(R.id.action0) }
+ action1 = ImageButton(context).also { it.setId(R.id.action1) }
+ action2 = ImageButton(context).also { it.setId(R.id.action2) }
+ action3 = ImageButton(context).also { it.setId(R.id.action3) }
+ action4 = ImageButton(context).also { it.setId(R.id.action4) }
+
+ actionPlayPause = ImageButton(context).also { it.setId(R.id.actionPlayPause) }
+ actionPrev = ImageButton(context).also { it.setId(R.id.actionPrev) }
+ actionNext = ImageButton(context).also { it.setId(R.id.actionNext) }
+
initPlayerHolderMocks()
initSessionHolderMocks()
@@ -208,90 +218,64 @@ public class MediaControlPanelTest : SysuiTestCase() {
whenever(mediaFlags.useMediaSessionLayout()).thenReturn(false)
}
- /** Mock view holder for the notification player */
- private fun initPlayerHolderMocks() {
- whenever(holder.player).thenReturn(view)
- whenever(holder.appIcon).thenReturn(appIcon)
- whenever(holder.albumView).thenReturn(albumView)
- whenever(holder.titleText).thenReturn(titleText)
- whenever(holder.artistText).thenReturn(artistText)
+ /**
+ * Initialize elements common to both view holders
+ */
+ private fun initMediaViewHolderMocks(viewHolder: MediaViewHolder) {
+ whenever(viewHolder.player).thenReturn(view)
+ whenever(viewHolder.appIcon).thenReturn(appIcon)
+ whenever(viewHolder.albumView).thenReturn(albumView)
+ whenever(viewHolder.titleText).thenReturn(titleText)
+ whenever(viewHolder.artistText).thenReturn(artistText)
whenever(seamlessBackground.getDrawable(0)).thenReturn(mock(GradientDrawable::class.java))
- whenever(holder.seamless).thenReturn(seamless)
- whenever(holder.seamlessButton).thenReturn(seamlessButton)
- whenever(holder.seamlessIcon).thenReturn(seamlessIcon)
- whenever(holder.seamlessText).thenReturn(seamlessText)
- whenever(holder.seekBar).thenReturn(seekBar)
- whenever(holder.elapsedTimeView).thenReturn(elapsedTimeView)
- whenever(holder.totalTimeView).thenReturn(totalTimeView)
+ whenever(viewHolder.seamless).thenReturn(seamless)
+ whenever(viewHolder.seamlessButton).thenReturn(seamlessButton)
+ whenever(viewHolder.seamlessIcon).thenReturn(seamlessIcon)
+ whenever(viewHolder.seamlessText).thenReturn(seamlessText)
+ whenever(viewHolder.seekBar).thenReturn(seekBar)
// Action buttons
- action0 = ImageButton(context)
- whenever(holder.action0).thenReturn(action0)
- whenever(holder.getAction(R.id.action0)).thenReturn(action0)
- action1 = ImageButton(context)
- whenever(holder.action1).thenReturn(action1)
- whenever(holder.getAction(R.id.action1)).thenReturn(action1)
- action2 = ImageButton(context)
- whenever(holder.action2).thenReturn(action2)
- whenever(holder.getAction(R.id.action2)).thenReturn(action2)
- action3 = ImageButton(context)
- whenever(holder.action3).thenReturn(action3)
- whenever(holder.getAction(R.id.action3)).thenReturn(action3)
- action4 = ImageButton(context)
- whenever(holder.action4).thenReturn(action4)
- whenever(holder.getAction(R.id.action4)).thenReturn(action4)
+ whenever(viewHolder.action0).thenReturn(action0)
+ whenever(viewHolder.getAction(R.id.action0)).thenReturn(action0)
+ whenever(viewHolder.action1).thenReturn(action1)
+ whenever(viewHolder.getAction(R.id.action1)).thenReturn(action1)
+ whenever(viewHolder.action2).thenReturn(action2)
+ whenever(viewHolder.getAction(R.id.action2)).thenReturn(action2)
+ whenever(viewHolder.action3).thenReturn(action3)
+ whenever(viewHolder.getAction(R.id.action3)).thenReturn(action3)
+ whenever(viewHolder.action4).thenReturn(action4)
+ whenever(viewHolder.getAction(R.id.action4)).thenReturn(action4)
// Long press menu
- whenever(holder.longPressText).thenReturn(longPressText)
+ whenever(viewHolder.longPressText).thenReturn(longPressText)
whenever(longPressText.handler).thenReturn(handler)
- whenever(holder.settings).thenReturn(settings)
- whenever(holder.settingsText).thenReturn(settingsText)
- whenever(holder.cancel).thenReturn(cancel)
- whenever(holder.cancelText).thenReturn(cancelText)
- whenever(holder.dismiss).thenReturn(dismiss)
- whenever(holder.dismissText).thenReturn(dismissText)
+ whenever(viewHolder.settings).thenReturn(settings)
+ whenever(viewHolder.settingsText).thenReturn(settingsText)
+ whenever(viewHolder.cancel).thenReturn(cancel)
+ whenever(viewHolder.cancelText).thenReturn(cancelText)
+ whenever(viewHolder.dismiss).thenReturn(dismiss)
+ whenever(viewHolder.dismissText).thenReturn(dismissText)
+ }
+
+ /** Mock view holder for the notification player */
+ private fun initPlayerHolderMocks() {
+ initMediaViewHolderMocks(holder)
+
+ whenever(holder.elapsedTimeView).thenReturn(elapsedTimeView)
+ whenever(holder.totalTimeView).thenReturn(totalTimeView)
}
/** Mock view holder for session player */
private fun initSessionHolderMocks() {
- whenever(sessionHolder.player).thenReturn(view)
- whenever(sessionHolder.albumView).thenReturn(albumView)
- whenever(sessionHolder.appIcon).thenReturn(appIcon)
- whenever(sessionHolder.titleText).thenReturn(titleText)
- whenever(sessionHolder.artistText).thenReturn(artistText)
- val seamlessBackground = mock(RippleDrawable::class.java)
- whenever(seamlessBackground.getDrawable(0)).thenReturn(mock(GradientDrawable::class.java))
- whenever(sessionHolder.seamless).thenReturn(seamless)
- whenever(sessionHolder.seamlessButton).thenReturn(seamlessButton)
- whenever(sessionHolder.seamlessIcon).thenReturn(seamlessIcon)
- whenever(sessionHolder.seamlessText).thenReturn(seamlessText)
- whenever(sessionHolder.seekBar).thenReturn(seekBar)
+ initMediaViewHolderMocks(sessionHolder)
- // Action buttons
- actionPlayPause = ImageButton(context)
+ // Semantic action buttons
whenever(sessionHolder.actionPlayPause).thenReturn(actionPlayPause)
whenever(sessionHolder.getAction(R.id.actionPlayPause)).thenReturn(actionPlayPause)
- actionNext = ImageButton(context)
whenever(sessionHolder.actionNext).thenReturn(actionNext)
whenever(sessionHolder.getAction(R.id.actionNext)).thenReturn(actionNext)
- actionPrev = ImageButton(context)
whenever(sessionHolder.actionPrev).thenReturn(actionPrev)
whenever(sessionHolder.getAction(R.id.actionPrev)).thenReturn(actionPrev)
- actionStart = ImageButton(context)
- whenever(sessionHolder.actionStart).thenReturn(actionStart)
- whenever(sessionHolder.getAction(R.id.actionStart)).thenReturn(actionStart)
- actionEnd = ImageButton(context)
- whenever(sessionHolder.actionEnd).thenReturn(actionEnd)
- whenever(sessionHolder.getAction(R.id.actionEnd)).thenReturn(actionEnd)
-
- // Long press menu
- whenever(sessionHolder.longPressText).thenReturn(longPressText)
- whenever(sessionHolder.settings).thenReturn(settings)
- whenever(sessionHolder.settingsText).thenReturn(settingsText)
- whenever(sessionHolder.cancel).thenReturn(cancel)
- whenever(sessionHolder.cancelText).thenReturn(cancelText)
- whenever(sessionHolder.dismiss).thenReturn(dismiss)
- whenever(sessionHolder.dismissText).thenReturn(dismissText)
}
@After
@@ -316,8 +300,8 @@ public class MediaControlPanelTest : SysuiTestCase() {
val semanticActions = MediaButton(
playOrPause = MediaAction(icon, Runnable {}, "play"),
nextOrCustom = MediaAction(icon, Runnable {}, "next"),
- startCustom = MediaAction(icon, null, "custom 1"),
- endCustom = MediaAction(icon, null, "custom 2")
+ custom0 = MediaAction(icon, null, "custom 0"),
+ custom1 = MediaAction(icon, null, "custom 1")
)
val state = mediaData.copy(semanticActions = semanticActions)
@@ -325,7 +309,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
player.bindPlayer(state, PACKAGE)
verify(expandedSet).setVisibility(R.id.action0, ConstraintSet.VISIBLE)
- assertThat(action0.contentDescription).isEqualTo("custom 1")
+ assertThat(action0.contentDescription).isEqualTo("custom 0")
assertThat(action0.isEnabled()).isFalse()
verify(expandedSet).setVisibility(R.id.action1, ConstraintSet.INVISIBLE)
@@ -340,7 +324,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
assertThat(action3.contentDescription).isEqualTo("next")
verify(expandedSet).setVisibility(R.id.action4, ConstraintSet.VISIBLE)
- assertThat(action4.contentDescription).isEqualTo("custom 2")
+ assertThat(action4.contentDescription).isEqualTo("custom 1")
assertThat(action4.isEnabled()).isFalse()
}
@@ -353,28 +337,96 @@ public class MediaControlPanelTest : SysuiTestCase() {
val semanticActions = MediaButton(
playOrPause = MediaAction(icon, Runnable {}, "play"),
nextOrCustom = MediaAction(icon, Runnable {}, "next"),
- startCustom = MediaAction(icon, null, "custom 1"),
- endCustom = MediaAction(icon, null, "custom 2")
+ custom0 = MediaAction(icon, null, "custom 0"),
+ custom1 = MediaAction(icon, null, "custom 1")
)
val state = mediaData.copy(semanticActions = semanticActions)
player.attachPlayer(sessionHolder, MediaViewController.TYPE.PLAYER_SESSION)
player.bindPlayer(state, PACKAGE)
- assertThat(actionStart.contentDescription).isEqualTo("custom 1")
- assertThat(actionStart.isEnabled()).isFalse()
-
assertThat(actionPrev.isEnabled()).isFalse()
assertThat(actionPrev.drawable).isNull()
+ verify(collapsedSet).setVisibility(R.id.actionPrev, ConstraintSet.GONE)
assertThat(actionPlayPause.isEnabled()).isTrue()
assertThat(actionPlayPause.contentDescription).isEqualTo("play")
+ verify(collapsedSet).setVisibility(R.id.actionPlayPause, ConstraintSet.VISIBLE)
assertThat(actionNext.isEnabled()).isTrue()
assertThat(actionNext.contentDescription).isEqualTo("next")
+ verify(collapsedSet).setVisibility(R.id.actionNext, ConstraintSet.VISIBLE)
+
+ // Called twice since these IDs are used as generic buttons
+ assertThat(action0.contentDescription).isEqualTo("custom 0")
+ assertThat(action0.isEnabled()).isFalse()
+ verify(collapsedSet, times(2)).setVisibility(R.id.action0, ConstraintSet.GONE)
+
+ assertThat(action1.contentDescription).isEqualTo("custom 1")
+ assertThat(action1.isEnabled()).isFalse()
+ verify(collapsedSet, times(2)).setVisibility(R.id.action1, ConstraintSet.GONE)
+
+ // Verify generic buttons are hidden
+ verify(collapsedSet).setVisibility(R.id.action2, ConstraintSet.GONE)
+ verify(expandedSet).setVisibility(R.id.action2, ConstraintSet.GONE)
+
+ verify(collapsedSet).setVisibility(R.id.action3, ConstraintSet.GONE)
+ verify(expandedSet).setVisibility(R.id.action3, ConstraintSet.GONE)
+
+ verify(collapsedSet).setVisibility(R.id.action4, ConstraintSet.GONE)
+ verify(expandedSet).setVisibility(R.id.action4, ConstraintSet.GONE)
+ }
+
+ @Test
+ fun bindNotificationActionsNewLayout() {
+ whenever(mediaFlags.areMediaSessionActionsEnabled()).thenReturn(true)
+ whenever(mediaFlags.useMediaSessionLayout()).thenReturn(true)
+
+ val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play)
+ val actions = listOf(
+ MediaAction(icon, Runnable {}, "previous"),
+ MediaAction(icon, Runnable {}, "play"),
+ MediaAction(icon, null, "next"),
+ MediaAction(icon, null, "custom 0"),
+ MediaAction(icon, Runnable {}, "custom 1")
+ )
+ val state = mediaData.copy(actions = actions,
+ actionsToShowInCompact = listOf(1, 2),
+ semanticActions = null)
+
+ player.attachPlayer(sessionHolder, MediaViewController.TYPE.PLAYER_SESSION)
+ player.bindPlayer(state, PACKAGE)
+
+ // Verify semantic actions are hidden
+ verify(collapsedSet).setVisibility(R.id.actionPrev, ConstraintSet.GONE)
+ verify(expandedSet).setVisibility(R.id.actionPrev, ConstraintSet.GONE)
+
+ verify(collapsedSet).setVisibility(R.id.actionPlayPause, ConstraintSet.GONE)
+ verify(expandedSet).setVisibility(R.id.actionPlayPause, ConstraintSet.GONE)
+
+ verify(collapsedSet).setVisibility(R.id.actionNext, ConstraintSet.GONE)
+ verify(expandedSet).setVisibility(R.id.actionNext, ConstraintSet.GONE)
+
+ // Generic actions all enabled
+ assertThat(action0.contentDescription).isEqualTo("previous")
+ assertThat(action0.isEnabled()).isTrue()
+ verify(collapsedSet).setVisibility(R.id.action0, ConstraintSet.GONE)
+
+ assertThat(action1.contentDescription).isEqualTo("play")
+ assertThat(action1.isEnabled()).isTrue()
+ verify(collapsedSet).setVisibility(R.id.action1, ConstraintSet.VISIBLE)
+
+ assertThat(action2.contentDescription).isEqualTo("next")
+ assertThat(action2.isEnabled()).isFalse()
+ verify(collapsedSet).setVisibility(R.id.action2, ConstraintSet.VISIBLE)
+
+ assertThat(action3.contentDescription).isEqualTo("custom 0")
+ assertThat(action3.isEnabled()).isFalse()
+ verify(collapsedSet).setVisibility(R.id.action3, ConstraintSet.GONE)
- assertThat(actionEnd.contentDescription).isEqualTo("custom 2")
- assertThat(actionEnd.isEnabled()).isFalse()
+ assertThat(action4.contentDescription).isEqualTo("custom 1")
+ assertThat(action4.isEnabled()).isTrue()
+ verify(collapsedSet).setVisibility(R.id.action4, ConstraintSet.GONE)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
index 021f70e05b32..925ae30e8773 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -659,11 +659,11 @@ class MediaDataManagerTest : SysuiTestCase() {
actions.nextOrCustom!!.action!!.run()
verify(transportControls).skipToNext()
- assertThat(actions.startCustom).isNotNull()
- assertThat(actions.startCustom!!.contentDescription).isEqualTo(customDesc[0])
+ assertThat(actions.custom0).isNotNull()
+ assertThat(actions.custom0!!.contentDescription).isEqualTo(customDesc[0])
- assertThat(actions.endCustom).isNotNull()
- assertThat(actions.endCustom!!.contentDescription).isEqualTo(customDesc[1])
+ assertThat(actions.custom1).isNotNull()
+ assertThat(actions.custom1!!.contentDescription).isEqualTo(customDesc[1])
}
@Test
@@ -697,11 +697,11 @@ class MediaDataManagerTest : SysuiTestCase() {
assertThat(actions.nextOrCustom).isNotNull()
assertThat(actions.nextOrCustom!!.contentDescription).isEqualTo(customDesc[1])
- assertThat(actions.startCustom).isNotNull()
- assertThat(actions.startCustom!!.contentDescription).isEqualTo(customDesc[2])
+ assertThat(actions.custom0).isNotNull()
+ assertThat(actions.custom0!!.contentDescription).isEqualTo(customDesc[2])
- assertThat(actions.endCustom).isNotNull()
- assertThat(actions.endCustom!!.contentDescription).isEqualTo(customDesc[3])
+ assertThat(actions.custom1).isNotNull()
+ assertThat(actions.custom1!!.contentDescription).isEqualTo(customDesc[3])
}
@Test
@@ -737,10 +737,10 @@ class MediaDataManagerTest : SysuiTestCase() {
assertThat(actions.prevOrCustom).isNull()
assertThat(actions.nextOrCustom).isNull()
- assertThat(actions.startCustom).isNotNull()
- assertThat(actions.startCustom!!.contentDescription).isEqualTo(customDesc[0])
+ assertThat(actions.custom0).isNotNull()
+ assertThat(actions.custom0!!.contentDescription).isEqualTo(customDesc[0])
- assertThat(actions.endCustom).isNotNull()
- assertThat(actions.endCustom!!.contentDescription).isEqualTo(customDesc[1])
+ assertThat(actions.custom1).isNotNull()
+ assertThat(actions.custom1!!.contentDescription).isEqualTo(customDesc[1])
}
}