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

Commit ac72d00d authored by Marvin Bernal's avatar Marvin Bernal Committed by Automerger Merge Worker
Browse files

Merge "Back arrow animation polish for CANCEL and fling from INACTIVE states"...

Merge "Back arrow animation polish for CANCEL and fling from INACTIVE states" into udc-dev am: 53d240a5

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



Change-Id: I4def77aafbaa3a123bfaa764eb525221cf685fdf
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 2daa795e 53d240a5
Loading
Loading
Loading
Loading
+0 −4
Original line number Diff line number Diff line
@@ -43,8 +43,6 @@
    <dimen name="navigation_edge_panel_height">268dp</dimen>
    <!-- The threshold to drag to trigger the edge action -->
    <dimen name="navigation_edge_action_drag_threshold">16dp</dimen>
    <!-- The drag distance to consider evaluating gesture -->
    <dimen name="navigation_edge_action_min_distance_to_start_animation">24dp</dimen>
    <!-- The threshold to progress back animation for edge swipe -->
    <dimen name="navigation_edge_action_progress_threshold">412dp</dimen>
    <!-- The minimum display position of the arrow on the screen -->
@@ -58,8 +56,6 @@

    <!-- The thickness of the arrow -->
    <dimen name="navigation_edge_arrow_thickness">4dp</dimen>
    <!-- The minimum delta needed to change direction / stop triggering back -->
    <dimen name="navigation_edge_minimum_x_delta_for_switch">32dp</dimen>

    <!-- entry state -->
    <item name="navigation_edge_entry_scale" format="float" type="dimen">0.98</item>
+56 −26
Original line number Diff line number Diff line
@@ -53,11 +53,14 @@ private const val ENABLE_FAILSAFE = true
private const val PX_PER_SEC = 1000
private const val PX_PER_MS = 1

internal const val MIN_DURATION_ACTIVE_ANIMATION = 300L
internal const val MIN_DURATION_ACTIVE_BEFORE_INACTIVE_ANIMATION = 300L
private const val MIN_DURATION_ACTIVE_AFTER_INACTIVE_ANIMATION = 130L
private const val MIN_DURATION_CANCELLED_ANIMATION = 200L
private const val MIN_DURATION_COMMITTED_ANIMATION = 120L
private const val MIN_DURATION_INACTIVE_BEFORE_FLUNG_ANIMATION = 50L
private const val MIN_DURATION_CONSIDERED_AS_FLING = 100L

private const val MIN_DURATION_ENTRY_TO_ACTIVE_CONSIDERED_AS_FLING = 100L
private const val MIN_DURATION_INACTIVE_TO_ACTIVE_CONSIDERED_AS_FLING = 400L

private const val FAILSAFE_DELAY_MS = 350L
private const val POP_ON_FLING_DELAY = 140L
@@ -145,12 +148,12 @@ class BackPanelController internal constructor(
    private var startY = 0f
    private var startIsLeft: Boolean? = null

    private var gestureSinceActionDown = 0L
    private var gestureEntryTime = 0L
    private var gestureInactiveTime = 0L
    private var gestureActiveTime = 0L

    private val elapsedTimeSinceActionDown
        get() = SystemClock.uptimeMillis() - gestureSinceActionDown
    private val elapsedTimeSinceInactive
        get() = SystemClock.uptimeMillis() - gestureInactiveTime
    private val elapsedTimeSinceEntry
        get() = SystemClock.uptimeMillis() - gestureEntryTime

@@ -158,6 +161,9 @@ class BackPanelController internal constructor(
    // so that we can unambiguously start showing the ENTRY animation
    private var hasPassedDragSlop = false

    // Distance in pixels a drag can be considered for a fling event
    private var minFlingDistance = 0

    private val failsafeRunnable = Runnable { onFailsafe() }

    internal enum class GestureState {
@@ -235,6 +241,7 @@ class BackPanelController internal constructor(
    private fun updateConfiguration() {
        params.update(resources)
        mView.updateArrowPaint(params.arrowThickness)
        minFlingDistance = ViewConfiguration.get(context).scaledTouchSlop * 3
    }

    private val configurationListener = object : ConfigurationController.ConfigurationListener {
@@ -268,7 +275,6 @@ class BackPanelController internal constructor(
        velocityTracker!!.addMovement(event)
        when (event.actionMasked) {
            MotionEvent.ACTION_DOWN -> {
                gestureSinceActionDown = SystemClock.uptimeMillis()
                cancelAllPendingAnimations()
                startX = event.x
                startY = event.y
@@ -307,8 +313,22 @@ class BackPanelController internal constructor(
                        }
                    }
                    GestureState.ACTIVE -> {
                        if (elapsedTimeSinceEntry < MIN_DURATION_CONSIDERED_AS_FLING) {
                        if (previousState == GestureState.ENTRY &&
                                elapsedTimeSinceEntry
                                    < MIN_DURATION_ENTRY_TO_ACTIVE_CONSIDERED_AS_FLING
                        ) {
                            updateArrowState(GestureState.FLUNG)
                        } else if (previousState == GestureState.INACTIVE &&
                                elapsedTimeSinceInactive
                                    < MIN_DURATION_INACTIVE_TO_ACTIVE_CONSIDERED_AS_FLING
                        ) {
                            // A delay is added to allow the background to transition back to ACTIVE
                            // since it was briefly in INACTIVE. Without this delay, setting it
                            // immediately to COMMITTED would result in the committed animation
                            // appearing like it was playing in INACTIVE.
                            mainHandler.postDelayed(MIN_DURATION_ACTIVE_AFTER_INACTIVE_ANIMATION) {
                                updateArrowState(GestureState.COMMITTED)
                            }
                        } else {
                            updateArrowState(GestureState.COMMITTED)
                        }
@@ -376,7 +396,7 @@ class BackPanelController internal constructor(
                val isPastDynamicDeactivationThreshold =
                        totalTouchDelta <= params.deactivationSwipeTriggerThreshold
                val isMinDurationElapsed =
                        elapsedTimeSinceActionDown > MIN_DURATION_ACTIVE_ANIMATION
                        elapsedTimeSinceEntry > MIN_DURATION_ACTIVE_BEFORE_INACTIVE_ANIMATION

                if (isMinDurationElapsed && (!isWithinYActivationThreshold ||
                                isPastDynamicDeactivationThreshold)
@@ -470,8 +490,15 @@ class BackPanelController internal constructor(
            GestureState.GONE -> 0f
        }

        val indicator = when (currentState) {
            GestureState.ENTRY -> params.entryIndicator
            GestureState.INACTIVE -> params.preThresholdIndicator
            GestureState.ACTIVE -> params.activeIndicator
            else -> params.preThresholdIndicator
        }

        strokeAlphaProgress?.let { progress ->
            params.arrowStrokeAlphaSpring.get(progress).takeIf { it.isNewState }?.let {
            indicator.arrowDimens.alphaSpring?.get(progress)?.takeIf { it.isNewState }?.let {
                mView.popArrowAlpha(0f, it.value)
            }
        }
@@ -537,7 +564,8 @@ class BackPanelController internal constructor(
                backgroundHeightStretchAmount = params.heightInterpolator
                        .getInterpolation(progress),
                backgroundAlphaStretchAmount = 1f,
                arrowAlphaStretchAmount = params.arrowStrokeAlphaInterpolator.get(progress).value,
                arrowAlphaStretchAmount = params.entryIndicator.arrowDimens
                        .alphaInterpolator?.get(progress)?.value ?: 0f,
                edgeCornerStretchAmount = params.edgeCornerInterpolator.getInterpolation(progress),
                farCornerStretchAmount = params.farCornerInterpolator.getInterpolation(progress),
                fullyStretchedDimens = params.preThresholdIndicator
@@ -567,7 +595,8 @@ class BackPanelController internal constructor(
                backgroundHeightStretchAmount = params.heightInterpolator
                        .getInterpolation(progress),
                backgroundAlphaStretchAmount = 1f,
                arrowAlphaStretchAmount = params.arrowStrokeAlphaInterpolator.get(progress).value,
                arrowAlphaStretchAmount = params.preThresholdIndicator.arrowDimens
                        .alphaInterpolator?.get(progress)?.value ?: 0f,
                edgeCornerStretchAmount = params.edgeCornerInterpolator.getInterpolation(progress),
                farCornerStretchAmount = params.farCornerInterpolator.getInterpolation(progress),
                fullyStretchedDimens = params.preThresholdIndicator
@@ -599,19 +628,15 @@ class BackPanelController internal constructor(
        windowManager.addView(mView, layoutParams)
    }

    private fun isDragAwayFromEdge(velocityPxPerSecThreshold: Int = 0) = velocityTracker!!.run {
        computeCurrentVelocity(PX_PER_SEC)
        val velocity = xVelocity.takeIf { mView.isLeftPanel } ?: (xVelocity * -1)
        velocity > velocityPxPerSecThreshold
    }

    private fun isFlungAwayFromEdge(endX: Float, startX: Float = touchDeltaStartX): Boolean {
        val minDistanceConsideredForFling = ViewConfiguration.get(context).scaledTouchSlop
        val flingDistance = if (mView.isLeftPanel) endX - startX else startX - endX
        val isPastFlingVelocity = isDragAwayFromEdge(
                velocityPxPerSecThreshold =
                ViewConfiguration.get(context).scaledMinimumFlingVelocity)
        return flingDistance > minDistanceConsideredForFling && isPastFlingVelocity
        val flingVelocity = velocityTracker?.run {
            computeCurrentVelocity(PX_PER_SEC)
            xVelocity.takeIf { mView.isLeftPanel } ?: (xVelocity * -1)
        } ?: 0f
        val isPastFlingVelocityThreshold =
                flingVelocity > ViewConfiguration.get(context).scaledMinimumFlingVelocity
        return flingDistance > minFlingDistance && isPastFlingVelocityThreshold
    }

    private fun playHorizontalAnimationThen(onEnd: DelayedOnAnimationEndListener) {
@@ -664,7 +689,6 @@ class BackPanelController internal constructor(
                mView.setSpring(
                        arrowLength = params.entryIndicator.arrowDimens.lengthSpring,
                        arrowHeight = params.entryIndicator.arrowDimens.heightSpring,
                        arrowAlpha = params.entryIndicator.arrowDimens.alphaSpring,
                        scale = params.entryIndicator.scaleSpring,
                        verticalTranslation = params.entryIndicator.verticalTranslationSpring,
                        horizontalTranslation = params.entryIndicator.horizontalTranslationSpring,
@@ -725,6 +749,7 @@ class BackPanelController internal constructor(
                        arrowLength = params.committedIndicator.arrowDimens.lengthSpring,
                        arrowHeight = params.committedIndicator.arrowDimens.heightSpring,
                        scale = params.committedIndicator.scaleSpring,
                        backgroundAlpha = params.committedIndicator.backgroundDimens.alphaSpring,
                        backgroundWidth = params.committedIndicator.backgroundDimens.widthSpring,
                        backgroundHeight = params.committedIndicator.backgroundDimens.heightSpring,
                        backgroundEdgeCornerRadius = params.committedIndicator.backgroundDimens
@@ -733,6 +758,10 @@ class BackPanelController internal constructor(
                                .farCornerRadiusSpring,
                )
            }
            GestureState.CANCELLED -> {
                mView.setSpring(
                        backgroundAlpha = params.cancelledIndicator.backgroundDimens.alphaSpring)
            }
            else -> {}
        }

@@ -864,6 +893,7 @@ class BackPanelController internal constructor(
            }

            GestureState.INACTIVE -> {
                gestureInactiveTime = SystemClock.uptimeMillis()

                // Typically entering INACTIVE means
                // totalTouchDelta <= deactivationSwipeTriggerThreshold
@@ -900,9 +930,9 @@ class BackPanelController internal constructor(
                val delay = max(0, MIN_DURATION_CANCELLED_ANIMATION - elapsedTimeSinceEntry)
                playWithBackgroundWidthAnimation(onEndSetGoneStateListener, delay)

                params.arrowStrokeAlphaSpring.get(0f).takeIf { it.isNewState }?.let {
                    mView.popArrowAlpha(0f, it.value)
                }
                val springForceOnCancelled = params.cancelledIndicator
                        .arrowDimens.alphaSpring?.get(0f)?.value
                mView.popArrowAlpha(0f, springForceOnCancelled)
                mainHandler.postDelayed(10L) { vibratorHelper.cancel() }
            }
        }
+43 −40
Original line number Diff line number Diff line
@@ -12,9 +12,10 @@ data class EdgePanelParams(private var resources: Resources) {
            val length: Float? = 0f,
            val height: Float? = 0f,
            val alpha: Float = 0f,
            var alphaSpring: SpringForce? = null,
            val heightSpring: SpringForce? = null,
            val lengthSpring: SpringForce? = null,
            var alphaSpring: Step<SpringForce>? = null,
            var alphaInterpolator: Step<Float>? = null
    )

    data class BackgroundDimens(
@@ -61,11 +62,6 @@ data class EdgePanelParams(private var resources: Resources) {
        private set
    var arrowThickness: Float = 0f
        private set
    lateinit var arrowStrokeAlphaSpring: Step<SpringForce>
        private set
    lateinit var arrowStrokeAlphaInterpolator: Step<Float>
        private set

    // The closest to y
    var minArrowYPosition: Int = 0
        private set
@@ -81,13 +77,6 @@ data class EdgePanelParams(private var resources: Resources) {
    var swipeProgressThreshold: Float = 0f
        private set

    // The minimum delta needed to change direction / stop triggering back
    var minDeltaForSwitch: Int = 0
        private set

    var minDragToStartAnimation: Float = 0f
        private set

    lateinit var entryWidthInterpolator: PathInterpolator
        private set
    lateinit var entryWidthTowardsEdgeInterpolator: PathInterpolator
@@ -133,23 +122,17 @@ data class EdgePanelParams(private var resources: Resources) {
        deactivationSwipeTriggerThreshold =
                getDimen(R.dimen.navigation_edge_action_deactivation_drag_threshold)
        swipeProgressThreshold = getDimen(R.dimen.navigation_edge_action_progress_threshold)
        minDeltaForSwitch = getPx(R.dimen.navigation_edge_minimum_x_delta_for_switch)
        minDragToStartAnimation =
                getDimen(R.dimen.navigation_edge_action_min_distance_to_start_animation)

        entryWidthInterpolator = PathInterpolator(.19f, 1.27f, .71f, .86f)
        entryWidthTowardsEdgeInterpolator = PathInterpolator(1f, -3f, 1f, 1.2f)
        activeWidthInterpolator = PathInterpolator(.32f, 0f, .16f, .94f)
        activeWidthInterpolator = PathInterpolator(.7f, .06f, .34f, .97f)
        arrowAngleInterpolator = entryWidthInterpolator
        translationInterpolator = PathInterpolator(0.2f, 1.0f, 1.0f, 1.0f)
        farCornerInterpolator = PathInterpolator(.03f, .19f, .14f, 1.09f)
        edgeCornerInterpolator = PathInterpolator(0f, 1.11f, .85f, .84f)
        heightInterpolator = PathInterpolator(1f, .05f, .9f, -0.29f)

        val showArrowOnProgressValue = .23f
        val showArrowOnProgressValueFactor = 1.05f

        val entryActiveHorizontalTranslationSpring = createSpring(800f, 0.8f)
        val entryActiveHorizontalTranslationSpring = createSpring(800f, 0.76f)
        val activeCommittedArrowLengthSpring = createSpring(1500f, 0.29f)
        val activeCommittedArrowHeightSpring = createSpring(1500f, 0.29f)
        val flungCommittedEdgeCornerSpring = createSpring(10000f, 1f)
@@ -157,6 +140,8 @@ data class EdgePanelParams(private var resources: Resources) {
        val flungCommittedWidthSpring = createSpring(10000f, 1f)
        val flungCommittedHeightSpring = createSpring(10000f, 1f)

        val entryIndicatorAlphaThreshold = .23f
        val entryIndicatorAlphaFactor = 1.05f
        entryIndicator = BackIndicatorDimens(
                horizontalTranslation = getDimen(R.dimen.navigation_edge_entry_margin),
                scale = getDimenFloat(R.dimen.navigation_edge_entry_scale),
@@ -168,9 +153,20 @@ data class EdgePanelParams(private var resources: Resources) {
                        length = getDimen(R.dimen.navigation_edge_entry_arrow_length),
                        height = getDimen(R.dimen.navigation_edge_entry_arrow_height),
                        alpha = 0f,
                        alphaSpring = createSpring(200f, 1f),
                        lengthSpring = createSpring(600f, 0.4f),
                        heightSpring = createSpring(600f, 0.4f),
                        alphaSpring = Step(
                                threshold = entryIndicatorAlphaThreshold,
                                factor = entryIndicatorAlphaFactor,
                                postThreshold = createSpring(200f, 1f),
                                preThreshold = createSpring(2000f, 0.6f)
                        ),
                        alphaInterpolator = Step(
                                threshold = entryIndicatorAlphaThreshold,
                                factor = entryIndicatorAlphaFactor,
                                postThreshold = 1f,
                                preThreshold = 0f
                        )
                ),
                backgroundDimens = BackgroundDimens(
                        alpha = 1f,
@@ -186,6 +182,20 @@ data class EdgePanelParams(private var resources: Resources) {
                )
        )

        val preThresholdAndActiveIndicatorAlphaThreshold = .355f
        val preThresholdAndActiveIndicatorAlphaFactor = 1.05f
        val preThresholdAndActiveAlphaSpring = Step(
                threshold = preThresholdAndActiveIndicatorAlphaThreshold,
                factor = preThresholdAndActiveIndicatorAlphaFactor,
                postThreshold = createSpring(180f, 0.9f),
                preThreshold = createSpring(2000f, 0.6f)
        )
        val preThresholdAndActiveAlphaSpringInterpolator = Step(
                threshold = preThresholdAndActiveIndicatorAlphaThreshold,
                factor = preThresholdAndActiveIndicatorAlphaFactor,
                postThreshold = 1f,
                preThreshold = 0f
        )
        activeIndicator = BackIndicatorDimens(
                horizontalTranslation = getDimen(R.dimen.navigation_edge_active_margin),
                scale = getDimenFloat(R.dimen.navigation_edge_active_scale),
@@ -197,6 +207,8 @@ data class EdgePanelParams(private var resources: Resources) {
                        alpha = 1f,
                        lengthSpring = activeCommittedArrowLengthSpring,
                        heightSpring = activeCommittedArrowHeightSpring,
                        alphaSpring = preThresholdAndActiveAlphaSpring,
                        alphaInterpolator = preThresholdAndActiveAlphaSpringInterpolator
                ),
                backgroundDimens = BackgroundDimens(
                        alpha = 1f,
@@ -204,7 +216,7 @@ data class EdgePanelParams(private var resources: Resources) {
                        height = getDimen(R.dimen.navigation_edge_active_background_height),
                        edgeCornerRadius = getDimen(R.dimen.navigation_edge_active_edge_corners),
                        farCornerRadius = getDimen(R.dimen.navigation_edge_active_far_corners),
                        widthSpring = createSpring(375f, 0.675f),
                        widthSpring = createSpring(650f, 0.75f),
                        heightSpring = createSpring(10000f, 1f),
                        edgeCornerRadiusSpring = createSpring(600f, 0.36f),
                        farCornerRadiusSpring = createSpring(2500f, 0.855f),
@@ -223,6 +235,8 @@ data class EdgePanelParams(private var resources: Resources) {
                        alpha = 1f,
                        lengthSpring = createSpring(100f, 0.6f),
                        heightSpring = createSpring(100f, 0.6f),
                        alphaSpring = preThresholdAndActiveAlphaSpring,
                        alphaInterpolator = preThresholdAndActiveAlphaSpringInterpolator
                ),
                backgroundDimens = BackgroundDimens(
                        alpha = 1f,
@@ -255,6 +269,7 @@ data class EdgePanelParams(private var resources: Resources) {
                        heightSpring = flungCommittedHeightSpring,
                        edgeCornerRadiusSpring = flungCommittedEdgeCornerSpring,
                        farCornerRadiusSpring = flungCommittedFarCornerSpring,
                        alphaSpring = createSpring(1100f, 1f),
                ),
                scale = 0.85f,
                scaleSpring = createSpring(1150f, 1f),
@@ -276,7 +291,11 @@ data class EdgePanelParams(private var resources: Resources) {
        )

        cancelledIndicator = entryIndicator.copy(
                backgroundDimens = entryIndicator.backgroundDimens.copy(width = 0f)
                backgroundDimens = entryIndicator.backgroundDimens.copy(
                        width = 0f,
                        alpha = 0f,
                        alphaSpring = createSpring(450f, 1f)
                )
        )

        fullyStretchedIndicator = BackIndicatorDimens(
@@ -306,22 +325,6 @@ data class EdgePanelParams(private var resources: Resources) {
                        farCornerRadiusSpring = null,
                )
        )

        arrowStrokeAlphaInterpolator = Step(
                threshold = showArrowOnProgressValue,
                factor = showArrowOnProgressValueFactor,
                postThreshold = 1f,
                preThreshold = 0f
        )

        entryIndicator.arrowDimens.alphaSpring?.let { alphaSpring ->
            arrowStrokeAlphaSpring = Step(
                    threshold = showArrowOnProgressValue,
                    factor = showArrowOnProgressValueFactor,
                    postThreshold = alphaSpring,
                    preThreshold = SpringForce().setStiffness(2000f).setDampingRatio(1f)
            )
        }
    }
}

+1 −1
Original line number Diff line number Diff line
@@ -127,7 +127,7 @@ class BackPanelControllerTest : SysuiTestCase() {
                mBackPanelController.params.deactivationSwipeTriggerThreshold
        )
        clearInvocations(backCallback)
        Thread.sleep(MIN_DURATION_ACTIVE_ANIMATION)
        Thread.sleep(MIN_DURATION_ACTIVE_BEFORE_INACTIVE_ANIMATION)
        // Move in the opposite direction to cross the deactivation threshold and cancel back
        continueTouch(START_X)