Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c00205a3 authored by cecilia's avatar cecilia Committed by Cecilia Hong
Browse files

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
parent 2aa8be16
Loading
Loading
Loading
Loading
+83 −47
Original line number Diff line number Diff line
@@ -63,65 +63,101 @@
        android:breakStrategy="balanced"
        android:hyphenationFrequency="none"/>

    <ImageView
        android:id="@+id/media_cover1"
    <FrameLayout
        android:id="@+id/media_cover1_container"
        android:layout_width="0dp"
        android:layout_height="@dimen/qs_aa_media_rec_album_size_collapsed"
        android:background="@drawable/qs_media_light_source">
        <ImageView
            android:id="@+id/media_cover1"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:adjustViewBounds="true"
            android:background="@drawable/bg_smartspace_media_item"
            style="@style/MediaPlayer.Album"
            android:clipToOutline="true"
            android:scaleType="centerCrop"/>
    </FrameLayout>

    <ImageView
        android:id="@+id/media_cover2"
    <FrameLayout
        android:id="@+id/media_cover2_container"
        android:layout_width="0dp"
        android:layout_height="@dimen/qs_aa_media_rec_album_size_collapsed"
        android:background="@drawable/qs_media_light_source">
        <ImageView
            android:id="@+id/media_cover2"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:adjustViewBounds="true"
            android:background="@drawable/bg_smartspace_media_item"
            style="@style/MediaPlayer.Album"
            android:clipToOutline="true"
            android:scaleType="centerCrop"/>
    </FrameLayout>

    <ImageView
        android:id="@+id/media_cover3"
    <FrameLayout
        android:id="@+id/media_cover3_container"
        android:layout_width="0dp"
        android:layout_height="@dimen/qs_aa_media_rec_album_size_collapsed"
        android:background="@drawable/qs_media_light_source">
        <ImageView
            android:id="@+id/media_cover3"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:adjustViewBounds="true"
            android:background="@drawable/bg_smartspace_media_item"
            style="@style/MediaPlayer.Album"
            android:clipToOutline="true"
            android:scaleType="centerCrop"/>
    </FrameLayout>

    <ImageView
        android:id="@+id/media_cover4"
    <FrameLayout
        android:id="@+id/media_cover4_container"
        android:layout_width="0dp"
        android:layout_height="@dimen/qs_aa_media_rec_album_size_collapsed"
        android:background="@drawable/qs_media_light_source">
        <ImageView
            android:id="@+id/media_cover4"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:adjustViewBounds="true"
            android:background="@drawable/bg_smartspace_media_item"
            style="@style/MediaPlayer.Album"
            android:clipToOutline="true"
            android:scaleType="centerCrop"/>
    </FrameLayout>

    <ImageView
        android:id="@+id/media_cover5"
    <FrameLayout
        android:id="@+id/media_cover5_container"
        android:layout_width="0dp"
        android:layout_height="@dimen/qs_aa_media_rec_album_size_collapsed"
        android:background="@drawable/qs_media_light_source">
        <ImageView
            android:id="@+id/media_cover5"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:adjustViewBounds="true"
            android:background="@drawable/bg_smartspace_media_item"
            style="@style/MediaPlayer.Album"
            android:clipToOutline="true"
            android:scaleType="centerCrop"/>
    </FrameLayout>

    <ImageView
        android:id="@+id/media_cover6"
    <FrameLayout
        android:id="@+id/media_cover6_container"
        android:layout_width="0dp"
        android:layout_height="@dimen/qs_aa_media_rec_album_size_collapsed"
        android:background="@drawable/qs_media_light_source">
        <ImageView
            android:id="@+id/media_cover6"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:adjustViewBounds="true"
            android:background="@drawable/bg_smartspace_media_item"
            style="@style/MediaPlayer.Album"
            android:clipToOutline="true"
            android:scaleType="centerCrop"/>
    </FrameLayout>

    <!-- Long press menu -->
    <TextView
+17 −17
Original line number Diff line number Diff line
@@ -38,7 +38,7 @@
        app:layout_constraintHorizontal_bias="0" />

    <Constraint
        android:id="@+id/media_cover1"
        android:id="@+id/media_cover1_container"
        android:layout_width="0dp"
        android:layout_height="@dimen/qs_aa_media_rec_album_size_collapsed"
        app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_collapsed"
@@ -48,13 +48,13 @@
        android:layout_marginBottom="@dimen/qs_media_padding"
        android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin"
        app:layout_constraintStart_toEndOf="@id/media_vertical_start_guideline"
        app:layout_constraintEnd_toStartOf="@id/media_cover2"
        app:layout_constraintEnd_toStartOf="@id/media_cover2_container"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintHorizontal_bias="1"
        android:visibility="gone" />

    <Constraint
        android:id="@+id/media_cover2"
        android:id="@+id/media_cover2_container"
        android:layout_width="0dp"
        android:layout_height="@dimen/qs_aa_media_rec_album_size_collapsed"
        app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_collapsed"
@@ -63,14 +63,14 @@
        android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="@id/media_cover1"
        app:layout_constraintEnd_toStartOf="@id/media_cover3"
        app:layout_constraintStart_toEndOf="@id/media_cover1_container"
        app:layout_constraintEnd_toStartOf="@id/media_cover3_container"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintHorizontal_bias="1"
        android:visibility="gone" />

    <Constraint
        android:id="@+id/media_cover3"
        android:id="@+id/media_cover3_container"
        android:layout_width="0dp"
        android:layout_height="@dimen/qs_aa_media_rec_album_size_collapsed"
        app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_collapsed"
@@ -78,45 +78,45 @@
        android:layout_marginBottom="@dimen/qs_media_padding"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="@id/media_cover2"
        app:layout_constraintStart_toEndOf="@id/media_cover2_container"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintHorizontal_bias="1"
        android:visibility="gone" />

    <Constraint
        android:id="@+id/media_cover4"
        android:id="@+id/media_cover4_container"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin"
        app:layout_constraintTop_toBottomOf="@+id/media_cover1"
        app:layout_constraintTop_toBottomOf="@+id/media_cover1_container"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="@id/media_vertical_start_guideline"
        app:layout_constraintEnd_toStartOf="@id/media_cover5"
        app:layout_constraintEnd_toStartOf="@id/media_cover5_container"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintHorizontal_bias="1"
        android:visibility="gone" />

    <Constraint
        android:id="@+id/media_cover5"
        android:id="@+id/media_cover5_container"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin"
        app:layout_constraintTop_toBottomOf="@+id/media_cover2"
        app:layout_constraintTop_toBottomOf="@+id/media_cover2_container"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="@+id/media_cover4"
        app:layout_constraintEnd_toStartOf="@+id/media_cover6"
        app:layout_constraintStart_toEndOf="@+id/media_cover4_container"
        app:layout_constraintEnd_toStartOf="@+id/media_cover6_container"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintHorizontal_bias="1"
        android:visibility="gone" />

    <Constraint
        android:id="@+id/media_cover6"
        android:id="@+id/media_cover6_container"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintTop_toBottomOf="@id/media_cover3"
        app:layout_constraintTop_toBottomOf="@id/media_cover3_container"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="@id/media_cover5"
        app:layout_constraintStart_toEndOf="@id/media_cover5_container"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintHorizontal_bias="1"
+14 −14
Original line number Diff line number Diff line
@@ -38,7 +38,7 @@
        app:layout_constraintHorizontal_bias="0" />

    <Constraint
        android:id="@+id/media_cover1"
        android:id="@+id/media_cover1_container"
        android:layout_width="0dp"
        android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
        app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded"
@@ -48,7 +48,7 @@
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@+id/media_horizontal_center_guideline"
        app:layout_constraintStart_toEndOf="@id/media_vertical_start_guideline"
        app:layout_constraintEnd_toStartOf="@id/media_cover2"
        app:layout_constraintEnd_toStartOf="@id/media_cover2_container"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintHorizontal_bias="1"
        app:layout_constraintVertical_chainStyle="packed"
@@ -56,7 +56,7 @@
        android:visibility="gone" />

    <Constraint
        android:id="@+id/media_cover2"
        android:id="@+id/media_cover2_container"
        android:layout_width="0dp"
        android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
        app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded"
@@ -65,8 +65,8 @@
        android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@+id/media_horizontal_center_guideline"
        app:layout_constraintStart_toEndOf="@id/media_cover1"
        app:layout_constraintEnd_toStartOf="@id/media_cover3"
        app:layout_constraintStart_toEndOf="@id/media_cover1_container"
        app:layout_constraintEnd_toStartOf="@id/media_cover3_container"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintHorizontal_bias="1"
        app:layout_constraintVertical_chainStyle="packed"
@@ -74,7 +74,7 @@
        android:visibility="gone" />

    <Constraint
        android:id="@+id/media_cover3"
        android:id="@+id/media_cover3_container"
        android:layout_width="0dp"
        android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
        app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded"
@@ -82,7 +82,7 @@
        android:layout_marginBottom="@dimen/qs_aa_media_rec_album_margin"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@+id/media_horizontal_center_guideline"
        app:layout_constraintStart_toEndOf="@id/media_cover2"
        app:layout_constraintStart_toEndOf="@id/media_cover2_container"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintHorizontal_bias="1"
@@ -91,7 +91,7 @@
        android:visibility="gone" />

    <Constraint
        android:id="@+id/media_cover4"
        android:id="@+id/media_cover4_container"
        android:layout_width="0dp"
        android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
        app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded"
@@ -101,7 +101,7 @@
        app:layout_constraintTop_toBottomOf="@+id/media_horizontal_center_guideline"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="@id/media_vertical_start_guideline"
        app:layout_constraintEnd_toStartOf="@id/media_cover5"
        app:layout_constraintEnd_toStartOf="@id/media_cover5_container"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintHorizontal_bias="1"
        app:layout_constraintVertical_chainStyle="packed"
@@ -109,7 +109,7 @@
        android:visibility="gone" />

    <Constraint
        android:id="@+id/media_cover5"
        android:id="@+id/media_cover5_container"
        android:layout_width="0dp"
        android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
        app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded"
@@ -118,8 +118,8 @@
        android:layout_marginEnd="@dimen/qs_aa_media_rec_album_margin"
        app:layout_constraintTop_toBottomOf="@+id/media_horizontal_center_guideline"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="@+id/media_cover4"
        app:layout_constraintEnd_toStartOf="@+id/media_cover6"
        app:layout_constraintStart_toEndOf="@+id/media_cover4_container"
        app:layout_constraintEnd_toStartOf="@+id/media_cover6_container"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintHorizontal_bias="1"
        app:layout_constraintVertical_chainStyle="packed"
@@ -127,7 +127,7 @@
        android:visibility="gone" />

    <Constraint
        android:id="@+id/media_cover6"
        android:id="@+id/media_cover6_container"
        android:layout_width="0dp"
        android:layout_height="@dimen/qs_aa_media_rec_album_size_expanded"
        app:layout_constraintWidth_max="@dimen/qs_aa_media_rec_album_size_expanded"
@@ -135,7 +135,7 @@
        android:layout_marginBottom="@dimen/qs_media_padding"
        app:layout_constraintTop_toBottomOf="@id/media_horizontal_center_guideline"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toEndOf="@id/media_cover5"
        app:layout_constraintStart_toEndOf="@id/media_cover5_container"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_chainStyle="packed"
        app:layout_constraintHorizontal_bias="1"
+23 −13
Original line number Diff line number Diff line
@@ -171,7 +171,7 @@ class MediaCarouselController @Inject constructor(
        visualStabilityCallback = VisualStabilityManager.Callback {
            if (needsReordering) {
                needsReordering = false
                reorderAllPlayers()
                reorderAllPlayers(previousVisiblePlayerKey = null)
            }

            keysNeedRemoval.forEach { removePlayer(it) }
@@ -285,7 +285,7 @@ class MediaCarouselController @Inject constructor(
        return mediaCarousel
    }

    private fun reorderAllPlayers() {
    private fun reorderAllPlayers(previousVisiblePlayerKey: MediaPlayerData.MediaSortKey?) {
        mediaContent.removeAllViews()
        for (mediaPlayer in MediaPlayerData.players()) {
            mediaPlayer.playerViewHolder?.let {
@@ -299,9 +299,16 @@ class MediaCarouselController @Inject constructor(
        // Automatically scroll to the active player if needed
        if (shouldScrollToActivePlayer) {
            shouldScrollToActivePlayer = false
            val activeMediaIndex = MediaPlayerData.activeMediaIndex()
            val activeMediaIndex = MediaPlayerData.firstActiveMediaIndex()
            if (activeMediaIndex != -1) {
                mediaCarouselScrollHandler.scrollToActivePlayer(activeMediaIndex)
                previousVisiblePlayerKey?.let {
                    val previousVisibleIndex = MediaPlayerData.playerKeys()
                        .indexOfFirst { key -> 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<MediaSortKey>
            { if (shouldPrioritizeSs) it.isSsMediaRec else !it.isSsMediaRec }
            .thenByDescending { it.data.isPlaying }
        compareByDescending<MediaSortKey> { 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()
+11 −2
Original line number Diff line number Diff line
@@ -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({
Loading