Merge "Media layout changes for tablets" into tm-dev

This commit is contained in:
Christian Göllner
2022-03-23 20:44:00 +00:00
committed by Android (Google) Code Review
7 changed files with 118 additions and 27 deletions

View File

@@ -172,6 +172,15 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
/> />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/media_action_barrier_top"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:barrierDirection="top"
app:constraint_referenced_ids="actionPrev,media_progress_bar,actionNext,action0,action1,action2,action3,action4"
/>
<!-- Button visibility will be controlled in code --> <!-- Button visibility will be controlled in code -->
<ImageButton <ImageButton
android:id="@+id/actionPrev" android:id="@+id/actionPrev"

View File

@@ -25,5 +25,5 @@
<dimen name="status_bar_header_height_keyguard">56dp</dimen> <dimen name="status_bar_header_height_keyguard">56dp</dimen>
<dimen name="qs_media_session_height_expanded">184dp</dimen> <dimen name="qs_media_session_height_expanded">251dp</dimen>
</resources> </resources>

View File

@@ -31,25 +31,24 @@
android:id="@+id/header_title" android:id="@+id/header_title"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginStart="@dimen/qs_media_padding" android:layout_marginStart="@dimen/qs_media_padding"
android:layout_marginEnd="@dimen/qs_media_padding" android:layout_marginEnd="@dimen/qs_media_padding"
app:layout_constraintEnd_toStartOf="@id/actionPlayPause" app:layout_constraintEnd_toStartOf="@id/actionPlayPause"
app:layout_constrainedWidth="true" app:layout_constrainedWidth="true"
app:layout_constraintTop_toBottomOf="@id/icon"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toTopOf="@id/header_artist"
app:layout_constraintHorizontal_bias="0" /> app:layout_constraintHorizontal_bias="0" />
<Constraint <Constraint
android:id="@+id/header_artist" android:id="@+id/header_artist"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/qs_media_padding" android:layout_marginEnd="@dimen/qs_media_padding"
android:layout_marginBottom="@dimen/qs_media_padding"
android:layout_marginTop="0dp" android:layout_marginTop="0dp"
app:layout_constrainedWidth="true" app:layout_constrainedWidth="true"
app:layout_constraintEnd_toStartOf="@id/actionPlayPause" 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_constraintStart_toStartOf="@id/header_title"
app:layout_constraintBottom_toTopOf="@id/media_action_barrier_top"
app:layout_constraintVertical_bias="0" app:layout_constraintVertical_bias="0"
app:layout_constraintHorizontal_bias="0" /> app:layout_constraintHorizontal_bias="0" />
@@ -59,10 +58,9 @@
android:layout_height="48dp" android:layout_height="48dp"
android:layout_marginStart="@dimen/qs_media_padding" android:layout_marginStart="@dimen/qs_media_padding"
android:layout_marginEnd="@dimen/qs_media_padding" android:layout_marginEnd="@dimen/qs_media_padding"
android:layout_marginBottom="0dp" android:layout_marginBottom="@dimen/qs_media_padding"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/media_seamless" app:layout_constraintBottom_toTopOf="@id/media_action_barrier_top" />
app:layout_constraintBottom_toBottomOf="@id/header_artist" />
<!-- <!--
The bottom row of action buttons should remain in the same order when RTL, so their constraints The bottom row of action buttons should remain in the same order when RTL, so their constraints
@@ -76,7 +74,6 @@
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/media_progress_bar" app:layout_constraintRight_toLeftOf="@id/media_progress_bar"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/header_artist"
app:layout_constraintHorizontal_chainStyle="spread" /> app:layout_constraintHorizontal_chainStyle="spread" />
<Constraint <Constraint
@@ -86,7 +83,6 @@
app:layout_constraintLeft_toRightOf="@id/actionPrev" app:layout_constraintLeft_toRightOf="@id/actionPrev"
app:layout_constraintRight_toLeftOf="@id/actionNext" app:layout_constraintRight_toLeftOf="@id/actionNext"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/header_artist"
app:layout_constraintHorizontal_weight="1" /> app:layout_constraintHorizontal_weight="1" />
<Constraint <Constraint
@@ -95,8 +91,7 @@
android:layout_height="48dp" android:layout_height="48dp"
app:layout_constraintLeft_toRightOf="@id/media_progress_bar" app:layout_constraintLeft_toRightOf="@id/media_progress_bar"
app:layout_constraintRight_toLeftOf="@id/action0" app:layout_constraintRight_toLeftOf="@id/action0"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent" />
app:layout_constraintTop_toBottomOf="@id/header_artist" />
<Constraint <Constraint
android:id="@+id/action0" android:id="@+id/action0"
@@ -104,8 +99,7 @@
android:layout_height="48dp" android:layout_height="48dp"
app:layout_constraintLeft_toRightOf="@id/actionNext" app:layout_constraintLeft_toRightOf="@id/actionNext"
app:layout_constraintRight_toLeftOf="@id/action1" app:layout_constraintRight_toLeftOf="@id/action1"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent" />
app:layout_constraintTop_toBottomOf="@id/header_artist" />
<Constraint <Constraint
android:id="@+id/action1" android:id="@+id/action1"
@@ -113,8 +107,7 @@
android:layout_height="48dp" android:layout_height="48dp"
app:layout_constraintLeft_toRightOf="@id/action0" app:layout_constraintLeft_toRightOf="@id/action0"
app:layout_constraintRight_toLeftOf="@id/action2" app:layout_constraintRight_toLeftOf="@id/action2"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent" />
app:layout_constraintTop_toBottomOf="@id/header_artist" />
<Constraint <Constraint
android:id="@+id/action2" android:id="@+id/action2"
@@ -122,8 +115,7 @@
android:layout_height="48dp" android:layout_height="48dp"
app:layout_constraintLeft_toRightOf="@id/action1" app:layout_constraintLeft_toRightOf="@id/action1"
app:layout_constraintRight_toLeftOf="@id/action3" app:layout_constraintRight_toLeftOf="@id/action3"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"/>
app:layout_constraintTop_toBottomOf="@id/header_artist" />
<Constraint <Constraint
android:id="@+id/action3" android:id="@+id/action3"
@@ -131,8 +123,7 @@
android:layout_height="48dp" android:layout_height="48dp"
app:layout_constraintLeft_toRightOf="@id/action2" app:layout_constraintLeft_toRightOf="@id/action2"
app:layout_constraintRight_toLeftOf="@id/action4" app:layout_constraintRight_toLeftOf="@id/action4"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"/>
app:layout_constraintTop_toBottomOf="@id/header_artist" />
<Constraint <Constraint
android:id="@+id/action4" android:id="@+id/action4"
@@ -140,6 +131,5 @@
android:layout_height="48dp" android:layout_height="48dp"
app:layout_constraintLeft_toRightOf="@id/action3" app:layout_constraintLeft_toRightOf="@id/action3"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent" />
app:layout_constraintTop_toBottomOf="@id/header_artist" />
</ConstraintSet> </ConstraintSet>

View File

@@ -606,12 +606,29 @@ public class MediaControlPanel {
setSemanticButton(genericButtons[i], null, collapsedSet, expandedSet, false); setSemanticButton(genericButtons[i], null, collapsedSet, expandedSet, false);
} }
} }
expandedSet.setVisibility(R.id.media_progress_bar, getSeekBarVisibility());
expandedSet.setAlpha(R.id.media_progress_bar, mSeekBarViewModel.getEnabled() ? 1.0f : 0.0f);
}
// If disabled, set progress bar to INVISIBLE instead of GONE so layout weights still work private int getSeekBarVisibility() {
boolean seekbarEnabled = mSeekBarViewModel.getEnabled(); boolean seekbarEnabled = mSeekBarViewModel.getEnabled();
expandedSet.setVisibility(R.id.media_progress_bar, if (seekbarEnabled) {
seekbarEnabled ? ConstraintSet.VISIBLE : ConstraintSet.INVISIBLE); return ConstraintSet.VISIBLE;
expandedSet.setAlpha(R.id.media_progress_bar, seekbarEnabled ? 1.0f : 0.0f); }
// If disabled and "neighbours" are visible, set progress bar to INVISIBLE instead of GONE
// so layout weights still work.
return areAnyExpandedBottomActionsVisible() ? ConstraintSet.INVISIBLE : ConstraintSet.GONE;
}
private boolean areAnyExpandedBottomActionsVisible() {
ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();
int[] referencedIds = mMediaViewHolder.getActionsTopBarrier().getReferencedIds();
for (int id : referencedIds) {
if (expandedSet.getVisibility(id) == ConstraintSet.VISIBLE) {
return true;
}
}
return false;
} }
private void setSemanticButton(final ImageButton button, MediaAction mediaAction, private void setSemanticButton(final ImageButton button, MediaAction mediaAction,

View File

@@ -24,6 +24,7 @@ import android.widget.ImageButton
import android.widget.ImageView import android.widget.ImageView
import android.widget.SeekBar import android.widget.SeekBar
import android.widget.TextView import android.widget.TextView
import androidx.constraintlayout.widget.Barrier
import com.android.systemui.R import com.android.systemui.R
import com.android.systemui.util.animation.TransitionLayout import com.android.systemui.util.animation.TransitionLayout
@@ -70,6 +71,8 @@ class MediaViewHolder constructor(itemView: View) {
val action3 = itemView.requireViewById<ImageButton>(R.id.action3) val action3 = itemView.requireViewById<ImageButton>(R.id.action3)
val action4 = itemView.requireViewById<ImageButton>(R.id.action4) val action4 = itemView.requireViewById<ImageButton>(R.id.action4)
val actionsTopBarrier = itemView.requireViewById<Barrier>(R.id.media_action_barrier_top)
init { init {
(player.background as IlluminationDrawable).let { (player.background as IlluminationDrawable).let {
it.registerLightSource(seamless) it.registerLightSource(seamless)

View File

@@ -16,6 +16,7 @@
package com.android.systemui.media package com.android.systemui.media
import org.mockito.Mockito.`when` as whenever
import android.content.Intent import android.content.Intent
import android.graphics.Color import android.graphics.Color
import android.graphics.drawable.GradientDrawable import android.graphics.drawable.GradientDrawable
@@ -35,6 +36,7 @@ import android.widget.ImageButton
import android.widget.ImageView import android.widget.ImageView
import android.widget.SeekBar import android.widget.SeekBar
import android.widget.TextView import android.widget.TextView
import androidx.constraintlayout.widget.Barrier
import androidx.constraintlayout.widget.ConstraintSet import androidx.constraintlayout.widget.ConstraintSet
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
@@ -63,7 +65,6 @@ import org.mockito.Mockito.never
import org.mockito.Mockito.times import org.mockito.Mockito.times
import org.mockito.Mockito.verify import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
private const val KEY = "TEST_KEY" private const val KEY = "TEST_KEY"
private const val APP = "APP" private const val APP = "APP"
@@ -120,6 +121,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
private lateinit var actionPlayPause: ImageButton private lateinit var actionPlayPause: ImageButton
private lateinit var actionNext: ImageButton private lateinit var actionNext: ImageButton
private lateinit var actionPrev: ImageButton private lateinit var actionPrev: ImageButton
private lateinit var actionsTopBarrier: Barrier
@Mock private lateinit var longPressText: TextView @Mock private lateinit var longPressText: TextView
@Mock private lateinit var handler: Handler @Mock private lateinit var handler: Handler
private lateinit var settings: ImageButton private lateinit var settings: ImageButton
@@ -176,6 +178,21 @@ public class MediaControlPanelTest : SysuiTestCase() {
actionPrev = ImageButton(context).also { it.setId(R.id.actionPrev) } actionPrev = ImageButton(context).also { it.setId(R.id.actionPrev) }
actionNext = ImageButton(context).also { it.setId(R.id.actionNext) } actionNext = ImageButton(context).also { it.setId(R.id.actionNext) }
actionsTopBarrier =
Barrier(context).also {
it.id = R.id.media_action_barrier_top
it.referencedIds =
intArrayOf(
actionPrev.id,
seekBar.id,
actionNext.id,
action0.id,
action1.id,
action2.id,
action3.id,
action4.id)
}
initMediaViewHolderMocks() initMediaViewHolderMocks()
// Create media session // Create media session
@@ -254,6 +271,8 @@ public class MediaControlPanelTest : SysuiTestCase() {
whenever(viewHolder.cancelText).thenReturn(cancelText) whenever(viewHolder.cancelText).thenReturn(cancelText)
whenever(viewHolder.dismiss).thenReturn(dismiss) whenever(viewHolder.dismiss).thenReturn(dismiss)
whenever(viewHolder.dismissText).thenReturn(dismissText) whenever(viewHolder.dismissText).thenReturn(dismissText)
whenever(viewHolder.actionsTopBarrier).thenReturn(actionsTopBarrier)
} }
@After @After
@@ -315,6 +334,35 @@ public class MediaControlPanelTest : SysuiTestCase() {
verify(expandedSet).setVisibility(R.id.action4, ConstraintSet.GONE) verify(expandedSet).setVisibility(R.id.action4, ConstraintSet.GONE)
} }
@Test
fun bind_seekBarDisabled_seekBarVisibilityIsSetToInvisible() {
whenever(seekBarViewModel.getEnabled()).thenReturn(false)
val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play)
val semanticActions = MediaButton(
playOrPause = MediaAction(icon, Runnable {}, "play"),
nextOrCustom = MediaAction(icon, Runnable {}, "next")
)
val state = mediaData.copy(semanticActions = semanticActions)
player.attachPlayer(viewHolder)
player.bindPlayer(state, PACKAGE)
verify(expandedSet).setVisibility(R.id.media_progress_bar, ConstraintSet.INVISIBLE)
}
@Test
fun bind_seekBarDisabled_noActions_seekBarVisibilityIsSetToGone() {
whenever(seekBarViewModel.getEnabled()).thenReturn(false)
val state = mediaData.copy(semanticActions = MediaButton())
player.attachPlayer(viewHolder)
player.bindPlayer(state, PACKAGE)
verify(expandedSet).setVisibility(R.id.media_progress_bar, ConstraintSet.INVISIBLE)
}
@Test @Test
fun bindNotificationActions() { fun bindNotificationActions() {
val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play) val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play)

View File

@@ -0,0 +1,24 @@
package com.android.systemui.media
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.LayoutInflater
import android.widget.FrameLayout
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper
class MediaViewHolderTest : SysuiTestCase() {
@Test
fun create_succeeds() {
val inflater = LayoutInflater.from(context)
val parent = FrameLayout(context)
MediaViewHolder.create(inflater, parent)
}
}