From c00205a3adb63a16e72226a53f579917055397ad Mon Sep 17 00:00:00 2001 From: cecilia Date: Wed, 2 Jun 2021 13:00:41 -0400 Subject: [PATCH] Update Smartspace media recommendation card based on Droidfood's feedbacks. - Sort the active media player before the Smartspace media recommendation card. - Add the click ripple effect to the media recs. Fixes: 189944948 Fixes: 189949373 Bug: 186586388 Test: Local builds Change-Id: I55ba2f7c8c03fb049ff154c9fb4be99323683015 --- .../media_smartspace_recommendations.xml | 120 ++++++++++++------ .../xml/media_recommendation_collapsed.xml | 34 ++--- .../res/xml/media_recommendation_expanded.xml | 28 ++-- .../systemui/media/MediaCarouselController.kt | 36 ++++-- .../media/MediaCarouselScrollHandler.kt | 13 +- .../systemui/media/MediaControlPanel.java | 14 +- .../systemui/media/MediaDataManager.kt | 2 +- .../media/RecommendationViewHolder.kt | 24 +++- 8 files changed, 178 insertions(+), 93 deletions(-) diff --git a/packages/SystemUI/res/layout/media_smartspace_recommendations.xml b/packages/SystemUI/res/layout/media_smartspace_recommendations.xml index 2ffc16b35b9f3..645dba4459a47 100644 --- a/packages/SystemUI/res/layout/media_smartspace_recommendations.xml +++ b/packages/SystemUI/res/layout/media_smartspace_recommendations.xml @@ -63,65 +63,101 @@ android:breakStrategy="balanced" android:hyphenationFrequency="none"/> - + android:background="@drawable/qs_media_light_source"> + + - + android:background="@drawable/qs_media_light_source"> + + - + android:background="@drawable/qs_media_light_source"> + + - + android:background="@drawable/qs_media_light_source"> + + - + android:background="@drawable/qs_media_light_source"> + + - + android:background="@drawable/qs_media_light_source"> + + it == key } + mediaCarouselScrollHandler + .scrollToPlayer(previousVisibleIndex, activeMediaIndex) + } ?: { + mediaCarouselScrollHandler.scrollToPlayer(destIndex = activeMediaIndex) + } } } } @@ -310,6 +317,8 @@ class MediaCarouselController @Inject constructor( private fun addOrUpdatePlayer(key: String, oldKey: String?, data: MediaData): Boolean { val dataCopy = data.copy(backgroundColor = bgColor) val existingPlayer = MediaPlayerData.getMediaPlayer(key, oldKey) + val curVisibleMediaKey = MediaPlayerData.playerKeys() + .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex) if (existingPlayer == null) { var newPlayer = mediaControlPanelFactory.get() newPlayer.attachPlayer( @@ -322,12 +331,12 @@ class MediaCarouselController @Inject constructor( newPlayer.setListening(currentlyExpanded) MediaPlayerData.addMediaPlayer(key, dataCopy, newPlayer) updatePlayerToState(newPlayer, noAnimation = true) - reorderAllPlayers() + reorderAllPlayers(curVisibleMediaKey) } else { existingPlayer.bindPlayer(dataCopy, key) MediaPlayerData.addMediaPlayer(key, dataCopy, existingPlayer) if (visualStabilityManager.isReorderingAllowed || shouldScrollToActivePlayer) { - reorderAllPlayers() + reorderAllPlayers(curVisibleMediaKey) } else { needsReordering = true } @@ -367,9 +376,11 @@ class MediaCarouselController @Inject constructor( ViewGroup.LayoutParams.WRAP_CONTENT) newRecs.recommendationViewHolder?.recommendations?.setLayoutParams(lp) newRecs.bindRecommendation(data.copy(backgroundColor = bgColor)) + val curVisibleMediaKey = MediaPlayerData.playerKeys() + .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex) MediaPlayerData.addMediaRecommendation(key, data, newRecs, shouldPrioritize) updatePlayerToState(newRecs, noAnimation = true) - reorderAllPlayers() + reorderAllPlayers(curVisibleMediaKey) updatePageIndicator() mediaCarousel.requiresRemeasuring = true // Check postcondition: mediaContent should have the same number of children as there are @@ -719,9 +730,8 @@ internal object MediaPlayerData { ) private val comparator = - compareByDescending - { if (shouldPrioritizeSs) it.isSsMediaRec else !it.isSsMediaRec } - .thenByDescending { it.data.isPlaying } + compareByDescending { it.data.isPlaying } + .thenByDescending { if (shouldPrioritizeSs) it.isSsMediaRec else !it.isSsMediaRec } .thenByDescending { it.data.isLocalSession } .thenByDescending { !it.data.resumption } .thenByDescending { it.updateTime } @@ -771,8 +781,10 @@ internal object MediaPlayerData { fun players() = mediaPlayers.values + fun playerKeys() = mediaPlayers.keys + /** Returns the index of the first non-timeout media. */ - fun activeMediaIndex(): Int { + fun firstActiveMediaIndex(): Int { mediaPlayers.entries.forEachIndexed { index, e -> if (!e.key.isSsMediaRec && e.key.data.active) { return index @@ -791,8 +803,6 @@ internal object MediaPlayerData { return null } - fun playerKeys() = mediaPlayers.keys - @VisibleForTesting fun clear() { mediaData.clear() diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt index 45ceceba5cba5..eb3549789c19b 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt @@ -559,8 +559,17 @@ class MediaCarouselScrollHandler( scrollView.relativeScrollX = 0 } - fun scrollToActivePlayer(activePlayerIndex: Int) { - val destIndex = Math.min(mediaContent.getChildCount() - 1, activePlayerIndex) + /** + * Smooth scroll to the destination player. + * + * @param sourceIndex optional source index to indicate where the scroll should begin. + * @param destIndex destination index to indicate where the scroll should end. + */ + fun scrollToPlayer(sourceIndex: Int = -1, destIndex: Int) { + if (sourceIndex >= 0 && sourceIndex < mediaContent.childCount) { + scrollView.relativeScrollX = sourceIndex * playerWidthPlusPadding + } + val destIndex = Math.min(mediaContent.getChildCount() - 1, destIndex) val view = mediaContent.getChildAt(destIndex) // We need to post this to wait for the active player becomes visible. mainExecutor.executeDelayed({ diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java index 4201411b168af..c2b580773424f 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java @@ -36,6 +36,7 @@ import android.media.session.PlaybackState; import android.text.Layout; import android.util.Log; import android.view.View; +import android.view.ViewGroup; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; @@ -45,7 +46,6 @@ import androidx.annotation.Nullable; import androidx.annotation.UiThread; import androidx.constraintlayout.widget.ConstraintSet; -import com.android.settingslib.Utils; import com.android.settingslib.widget.AdaptiveIcon; import com.android.systemui.R; import com.android.systemui.animation.ActivityLaunchAnimator; @@ -542,7 +542,10 @@ public class MediaControlPanel { mContext.getString(R.string.controls_media_smartspace_rec_description, appLabel)); List mediaCoverItems = mRecommendationViewHolder.getMediaCoverItems(); + List mediaCoverContainers = mRecommendationViewHolder.getMediaCoverContainers(); List mediaCoverItemsResIds = mRecommendationViewHolder.getMediaCoverItemsResIds(); + List mediaCoverContainersResIds = + mRecommendationViewHolder.getMediaCoverContainersResIds(); ConstraintSet expandedSet = mMediaViewController.getExpandedLayout(); ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout(); int mediaRecommendationNum = Math.min(mediaRecommendationList.size(), @@ -561,7 +564,8 @@ public class MediaControlPanel { mediaCoverImageView.setImageIcon(recommendation.getIcon()); // Set up the media item's click listener if applicable. - setSmartspaceRecItemOnClickListener(mediaCoverImageView, recommendation); + ViewGroup mediaCoverContainer = mediaCoverContainers.get(uiComponentIndex); + setSmartspaceRecItemOnClickListener(mediaCoverContainer, recommendation); // Set up the accessibility label for the media item. String artistName = recommendation.getExtras() @@ -581,12 +585,18 @@ public class MediaControlPanel { if (uiComponentIndex < MEDIA_RECOMMENDATION_ITEMS_PER_ROW) { setVisibleAndAlpha(collapsedSet, mediaCoverItemsResIds.get(uiComponentIndex), true); + setVisibleAndAlpha(collapsedSet, + mediaCoverContainersResIds.get(uiComponentIndex), true); } else { setVisibleAndAlpha(collapsedSet, mediaCoverItemsResIds.get(uiComponentIndex), false); + setVisibleAndAlpha(collapsedSet, + mediaCoverContainersResIds.get(uiComponentIndex), false); } setVisibleAndAlpha(expandedSet, mediaCoverItemsResIds.get(uiComponentIndex), true); + setVisibleAndAlpha(expandedSet, + mediaCoverContainersResIds.get(uiComponentIndex), true); uiComponentIndex++; } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt index 13c7f71f53ee6..5b1e039ad0f8c 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt @@ -437,10 +437,10 @@ class MediaDataManager( * connection session. */ fun dismissSmartspaceRecommendation(key: String, delay: Long) { - Log.d(TAG, "Dismissing Smartspace media target") if (smartspaceMediaData.targetId != key) { return } + Log.d(TAG, "Dismissing Smartspace media target") if (smartspaceMediaData.isActive) { smartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA.copy( targetId = smartspaceMediaData.targetId) diff --git a/packages/SystemUI/src/com/android/systemui/media/RecommendationViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/RecommendationViewHolder.kt index 78619d652c6c0..142628cff448f 100644 --- a/packages/SystemUI/src/com/android/systemui/media/RecommendationViewHolder.kt +++ b/packages/SystemUI/src/com/android/systemui/media/RecommendationViewHolder.kt @@ -40,6 +40,13 @@ class RecommendationViewHolder private constructor(itemView: View) { itemView.requireViewById(R.id.media_cover4), itemView.requireViewById(R.id.media_cover5), itemView.requireViewById(R.id.media_cover6)) + val mediaCoverContainers = listOf( + itemView.requireViewById(R.id.media_cover1_container), + itemView.requireViewById(R.id.media_cover2_container), + itemView.requireViewById(R.id.media_cover3_container), + itemView.requireViewById(R.id.media_cover4_container), + itemView.requireViewById(R.id.media_cover5_container), + itemView.requireViewById(R.id.media_cover6_container)) val mediaCoverItemsResIds = listOf<@IntegerRes Int>( R.id.media_cover1, R.id.media_cover2, @@ -47,6 +54,13 @@ class RecommendationViewHolder private constructor(itemView: View) { R.id.media_cover4, R.id.media_cover5, R.id.media_cover6) + val mediaCoverContainersResIds = listOf<@IntegerRes Int>( + R.id.media_cover1_container, + R.id.media_cover2_container, + R.id.media_cover3_container, + R.id.media_cover4_container, + R.id.media_cover5_container, + R.id.media_cover6_container) // Settings/Guts screen val longPressText = itemView.requireViewById(R.id.remove_text) @@ -58,7 +72,7 @@ class RecommendationViewHolder private constructor(itemView: View) { init { (recommendations.background as IlluminationDrawable).let { background -> - mediaCoverItems.forEach { background.registerLightSource(it) } + mediaCoverContainers.forEach { background.registerLightSource(it) } background.registerLightSource(cancel) background.registerLightSource(dismiss) background.registerLightSource(dismissLabel) @@ -100,7 +114,13 @@ class RecommendationViewHolder private constructor(itemView: View) { R.id.media_cover3, R.id.media_cover4, R.id.media_cover5, - R.id.media_cover6 + R.id.media_cover6, + R.id.media_cover1_container, + R.id.media_cover2_container, + R.id.media_cover3_container, + R.id.media_cover4_container, + R.id.media_cover5_container, + R.id.media_cover6_container ) // Res Ids for the components on the guts panel.