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

Commit 3f333191 authored by Robert Snoeberger's avatar Robert Snoeberger Committed by Automerger Merge Worker
Browse files

Merge "Paged carousel for media players" into rvc-dev am: 83dcd5f7

Change-Id: I20472a8eb118b918e24a40a094c721ac58fe4d5d
parents 4b341ec9 83dcd5f7
Loading
Loading
Loading
Loading
+26 −9
Original line number Diff line number Diff line
@@ -16,10 +16,17 @@
  -->

<!-- Carousel for media controls -->
<com.android.systemui.media.UnboundHorizontalScrollView
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:clipChildren="false"
    android:clipToPadding="false"
    >
    <com.android.systemui.media.UnboundHorizontalScrollView
        android:id="@+id/media_carousel_scroller"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scrollbars="none"
        android:clipChildren="false"
        android:clipToPadding="false"
@@ -35,3 +42,13 @@
            <!-- QSMediaPlayers will be added here dynamically -->
        </LinearLayout>
    </com.android.systemui.media.UnboundHorizontalScrollView>
    <com.android.systemui.qs.PageIndicator
        android:id="@+id/media_page_indicator"
        android:layout_width="wrap_content"
        android:layout_height="48dp"
        android:layout_marginBottom="4dp"
        android:layout_gravity="center_horizontal|bottom"
        android:gravity="center"
        android:tint="@color/media_primary_text"
    />
</FrameLayout>
+2 −2
Original line number Diff line number Diff line
@@ -58,7 +58,7 @@ class MediaHierarchyManager @Inject constructor(
    private var rootOverlay: ViewGroupOverlay? = null
    private lateinit var currentState: MediaState
    private val mediaCarousel
        get() = mediaViewManager.mediaCarousel
        get() = mediaViewManager.mediaFrame
    private var animationStartState: MediaState? = null
    private var statusbarState: Int = statusBarStateController.state
    private var animator = ValueAnimator.ofFloat(0.0f, 1.0f).apply {
+88 −4
Original line number Diff line number Diff line
package com.android.systemui.media

import android.content.Context
import android.graphics.Color
import android.view.LayoutInflater
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.widget.HorizontalScrollView
import android.widget.LinearLayout
import androidx.core.view.GestureDetectorCompat
import com.android.systemui.R
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.qs.PageIndicator
import com.android.systemui.statusbar.notification.VisualStabilityManager
import com.android.systemui.util.animation.MeasurementOutput
import com.android.systemui.util.animation.UniqueObjectHostView
@@ -18,6 +23,8 @@ import java.util.concurrent.Executor
import javax.inject.Inject
import javax.inject.Singleton

private const val FLING_SLOP = 1000000

/**
 * Class that is responsible for keeping the view carousel up to date.
 * This also handles changes in state and applies them to the media carousel like the expansion.
@@ -35,9 +42,12 @@ class MediaViewManager @Inject constructor(
    private var playerWidthPlusPadding: Int = 0
    private var desiredState: MediaHost.MediaHostState? = null
    private var currentState: MediaState? = null
    val mediaCarousel: HorizontalScrollView
    private val mediaCarousel: HorizontalScrollView
    val mediaFrame: ViewGroup
    private val mediaContent: ViewGroup
    private val mediaPlayers: MutableMap<String, MediaControlPanel> = mutableMapOf()
    private val pageIndicator: PageIndicator
    private val gestureDetector: GestureDetectorCompat
    private val visualStabilityCallback: VisualStabilityManager.Callback
    private var activeMediaIndex: Int = 0
    private var needsReordering: Boolean = false
@@ -66,10 +76,30 @@ class MediaViewManager @Inject constructor(
                    scrollX % playerWidthPlusPadding)
        }
    }
    private val gestureListener = object : GestureDetector.SimpleOnGestureListener() {
        override fun onFling(
            eStart: MotionEvent?,
            eCurrent: MotionEvent?,
            vX: Float,
            vY: Float
        ): Boolean {
            return this@MediaViewManager.onFling(eStart, eCurrent, vX, vY)
        }
    }
    private val touchListener = object : View.OnTouchListener {
        override fun onTouch(view: View, motionEvent: MotionEvent?): Boolean {
            return this@MediaViewManager.onTouch(view, motionEvent)
        }
    }

    init {
        mediaCarousel = inflateMediaCarousel()
        gestureDetector = GestureDetectorCompat(context, gestureListener)
        mediaFrame = inflateMediaCarousel()
        mediaCarousel = mediaFrame.requireViewById(R.id.media_carousel_scroller)
        pageIndicator = mediaFrame.requireViewById(R.id.media_page_indicator)
        mediaCarousel.setOnScrollChangeListener(scrollChangedListener)
        mediaCarousel.setOnTouchListener(touchListener)
        mediaCarousel.setOverScrollMode(View.OVER_SCROLL_NEVER)
        mediaContent = mediaCarousel.requireViewById(R.id.media_carousel)
        visualStabilityCallback = VisualStabilityManager.Callback {
            if (needsReordering) {
@@ -103,14 +133,15 @@ class MediaViewManager @Inject constructor(
                                playerWidthPlusPadding, 0)
                    }
                    updatePlayerVisibilities()
                    updatePageIndicator()
                }
            }
        })
    }

    private fun inflateMediaCarousel(): HorizontalScrollView {
    private fun inflateMediaCarousel(): ViewGroup {
        return LayoutInflater.from(context).inflate(R.layout.media_carousel,
                UniqueObjectHostView(context), false) as HorizontalScrollView
                UniqueObjectHostView(context), false) as ViewGroup
    }

    private fun reorderAllPlayers() {
@@ -133,6 +164,47 @@ class MediaViewManager @Inject constructor(
            activeMediaIndex = newIndex
            updatePlayerVisibilities()
        }
        val location = activeMediaIndex.toFloat() + if (playerWidthPlusPadding > 0)
                scrollInAmount.toFloat() / playerWidthPlusPadding else 0f
        pageIndicator.setLocation(location)
    }

    private fun onTouch(view: View, motionEvent: MotionEvent?): Boolean {
        if (gestureDetector.onTouchEvent(motionEvent)) {
            return true
        }
        if (motionEvent?.getAction() == MotionEvent.ACTION_UP) {
            val pos = mediaCarousel.scrollX % playerWidthPlusPadding
            if (pos > playerWidthPlusPadding / 2) {
                mediaCarousel.smoothScrollBy(playerWidthPlusPadding - pos, 0)
            } else {
                mediaCarousel.smoothScrollBy(-1 * pos, 0)
            }
            return true
        }
        return view.onTouchEvent(motionEvent)
    }

    private fun onFling(
        eStart: MotionEvent?,
        eCurrent: MotionEvent?,
        vX: Float,
        vY: Float
    ): Boolean {
        if (vX * vX < 0.5 * vY * vY) {
            return false
        }
        if (vX * vX < FLING_SLOP) {
            return false
        }
        val pos = mediaCarousel.scrollX
        val currentIndex = if (playerWidthPlusPadding > 0) pos / playerWidthPlusPadding else 0
        var destIndex = if (vX <= 0) currentIndex + 1 else currentIndex
        destIndex = Math.max(0, destIndex)
        destIndex = Math.min(mediaContent.getChildCount() - 1, destIndex)
        val view = mediaContent.getChildAt(destIndex)
        mediaCarousel.smoothScrollTo(view.left, mediaCarousel.scrollY)
        return true
    }

    private fun updatePlayerVisibilities() {
@@ -176,6 +248,7 @@ class MediaViewManager @Inject constructor(
        // motion model
        existingPlayer.view?.player?.progress = currentState?.expansion ?: 0.0f
        updateMediaPaddings()
        updatePageIndicator()
    }

    private fun updatePlayerToCurrentState(existingPlayer: MediaControlPanel) {
@@ -199,6 +272,14 @@ class MediaViewManager @Inject constructor(
        }
    }

    private fun updatePageIndicator() {
        val numPages = mediaContent.getChildCount()
        pageIndicator.setNumPages(numPages, Color.WHITE)
        if (numPages == 1) {
            pageIndicator.setLocation(0f)
        }
    }

    /**
     * Set the current state of a view. This is updated often during animations and we shouldn't
     * do anything expensive.
@@ -206,6 +287,9 @@ class MediaViewManager @Inject constructor(
    fun setCurrentState(state: MediaState) {
        currentState = state
        currentlyExpanded = state.expansion > 0
        // Hack: Since the indicator doesn't move with the player expansion, just make it disappear
        // and then reappear at the end.
        pageIndicator.alpha = if (state.expansion == 1f || state.expansion == 0f) 1f else 0f
        for (mediaPlayer in mediaPlayers.values) {
            val view = mediaPlayer.view?.player
            view?.progress = state.expansion
+9 −4
Original line number Diff line number Diff line
@@ -45,6 +45,15 @@ public class PageIndicator extends ViewGroup {
    }

    public void setNumPages(int numPages) {
        TypedArray array = getContext().obtainStyledAttributes(
                new int[]{android.R.attr.colorControlActivated});
        int color = array.getColor(0, 0);
        array.recycle();
        setNumPages(numPages, color);
    }

    /** Oveload of setNumPages that allows the indicator color to be specified.*/
    public void setNumPages(int numPages, int color) {
        setVisibility(numPages > 1 ? View.VISIBLE : View.GONE);
        if (mAnimating) {
            Log.w(TAG, "setNumPages during animation");
@@ -52,10 +61,6 @@ public class PageIndicator extends ViewGroup {
        while (numPages < getChildCount()) {
            removeViewAt(getChildCount() - 1);
        }
        TypedArray array = getContext().obtainStyledAttributes(
                new int[]{android.R.attr.colorControlActivated});
        int color = array.getColor(0, 0);
        array.recycle();
        while (numPages > getChildCount()) {
            ImageView v = new ImageView(mContext);
            v.setImageResource(R.drawable.minor_a_b);