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

Commit 4f8f824b authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Making transitions between gone hosts work better" into rvc-dev am: acd4508f

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/11967243

Change-Id: Ifdfbae373bb1ced69b4586623ac68d6779170105
parents f0006935 acd4508f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -48,5 +48,6 @@
        android:layout_height="48dp"
        android:layout_marginBottom="4dp"
        android:tint="@color/media_primary_text"
        android:forceHasOverlappingRendering="false"
    />
</FrameLayout>
+1 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
    android:clipChildren="false"
    android:clipToPadding="false"
    android:gravity="center_horizontal|fill_vertical"
    android:forceHasOverlappingRendering="false"
    android:background="@drawable/qs_media_background">

    <!-- As per Material Design on Biderectionality, this is forced to LTR in code -->
+28 −2
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ import android.content.Intent
import android.content.res.Configuration
import android.graphics.Color
import android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS
import android.util.MathUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@@ -328,9 +329,32 @@ class MediaCarouselController @Inject constructor(
                updatePlayerToState(mediaPlayer, immediately)
            }
            maybeResetSettingsCog()
            updatePageIndicatorAlpha()
        }
    }

    private fun updatePageIndicatorAlpha() {
        val hostStates = mediaHostStatesManager.mediaHostStates
        val endIsVisible = hostStates[currentEndLocation]?.visible ?: false
        val startIsVisible = hostStates[currentStartLocation]?.visible ?: false
        val startAlpha = if (startIsVisible) 1.0f else 0.0f
        val endAlpha = if (endIsVisible) 1.0f else 0.0f
        var alpha = 1.0f
        if (!endIsVisible || !startIsVisible) {
            var progress = currentTransitionProgress
            if (!endIsVisible) {
                progress = 1.0f - progress
            }
            // Let's fade in quickly at the end where the view is visible
            progress = MathUtils.constrain(
                    MathUtils.map(0.95f, 1.0f, 0.0f, 1.0f, progress),
                    0.0f,
                    1.0f)
            alpha = MathUtils.lerp(startAlpha, endAlpha, progress)
        }
        pageIndicator.alpha = alpha
    }

    private fun updatePageIndicatorLocation() {
        // Update the location of the page indicator, carousel clipping
        val translationX = if (isRtl) {
@@ -352,8 +376,10 @@ class MediaCarouselController @Inject constructor(
        var height = 0
        for (mediaPlayer in mediaPlayers.values) {
            val controller = mediaPlayer.mediaViewController
            width = Math.max(width, controller.currentWidth)
            height = Math.max(height, controller.currentHeight)
            // When transitioning the view to gone, the view gets smaller, but the translation
            // Doesn't, let's add the translation
            width = Math.max(width, controller.currentWidth + controller.translationX.toInt())
            height = Math.max(height, controller.currentHeight + controller.translationY.toInt())
        }
        if (width != currentCarouselWidth || height != currentCarouselHeight) {
            currentCarouselWidth = width
+23 −11
Original line number Diff line number Diff line
@@ -329,7 +329,7 @@ class MediaHierarchyManager @Inject constructor(
            applyTargetStateIfNotAnimating()
        } else if (animate) {
            animator.cancel()
            if (currentAttachmentLocation == IN_OVERLAY ||
            if (currentAttachmentLocation != previousLocation ||
                    !previousHost.hostView.isAttachedToWindow) {
                // Let's animate to the new position, starting from the current position
                // We also go in here in case the view was detached, since the bounds wouldn't
@@ -341,11 +341,13 @@ class MediaHierarchyManager @Inject constructor(
                animationStartBounds.set(previousHost.currentBounds)
            }
            adjustAnimatorForTransition(desiredLocation, previousLocation)
            if (!animationPending) {
                rootView?.let {
                    // Let's delay the animation start until we finished laying out
                    animationPending = true
                    it.postOnAnimation(startAnimation)
                }
            }
        } else {
            cancelAnimationAndApplyDesiredState()
        }
@@ -403,15 +405,23 @@ class MediaHierarchyManager @Inject constructor(
    }

    /**
     * Updates the state that the view wants to be in at the end of the animation.
     * Updates the bounds that the view wants to be in at the end of the animation.
     */
    private fun updateTargetState() {
        if (isCurrentlyInGuidedTransformation()) {
            val progress = getTransformationProgress()
            val currentHost = getHost(desiredLocation)!!
            val previousHost = getHost(previousLocation)!!
            val newBounds = currentHost.currentBounds
            val previousBounds = previousHost.currentBounds
            var endHost = getHost(desiredLocation)!!
            var starthost = getHost(previousLocation)!!
            // If either of the hosts are invisible, let's keep them at the other host location to
            // have a nicer disappear animation. Otherwise the currentBounds of the state might
            // be undefined
            if (!endHost.visible) {
                endHost = starthost
            } else if (!starthost.visible) {
                starthost = endHost
            }
            val newBounds = endHost.currentBounds
            val previousBounds = starthost.currentBounds
            targetBounds = interpolateBounds(previousBounds, newBounds, progress)
        } else {
            val bounds = getHost(desiredLocation)?.currentBounds ?: return
@@ -462,9 +472,11 @@ class MediaHierarchyManager @Inject constructor(
        val previousHost = getHost(previousLocation)
        if (currentHost?.location == LOCATION_QS) {
            if (previousHost?.location == LOCATION_QQS) {
                if (previousHost.visible || statusbarState != StatusBarState.KEYGUARD) {
                    return qsExpansion
                }
            }
        }
        return -1.0f
    }

+30 −29
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ import android.graphics.Rect
import android.util.ArraySet
import android.view.View
import android.view.View.OnAttachStateChangeListener
import com.android.systemui.util.animation.DisappearParameters
import com.android.systemui.util.animation.MeasurementInput
import com.android.systemui.util.animation.MeasurementOutput
import com.android.systemui.util.animation.UniqueObjectHostView
@@ -128,8 +129,6 @@ class MediaHost @Inject constructor(
    }

    class MediaHostStateHolder @Inject constructor() : MediaHostState {
        private var gonePivot: PointF = PointF()

        override var measurementInput: MeasurementInput? = null
            set(value) {
                if (value?.equals(field) != true) {
@@ -172,16 +171,19 @@ class MediaHost @Inject constructor(
                changedListener?.invoke()
            }

        override fun getPivotX(): Float = gonePivot.x
        override fun getPivotY(): Float = gonePivot.y
        override fun setGonePivot(x: Float, y: Float) {
            if (gonePivot.equals(x, y)) {
        override var disappearParameters: DisappearParameters = DisappearParameters()
            set(value) {
                val newHash = value.hashCode()
                if (lastDisappearHash.equals(newHash)) {
                    return
                }
            gonePivot.set(x, y)
                field = value
                lastDisappearHash = newHash
                changedListener?.invoke()
            }

        private var lastDisappearHash = disappearParameters.hashCode()

        /**
         * A listener for all changes. This won't be copied over when invoking [copy]
         */
@@ -196,7 +198,7 @@ class MediaHost @Inject constructor(
            mediaHostState.showsOnlyActiveMedia = showsOnlyActiveMedia
            mediaHostState.measurementInput = measurementInput?.copy()
            mediaHostState.visible = visible
            mediaHostState.gonePivot.set(gonePivot)
            mediaHostState.disappearParameters = disappearParameters.deepCopy()
            mediaHostState.falsingProtectionNeeded = falsingProtectionNeeded
            return mediaHostState
        }
@@ -220,7 +222,7 @@ class MediaHost @Inject constructor(
            if (falsingProtectionNeeded != other.falsingProtectionNeeded) {
                return false
            }
            if (!gonePivot.equals(other.getPivotX(), other.getPivotY())) {
            if (!disappearParameters.equals(other.disappearParameters)) {
                return false
            }
            return true
@@ -232,12 +234,23 @@ class MediaHost @Inject constructor(
            result = 31 * result + falsingProtectionNeeded.hashCode()
            result = 31 * result + showsOnlyActiveMedia.hashCode()
            result = 31 * result + if (visible) 1 else 2
            result = 31 * result + gonePivot.hashCode()
            result = 31 * result + disappearParameters.hashCode()
            return result
        }
    }
}

/**
 * A description of a media host state that describes the behavior whenever the media carousel
 * is hosted. The HostState notifies the media players of changes to their properties, who
 * in turn will create view states from it.
 * When adding a new property to this, make sure to update the listener and notify them
 * about the changes.
 * In case you need to have a different rendering based on the state, you can add a new
 * constraintState to the [MediaViewController]. Otherwise, similar host states will resolve
 * to the same viewstate, a behavior that is described in [CacheKey]. Make sure to only update
 * that key if the underlying view needs to have a different measurement.
 */
interface MediaHostState {

    /**
@@ -268,23 +281,11 @@ interface MediaHostState {
    var falsingProtectionNeeded: Boolean

    /**
     * Sets the pivot point when clipping the height or width.
     * Clipping happens when animating visibility when we're visible in QS but not on QQS,
     * for example.
     */
    fun setGonePivot(x: Float, y: Float)

    /**
     * x position of pivot, from 0 to 1
     * @see [setGonePivot]
     */
    fun getPivotX(): Float

    /**
     * y position of pivot, from 0 to 1
     * @see [setGonePivot]
     * The parameters how the view disappears from this location when going to a host that's not
     * visible. If modified, make sure to set this value again on the host to ensure the values
     * are propagated
     */
    fun getPivotY(): Float
    var disappearParameters: DisappearParameters

    /**
     * Get a copy of this view state, deepcopying all appropriate members
Loading