Merge changes from topic "b224749799" into tm-dev am: 123c1b0954
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17723163
Change-Id: I4e518a96980593f4984661af8715b683ac6eb20d
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 1b6d1d5..c9e888e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -837,7 +837,14 @@
scrubbingTimeViewsEnabled(semanticActions) && hideWhenScrubbing && mIsScrubbing;
boolean visible = mediaAction != null && !shouldBeHiddenDueToScrubbing;
- setVisibleAndAlpha(expandedSet, buttonId, visible);
+ int notVisibleValue;
+ if ((buttonId == R.id.actionPrev && semanticActions.getReservePrev())
+ || (buttonId == R.id.actionNext && semanticActions.getReserveNext())) {
+ notVisibleValue = ConstraintSet.INVISIBLE;
+ } else {
+ notVisibleValue = ConstraintSet.GONE;
+ }
+ setVisibleAndAlpha(expandedSet, buttonId, visible, notVisibleValue);
setVisibleAndAlpha(collapsedSet, buttonId, visible && showInCompact);
}
@@ -1177,7 +1184,12 @@
}
private void setVisibleAndAlpha(ConstraintSet set, int actionId, boolean visible) {
- set.setVisibility(actionId, visible ? ConstraintSet.VISIBLE : ConstraintSet.GONE);
+ setVisibleAndAlpha(set, actionId, visible, ConstraintSet.GONE);
+ }
+
+ private void setVisibleAndAlpha(ConstraintSet set, int actionId, boolean visible,
+ int notVisibleValue) {
+ set.setVisibility(actionId, visible ? ConstraintSet.VISIBLE : notVisibleValue);
set.setAlpha(actionId, visible ? 1.0f : 0.0f);
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
index bc8cca5..f6d531b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
@@ -149,23 +149,31 @@
/**
* Play/pause button
*/
- var playOrPause: MediaAction? = null,
+ val playOrPause: MediaAction? = null,
/**
* Next button, or custom action
*/
- var nextOrCustom: MediaAction? = null,
+ val nextOrCustom: MediaAction? = null,
/**
* Previous button, or custom action
*/
- var prevOrCustom: MediaAction? = null,
+ val prevOrCustom: MediaAction? = null,
/**
* First custom action space
*/
- var custom0: MediaAction? = null,
+ val custom0: MediaAction? = null,
/**
* Second custom action space
*/
- var custom1: MediaAction? = null
+ val custom1: MediaAction? = null,
+ /**
+ * Whether to reserve the empty space when the nextOrCustom is null
+ */
+ val reserveNext: Boolean = false,
+ /**
+ * Whether to reserve the empty space when the prevOrCustom is null
+ */
+ val reservePrev: Boolean = false
) {
fun getActionById(id: Int): MediaAction? {
return when (id) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 0ad15fa..0d65514 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -173,10 +173,6 @@
// Maximum number of actions allowed in expanded view
@JvmField
val MAX_NOTIFICATION_ACTIONS = MediaViewHolder.genericButtonIds.size
-
- /** Maximum number of [PlaybackState.CustomAction] buttons supported */
- @JvmField
- val MAX_CUSTOM_ACTIONS = 4
}
private val themeText = com.android.settingslib.Utils.getColorAttr(context,
@@ -795,71 +791,74 @@
*/
private fun createActionsFromState(packageName: String, controller: MediaController):
MediaButton? {
- val actions = MediaButton()
- controller.playbackState?.let { state ->
- // First, check for standard actions
- actions.playOrPause = if (isConnectingState(state.state)) {
- // Spinner needs to be animating to render anything. Start it here.
- val drawable = context.getDrawable(
- com.android.internal.R.drawable.progress_small_material)
- (drawable as Animatable).start()
- MediaAction(
- drawable,
- null, // no action to perform when clicked
- context.getString(R.string.controls_media_button_connecting),
- context.getDrawable(R.drawable.ic_media_connecting_container),
- // Specify a rebind id to prevent the spinner from restarting on later binds.
- com.android.internal.R.drawable.progress_small_material
- )
- } else if (isPlayingState(state.state)) {
- getStandardAction(controller, state.actions, PlaybackState.ACTION_PAUSE)
- } else {
- getStandardAction(controller, state.actions, PlaybackState.ACTION_PLAY)
- }
- val prevButton = getStandardAction(controller, state.actions,
- PlaybackState.ACTION_SKIP_TO_PREVIOUS)
- val nextButton = getStandardAction(controller, state.actions,
- PlaybackState.ACTION_SKIP_TO_NEXT)
-
- // Then, check for custom actions
- val customActions = MutableList<MediaAction?>(MAX_CUSTOM_ACTIONS) { null }
- var customCount = 0
- for (i in 0..(MAX_CUSTOM_ACTIONS - 1)) {
- getCustomAction(state, packageName, controller, customCount)?.let {
- customActions[customCount++] = it
- }
- }
-
- // Finally, assign the remaining button slots: play/pause A B C D
- // A = previous, else custom action (if not reserved)
- // B = next, else custom action (if not reserved)
- // C and D are always custom actions
- val reservePrev = controller.extras?.getBoolean(
- MediaConstants.SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV) == true
- val reserveNext = controller.extras?.getBoolean(
- MediaConstants.SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT) == true
- var customIdx = 0
-
- actions.prevOrCustom = if (prevButton != null) {
- prevButton
- } else if (!reservePrev) {
- customActions[customIdx++]
- } else {
- null
- }
-
- actions.nextOrCustom = if (nextButton != null) {
- nextButton
- } else if (!reserveNext) {
- customActions[customIdx++]
- } else {
- null
- }
-
- actions.custom0 = customActions[customIdx++]
- actions.custom1 = customActions[customIdx++]
+ val state = controller.playbackState
+ if (state == null) {
+ return MediaButton()
}
- return actions
+ // First, check for} standard actions
+ val playOrPause = if (isConnectingState(state.state)) {
+ // Spinner needs to be animating to render anything. Start it here.
+ val drawable = context.getDrawable(
+ com.android.internal.R.drawable.progress_small_material)
+ (drawable as Animatable).start()
+ MediaAction(
+ drawable,
+ null, // no action to perform when clicked
+ context.getString(R.string.controls_media_button_connecting),
+ context.getDrawable(R.drawable.ic_media_connecting_container),
+ // Specify a rebind id to prevent the spinner from restarting on later binds.
+ com.android.internal.R.drawable.progress_small_material
+ )
+ } else if (isPlayingState(state.state)) {
+ getStandardAction(controller, state.actions, PlaybackState.ACTION_PAUSE)
+ } else {
+ getStandardAction(controller, state.actions, PlaybackState.ACTION_PLAY)
+ }
+ val prevButton = getStandardAction(controller, state.actions,
+ PlaybackState.ACTION_SKIP_TO_PREVIOUS)
+ val nextButton = getStandardAction(controller, state.actions,
+ PlaybackState.ACTION_SKIP_TO_NEXT)
+
+ // Then, create a way to build any custom actions that will be needed
+ val customActions = state.customActions.asSequence().filterNotNull().map {
+ getCustomAction(state, packageName, controller, it)
+ }.iterator()
+ fun nextCustomAction() = if (customActions.hasNext()) customActions.next() else null
+
+ // Finally, assign the remaining button slots: play/pause A B C D
+ // A = previous, else custom action (if not reserved)
+ // B = next, else custom action (if not reserved)
+ // C and D are always custom actions
+ val reservePrev = controller.extras?.getBoolean(
+ MediaConstants.SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV) == true
+ val reserveNext = controller.extras?.getBoolean(
+ MediaConstants.SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT) == true
+
+ val prevOrCustom = if (prevButton != null) {
+ prevButton
+ } else if (!reservePrev) {
+ nextCustomAction()
+ } else {
+ null
+ }
+
+ val nextOrCustom = if (nextButton != null) {
+ nextButton
+ } else if (!reserveNext) {
+ nextCustomAction()
+ } else {
+ null
+ }
+
+ return MediaButton(
+ playOrPause,
+ nextOrCustom,
+ prevOrCustom,
+ nextCustomAction(),
+ nextCustomAction(),
+ reserveNext,
+ reservePrev
+ )
}
/**
@@ -938,18 +937,12 @@
state: PlaybackState,
packageName: String,
controller: MediaController,
- index: Int
- ): MediaAction? {
- if (state.customActions.size <= index || state.customActions[index] == null) {
- if (DEBUG) { Log.d(TAG, "not enough actions or action was null at $index") }
- return null
- }
-
- val it = state.customActions[index]
+ customAction: PlaybackState.CustomAction
+ ): MediaAction {
return MediaAction(
- Icon.createWithResource(packageName, it.icon).loadDrawable(context),
- { controller.transportControls.sendCustomAction(it, it.extras) },
- it.name,
+ Icon.createWithResource(packageName, customAction.icon).loadDrawable(context),
+ { controller.transportControls.sendCustomAction(customAction, customAction.extras) },
+ customAction.name,
null
)
}
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 a39ae6c..1bc8881 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -449,6 +449,64 @@
}
@Test
+ fun bindSemanticActions_reservedPrev() {
+ val icon = context.getDrawable(android.R.drawable.ic_media_play)
+ val bg = context.getDrawable(R.drawable.qs_media_round_button_background)
+
+ // Setup button state: no prev or next button and their slots reserved
+ val semanticActions = MediaButton(
+ playOrPause = MediaAction(icon, Runnable {}, "play", bg),
+ nextOrCustom = null,
+ prevOrCustom = null,
+ custom0 = MediaAction(icon, null, "custom 0", bg),
+ custom1 = MediaAction(icon, null, "custom 1", bg),
+ false,
+ true
+ )
+ val state = mediaData.copy(semanticActions = semanticActions)
+
+ player.attachPlayer(viewHolder)
+ player.bindPlayer(state, PACKAGE)
+
+ assertThat(actionPrev.isEnabled()).isFalse()
+ assertThat(actionPrev.drawable).isNull()
+ verify(expandedSet).setVisibility(R.id.actionPrev, ConstraintSet.INVISIBLE)
+
+ assertThat(actionNext.isEnabled()).isFalse()
+ assertThat(actionNext.drawable).isNull()
+ verify(expandedSet).setVisibility(R.id.actionNext, ConstraintSet.GONE)
+ }
+
+ @Test
+ fun bindSemanticActions_reservedNext() {
+ val icon = context.getDrawable(android.R.drawable.ic_media_play)
+ val bg = context.getDrawable(R.drawable.qs_media_round_button_background)
+
+ // Setup button state: no prev or next button and their slots reserved
+ val semanticActions = MediaButton(
+ playOrPause = MediaAction(icon, Runnable {}, "play", bg),
+ nextOrCustom = null,
+ prevOrCustom = null,
+ custom0 = MediaAction(icon, null, "custom 0", bg),
+ custom1 = MediaAction(icon, null, "custom 1", bg),
+ true,
+ false
+ )
+ val state = mediaData.copy(semanticActions = semanticActions)
+
+ player.attachPlayer(viewHolder)
+ player.bindPlayer(state, PACKAGE)
+
+ assertThat(actionPrev.isEnabled()).isFalse()
+ assertThat(actionPrev.drawable).isNull()
+ verify(expandedSet).setVisibility(R.id.actionPrev, ConstraintSet.GONE)
+
+ assertThat(actionNext.isEnabled()).isFalse()
+ assertThat(actionNext.drawable).isNull()
+ verify(expandedSet).setVisibility(R.id.actionNext, ConstraintSet.INVISIBLE)
+ }
+
+ @Test
fun bind_seekBarDisabled_seekBarVisibilityIsSetToInvisible() {
whenever(seekBarViewModel.getEnabled()).thenReturn(false)
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 8582499..7ec31a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -838,6 +838,9 @@
assertThat(actions.custom1).isNotNull()
assertThat(actions.custom1!!.contentDescription).isEqualTo(customDesc[1])
+
+ assertThat(actions.reserveNext).isTrue()
+ assertThat(actions.reservePrev).isTrue()
}
@Test