Merge "Add fallback media layout for notification actions" into tm-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
60c89a2fdf
@@ -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_marginTop="0dp" />
|
||||
android:layout_marginBottom="@dimen/qs_media_padding"
|
||||
android:layout_marginTop="0dp"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/actionEnd"
|
||||
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="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/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="@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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -18,6 +18,13 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
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"
|
||||
@@ -27,34 +34,74 @@
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
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/actionStart"
|
||||
android:id="@+id/action0"
|
||||
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/actionNext"
|
||||
app:layout_constraintRight_toLeftOf="@id/action1"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/media_seamless" />
|
||||
|
||||
<Constraint
|
||||
android:id="@+id/actionEnd"
|
||||
android:id="@+id/action1"
|
||||
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/action0"
|
||||
app:layout_constraintRight_toLeftOf="@id/action2"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/media_seamless" />
|
||||
|
||||
</ConstraintSet>
|
||||
<Constraint
|
||||
android:id="@+id/action2"
|
||||
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/action1"
|
||||
app:layout_constraintRight_toLeftOf="@id/action3"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/media_seamless" />
|
||||
|
||||
<Constraint
|
||||
android:id="@+id/action3"
|
||||
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/action2"
|
||||
app:layout_constraintRight_toLeftOf="@id/action4"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/media_seamless" />
|
||||
|
||||
<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>
|
||||
|
||||
@@ -27,58 +27,119 @@
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
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/actionPlayPause" />
|
||||
app:layout_constraintTop_toBottomOf="@id/header_artist" />
|
||||
|
||||
</ConstraintSet>
|
||||
<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/header_artist" />
|
||||
|
||||
<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>
|
||||
|
||||
@@ -105,6 +105,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;
|
||||
@@ -505,11 +512,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);
|
||||
@@ -566,6 +573,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,
|
||||
@@ -664,26 +674,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);
|
||||
@@ -695,7 +747,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());
|
||||
@@ -719,6 +772,9 @@ public class MediaControlPanel {
|
||||
button.setContentDescription(null);
|
||||
button.setEnabled(false);
|
||||
}
|
||||
|
||||
setVisibleAndAlpha(collapsedSet, button.getId(), mediaAction != null && showInCompact);
|
||||
setVisibleAndAlpha(expandedSet, button.getId(), mediaAction != null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -60,6 +60,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
|
||||
@@ -121,8 +122,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
|
||||
@@ -170,6 +169,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()
|
||||
|
||||
@@ -210,90 +220,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
|
||||
@@ -318,8 +302,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)
|
||||
|
||||
@@ -327,7 +311,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)
|
||||
@@ -342,7 +326,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()
|
||||
}
|
||||
|
||||
@@ -355,28 +339,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)
|
||||
|
||||
assertThat(actionEnd.contentDescription).isEqualTo("custom 2")
|
||||
assertThat(actionEnd.isEnabled()).isFalse()
|
||||
// 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(action4.contentDescription).isEqualTo("custom 1")
|
||||
assertThat(action4.isEnabled()).isTrue()
|
||||
verify(collapsedSet).setVisibility(R.id.action4, ConstraintSet.GONE)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user