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

Commit da8283f8 authored by cecilia's avatar cecilia
Browse files

Slide transition from the media reco card to the active media player after a media reco is tapped.

Demo: https://drive.google.com/file/d/1o97nWDXh4EIbyxv-Sl1Y4VKOwW6vk7AR/view?usp=sharing

Bug: 186786793
Test: Studio builds
Change-Id: If83441dc4f1c27058cb8c3c8c626bc4535bdf926
parent d7f30b0e
Loading
Loading
Loading
Loading
+24 −4
Original line number Diff line number Diff line
@@ -115,6 +115,7 @@ class MediaCarouselController @Inject constructor(
    private var needsReordering: Boolean = false
    private var keysNeedRemoval = mutableSetOf<String>()
    private var bgColor = getBackgroundColor()
    private var shouldScrollToActivePlayer: Boolean = false
    private var isRtl: Boolean = false
        set(value) {
            if (value != field) {
@@ -271,6 +272,15 @@ class MediaCarouselController @Inject constructor(
            }
        }
        mediaCarouselScrollHandler.onPlayersChanged()

        // Automatically scroll to the active player if needed
        if (shouldScrollToActivePlayer) {
            shouldScrollToActivePlayer = false
            val activeMediaIndex = MediaPlayerData.getActiveMediaIndex()
            if (activeMediaIndex != -1) {
                mediaCarouselScrollHandler.scrollToActivePlayer(activeMediaIndex)
            }
        }
    }

    private fun addOrUpdatePlayer(key: String, oldKey: String?, data: MediaData) {
@@ -322,8 +332,8 @@ class MediaCarouselController @Inject constructor(
        val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.WRAP_CONTENT)
        newRecs.recommendationViewHolder?.recommendations?.setLayoutParams(lp)
        newRecs.bindRecommendation(data, bgColor)
        MediaPlayerData.addMediaPlayer(key, newRecs)
        newRecs.bindRecommendation(data, bgColor, { v -> shouldScrollToActivePlayer = true })
        MediaPlayerData.addMediaRecommendation(key, newRecs)
        updatePlayerToState(newRecs, noAnimation = true)
        reorderAllPlayers()
        updatePageIndicator()
@@ -593,7 +603,7 @@ class MediaCarouselController @Inject constructor(
@VisibleForTesting
internal object MediaPlayerData {
    private val EMPTY = MediaData(-1, false, 0, null, null, null, null, null,
        emptyList(), emptyList(), "INVALID", null, null, null, true, null)
        emptyList(), emptyList(), "INVALID", null, null, null, false, null)

    private data class MediaSortKey(
        // Is Smartspace media recommendation. When the Smartspace media is present, it should
@@ -620,7 +630,7 @@ internal object MediaPlayerData {
        mediaPlayers.put(sortKey, player)
    }

    fun addMediaPlayer(key: String, player: MediaControlPanel) {
    fun addMediaRecommendation(key: String, player: MediaControlPanel) {
        removeMediaPlayer(key)
        val sortKey = MediaSortKey(isSsMediaRec = true, EMPTY, System.currentTimeMillis())
        mediaData.put(key, sortKey)
@@ -643,6 +653,16 @@ internal object MediaPlayerData {

    fun players() = mediaPlayers.values

    /** Returns the index of the first non-timeout media. */
    fun getActiveMediaIndex(): Int {
        mediaPlayers.entries.forEachIndexed { index, e ->
            if (e.key.data.active) {
                return index
            }
        }
        return -1
    }

    @VisibleForTesting
    fun clear() {
        mediaData.clear()
+23 −10
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import com.android.systemui.util.concurrency.DelayableExecutor

private const val FLING_SLOP = 1000000
private const val DISMISS_DELAY = 100L
private const val SCROLL_DELAY = 100L
private const val RUBBERBAND_FACTOR = 0.2f
private const val SETTINGS_BUTTON_TRANSLATION_FRACTION = 0.3f

@@ -100,10 +101,11 @@ class MediaCarouselScrollHandler(
    private lateinit var settingsButton: View

    /**
     * What's the currently active player index?
     * What's the currently visible player index?
     */
    var activeMediaIndex: Int = 0
    var visibleMediaIndex: Int = 0
        private set

    /**
     * How much are we scrolled into the current media?
     */
@@ -129,7 +131,7 @@ class MediaCarouselScrollHandler(
            field = value
            // The player width has changed, let's update the scroll position to make sure
            // it's still at the same place
            var newRelativeScroll = activeMediaIndex * playerWidthPlusPadding
            var newRelativeScroll = visibleMediaIndex * playerWidthPlusPadding
            if (scrollIntoCurrentMedia > playerWidthPlusPadding) {
                newRelativeScroll += playerWidthPlusPadding -
                        (scrollIntoCurrentMedia - playerWidthPlusPadding)
@@ -457,12 +459,12 @@ class MediaCarouselScrollHandler(
        val wasScrolledIn = scrollIntoCurrentMedia != 0
        scrollIntoCurrentMedia = scrollInAmount
        val nowScrolledIn = scrollIntoCurrentMedia != 0
        if (newIndex != activeMediaIndex || wasScrolledIn != nowScrolledIn) {
            activeMediaIndex = newIndex
        if (newIndex != visibleMediaIndex || wasScrolledIn != nowScrolledIn) {
            visibleMediaIndex = newIndex
            closeGuts()
            updatePlayerVisibilities()
        }
        val relativeLocation = activeMediaIndex.toFloat() + if (playerWidthPlusPadding > 0)
        val relativeLocation = visibleMediaIndex.toFloat() + if (playerWidthPlusPadding > 0)
            scrollInAmount.toFloat() / playerWidthPlusPadding else 0f
        // Fix the location, because PageIndicator does not handle RTL internally
        val location = if (isRtl) {
@@ -500,7 +502,7 @@ class MediaCarouselScrollHandler(
        val scrolledIn = scrollIntoCurrentMedia != 0
        for (i in 0 until mediaContent.childCount) {
            val view = mediaContent.getChildAt(i)
            val visible = (i == activeMediaIndex) || ((i == (activeMediaIndex + 1)) && scrolledIn)
            val visible = (i == visibleMediaIndex) || ((i == (visibleMediaIndex + 1)) && scrolledIn)
            view.visibility = if (visible) View.VISIBLE else View.INVISIBLE
        }
    }
@@ -511,12 +513,12 @@ class MediaCarouselScrollHandler(
     */
    fun onPrePlayerRemoved(removed: MediaControlPanel) {
        val removedIndex = mediaContent.indexOfChild(removed.playerViewHolder?.player)
        // If the removed index is less than the activeMediaIndex, then we need to decrement it.
        // If the removed index is less than the visibleMediaIndex, then we need to decrement it.
        // RTL has no effect on this, because indices are always relative (start-to-end).
        // Update the index 'manually' since we won't always get a call to onMediaScrollingChanged
        val beforeActive = removedIndex <= activeMediaIndex
        val beforeActive = removedIndex <= visibleMediaIndex
        if (beforeActive) {
            activeMediaIndex = Math.max(0, activeMediaIndex - 1)
            visibleMediaIndex = Math.max(0, visibleMediaIndex - 1)
        }
        // If the removed media item is "left of" the active one (in an absolute sense), we need to
        // scroll the view to keep that player in view.  This is because scroll position is always
@@ -545,6 +547,17 @@ class MediaCarouselScrollHandler(
        scrollView.relativeScrollX = 0
    }

    fun scrollToActivePlayer(activePlayerIndex: Int) {
        var destIndex = activePlayerIndex
        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({
            visibleMediaIndex = activePlayerIndex
            scrollView.smoothScrollTo(view.left, scrollView.scrollY)
        }, SCROLL_DELAY)
    }

    companion object {
        private val CONTENT_TRANSLATION = object : FloatPropertyCompat<MediaCarouselScrollHandler>(
                "contentTranslation") {
+3 −2
Original line number Diff line number Diff line
@@ -462,7 +462,8 @@ public class MediaControlPanel {
    /** Bind this recommendation view based on the data given. */
    public void bindRecommendation(
            @NonNull SmartspaceTarget target,
            @NonNull int backgroundColor) {
            @NonNull int backgroundColor,
            @Nullable View.OnClickListener callback) {
        if (mRecommendationViewHolder == null) {
            return;
        }
@@ -526,7 +527,7 @@ public class MediaControlPanel {
            setSmartspaceRecItemOnClickListener(
                    mediaCoverImageView,
                    recommendation,
                    null);
                    callback);

            if (uiComponentIndex < MEDIA_RECOMMENDATION_ITEMS_PER_ROW) {
                setVisibleAndAlpha(collapsedSet,