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

Commit 76be5a47 authored by Rahul Banerjee's avatar Rahul Banerjee
Browse files

Fix new back arrow's "over eager" appearance

There are two fixes in this cl:
1. The back arrow launches into its ENTRY state too easily: guard it
   with a minimum motion threshold.
2. The cancel animation is triggered upon MotionEvent.ACITON_UP, even
   when there has not been sufficient motion to trigger a change from
   GONE -> ENTRY (invisible to appearance): prevent GONE -> CANCELLED
   state transitions.

Bug: 238907408
Test: manual
Change-Id: I5ab8042fc675cfc527b837578b1d415d2d061d79
parent 18dfc2fb
Loading
Loading
Loading
Loading
+38 −8
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import android.view.Gravity
import android.view.MotionEvent
import android.view.VelocityTracker
import android.view.View
import android.view.ViewConfiguration
import android.view.WindowManager
import android.view.animation.DecelerateInterpolator
import android.view.animation.PathInterpolator
@@ -98,6 +99,7 @@ class BackPanelController private constructor(
    context: Context,
    private var backAnimation: BackAnimation?,
    private val windowManager: WindowManager,
    private val viewConfiguration: ViewConfiguration,
    @Main private val mainHandler: Handler,
    private val vibratorHelper: VibratorHelper,
    private val configurationController: ConfigurationController,
@@ -112,6 +114,7 @@ class BackPanelController private constructor(
     */
    class Factory @Inject constructor(
        private val windowManager: WindowManager,
        private val viewConfiguration: ViewConfiguration,
        @Main private val mainHandler: Handler,
        private val vibratorHelper: VibratorHelper,
        private val configurationController: ConfigurationController,
@@ -123,6 +126,7 @@ class BackPanelController private constructor(
                context,
                backAnimation,
                windowManager,
                viewConfiguration,
                mainHandler,
                vibratorHelper,
                configurationController,
@@ -164,6 +168,10 @@ class BackPanelController private constructor(

    private var gestureStartTime = 0L

    // Whether the current gesture has moved a sufficiently large amount,
    // so that we can unambiguously start showing the ENTRY animation
    private var hasPassedDragSlop = false

    private val failsafeRunnable = Runnable { onFailsafe() }

    private enum class GestureState {
@@ -304,18 +312,17 @@ class BackPanelController private constructor(
                startX = event.x
                startY = event.y
                gestureStartTime = SystemClock.uptimeMillis()

                // Reset the arrow to the side
                updateArrowState(GestureState.ENTRY)

                windowManager.updateViewLayout(mView, layoutParams)
                mView.startTrackingShowBackArrowLatency()
            }
            MotionEvent.ACTION_MOVE -> handleMoveEvent(event)
            MotionEvent.ACTION_MOVE -> {
                // only go to the ENTRY state after some minimum motion has occurred
                if (dragSlopExceeded(event.x, startX)) {
                    handleMoveEvent(event)
                }
            }
            MotionEvent.ACTION_UP -> {
                if (currentState == GestureState.ACTIVE) {
                    updateArrowState(if (isFlung()) GestureState.FLUNG else GestureState.COMMITTED)
                } else {
                } else if (currentState != GestureState.GONE) { // if invisible, skip animation
                    updateArrowState(GestureState.CANCELLED)
                }
                velocityTracker = null
@@ -330,6 +337,28 @@ class BackPanelController private constructor(
        }
    }

    /**
     * Returns false until the current gesture exceeds the touch slop threshold,
     * and returns true thereafter (we reset on the subsequent back gesture).
     * The moment it switches from false -> true is important,
     * because that's when we switch state, from GONE -> ENTRY.
     * @return whether the current gesture has moved past a minimum threshold.
     */
    private fun dragSlopExceeded(curX: Float, startX: Float): Boolean {
        if (hasPassedDragSlop) return true

        if (abs(curX - startX) > viewConfiguration.scaledTouchSlop) {
            // Reset the arrow to the side
            updateArrowState(GestureState.ENTRY)

            windowManager.updateViewLayout(mView, layoutParams)
            mView.startTrackingShowBackArrowLatency()

            hasPassedDragSlop = true
        }
        return hasPassedDragSlop
    }

    private fun updateArrowStateOnMove(yTranslation: Float, xTranslation: Float) {
        if (!currentState.isInteractive())
            return
@@ -533,6 +562,7 @@ class BackPanelController private constructor(
    }

    private fun resetOnDown() {
        hasPassedDragSlop = false
        hasHapticPlayed = false
        totalTouchDelta = 0f
        vibrationTime = 0