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

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

Merge "Simplify arrow stretch width interpolator and edge stickiness" into udc-dev am: 6f2d4091

parents 56e1791c 6f2d4091
Loading
Loading
Loading
Loading
+71 −42
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@ private const val MIN_DURATION_CANCELLED_ANIMATION = 200L
private const val MIN_DURATION_COMMITTED_ANIMATION = 80L
private const val MIN_DURATION_COMMITTED_AFTER_FLING_ANIMATION = 120L
private const val MIN_DURATION_INACTIVE_BEFORE_FLUNG_ANIMATION = 50L
private const val MIN_DURATION_INACTIVE_BEFORE_ACTIVE_ANIMATION = 80L
private const val MIN_DURATION_FLING_ANIMATION = 160L

private const val MIN_DURATION_ENTRY_TO_ACTIVE_CONSIDERED_AS_FLING = 100L
@@ -135,7 +136,8 @@ class BackPanelController internal constructor(
    private lateinit var backCallback: NavigationEdgeBackPlugin.BackCallback
    private var previousXTranslationOnActiveOffset = 0f
    private var previousXTranslation = 0f
    private var totalTouchDelta = 0f
    private var totalTouchDeltaActive = 0f
    private var totalTouchDeltaInactive = 0f
    private var touchDeltaStartX = 0f
    private var velocityTracker: VelocityTracker? = null
        set(value) {
@@ -154,7 +156,7 @@ class BackPanelController internal constructor(

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

    private val elapsedTimeSinceInactive
        get() = SystemClock.uptimeMillis() - gestureInactiveTime
@@ -250,7 +252,7 @@ class BackPanelController internal constructor(
    private fun updateConfiguration() {
        params.update(resources)
        mView.updateArrowPaint(params.arrowThickness)
        minFlingDistance = ViewConfiguration.get(context).scaledTouchSlop * 3
        minFlingDistance = viewConfiguration.scaledTouchSlop * 3
    }

    private val configurationListener = object : ConfigurationController.ConfigurationListener {
@@ -403,7 +405,7 @@ class BackPanelController internal constructor(
            }
            GestureState.ACTIVE -> {
                val isPastDynamicDeactivationThreshold =
                        totalTouchDelta <= params.deactivationSwipeTriggerThreshold
                    totalTouchDeltaActive <= params.deactivationTriggerThreshold
                val isMinDurationElapsed =
                    elapsedTimeSinceEntry > MIN_DURATION_ACTIVE_BEFORE_INACTIVE_ANIMATION

@@ -416,17 +418,33 @@ class BackPanelController internal constructor(
            GestureState.INACTIVE -> {
                val isPastStaticThreshold =
                    xTranslation > params.staticTriggerThreshold
                val isPastDynamicReactivationThreshold = totalTouchDelta > 0 &&
                        abs(totalTouchDelta) >=
                        params.reactivationTriggerThreshold

                if (isPastStaticThreshold &&
                val isPastDynamicReactivationThreshold =
                    totalTouchDeltaInactive >= params.reactivationTriggerThreshold
                val isPastAllThresholds = isPastStaticThreshold &&
                        isPastDynamicReactivationThreshold &&
                        isWithinYActivationThreshold
                ) {
                val isPastAllThresholdsForFirstTime = isPastAllThresholds &&
                        gesturePastActiveThresholdWhileInactiveTime == 0L

                gesturePastActiveThresholdWhileInactiveTime = when {
                    isPastAllThresholdsForFirstTime -> SystemClock.uptimeMillis()
                    isPastAllThresholds -> gesturePastActiveThresholdWhileInactiveTime
                    else -> 0L
                }

                val elapsedTimePastAllThresholds =
                    SystemClock.uptimeMillis() - gesturePastActiveThresholdWhileInactiveTime

                val isPastMinimumInactiveToActiveDuration =
                    elapsedTimePastAllThresholds > MIN_DURATION_INACTIVE_BEFORE_ACTIVE_ANIMATION

                if (isPastAllThresholds && isPastMinimumInactiveToActiveDuration) {
                    // The minimum duration adds the 'edge stickiness'
                    // factor before pulling it off edge
                    updateArrowState(GestureState.ACTIVE)
                }
            }

            else -> {}
        }
    }
@@ -451,19 +469,25 @@ class BackPanelController internal constructor(
        previousXTranslation = xTranslation

        if (abs(xDelta) > 0) {
            val range =
                params.run { deactivationSwipeTriggerThreshold..reactivationTriggerThreshold }
            val isTouchInContinuousDirection =
                    sign(xDelta) == sign(totalTouchDelta) || totalTouchDelta in range
            val isInSameDirection = sign(xDelta) == sign(totalTouchDeltaActive)
            val isInDynamicRange = totalTouchDeltaActive in params.dynamicTriggerThresholdRange
            val isTouchInContinuousDirection = isInSameDirection || isInDynamicRange

            if (isTouchInContinuousDirection) {
                // Direction has NOT changed, so keep counting the delta
                totalTouchDelta += xDelta
                totalTouchDeltaActive += xDelta
            } else {
                // Direction has changed, so reset the delta
                totalTouchDelta = xDelta
                totalTouchDeltaActive = xDelta
                touchDeltaStartX = x
            }

            // Add a slop to to prevent small jitters when arrow is at edge in
            // emitting small values that cause the arrow to poke out slightly
            val minimumDelta = -viewConfiguration.scaledTouchSlop.toFloat()
            totalTouchDeltaInactive = totalTouchDeltaInactive
                .plus(xDelta)
                .coerceAtLeast(minimumDelta)
        }

        updateArrowStateOnMove(yTranslation, xTranslation)
@@ -471,7 +495,7 @@ class BackPanelController internal constructor(
        val gestureProgress = when (currentState) {
            GestureState.ACTIVE -> fullScreenProgress(xTranslation)
            GestureState.ENTRY -> staticThresholdProgress(xTranslation)
            GestureState.INACTIVE -> reactivationThresholdProgress(totalTouchDelta)
            GestureState.INACTIVE -> reactivationThresholdProgress(totalTouchDeltaInactive)
            else -> null
        }

@@ -529,8 +553,7 @@ class BackPanelController internal constructor(
     * the arrow is fully stretched (between 0.0 - 1.0f)
     */
    private fun fullScreenProgress(xTranslation: Float): Float {
        val progress = abs((xTranslation - previousXTranslationOnActiveOffset) /
                (fullyStretchedThreshold - previousXTranslationOnActiveOffset))
        val progress = (xTranslation - previousXTranslationOnActiveOffset) / fullyStretchedThreshold
        return MathUtils.saturate(progress)
    }

@@ -581,13 +604,15 @@ class BackPanelController internal constructor(
    }

    private var previousPreThresholdWidthInterpolator = params.entryWidthTowardsEdgeInterpolator
    fun preThresholdWidthStretchAmount(progress: Float): Float {
    private fun preThresholdWidthStretchAmount(progress: Float): Float {
        val interpolator = run {
            val isPastSlop = abs(totalTouchDelta) > ViewConfiguration.get(context).scaledTouchSlop
            val isPastSlop = totalTouchDeltaInactive > viewConfiguration.scaledTouchSlop
            if (isPastSlop) {
                if (totalTouchDelta > 0) {
                if (totalTouchDeltaInactive > 0) {
                    params.entryWidthInterpolator
                } else params.entryWidthTowardsEdgeInterpolator
                } else {
                    params.entryWidthTowardsEdgeInterpolator
                }
            } else {
                previousPreThresholdWidthInterpolator
            }.also { previousPreThresholdWidthInterpolator = it }
@@ -643,7 +668,7 @@ class BackPanelController internal constructor(
            xVelocity.takeIf { mView.isLeftPanel } ?: (xVelocity * -1)
        } ?: 0f
        val isPastFlingVelocityThreshold =
                flingVelocity > ViewConfiguration.get(context).scaledMinimumFlingVelocity
                flingVelocity > viewConfiguration.scaledMinimumFlingVelocity
        return flingDistance > minFlingDistance && isPastFlingVelocityThreshold
    }

@@ -861,7 +886,6 @@ class BackPanelController internal constructor(
            }
            GestureState.ACTIVE -> {
                previousXTranslationOnActiveOffset = previousXTranslation
                gestureActiveTime = SystemClock.uptimeMillis()

                updateRestingArrowDimens()

@@ -870,20 +894,23 @@ class BackPanelController internal constructor(
                    vibratorHelper.vibrate(VIBRATE_ACTIVATED_EFFECT)
                }

                val startingVelocity = convertVelocityToSpringStartingVelocity(
                    valueOnFastVelocity = 0f,
                    valueOnSlowVelocity = if (previousState == GestureState.ENTRY) 2f else 4.5f
                )
                val minimumPop = 2f
                val maximumPop = 4.5f

                when (previousState) {
                    GestureState.ENTRY,
                    GestureState.INACTIVE -> {
                    GestureState.ENTRY -> {
                        val startingVelocity = convertVelocityToSpringStartingVelocity(
                            valueOnFastVelocity = minimumPop,
                            valueOnSlowVelocity = maximumPop,
                            fastVelocityBound = 1f,
                            slowVelocityBound = 0.5f,
                        )
                        mView.popOffEdge(startingVelocity)
                    }
                    GestureState.COMMITTED -> {
                        // if previous state was committed then this activation
                        // was due to a quick second swipe. Don't pop the arrow this time
                    GestureState.INACTIVE -> {
                        mView.popOffEdge(maximumPop)
                    }

                    else -> {}
                }
            }
@@ -896,7 +923,7 @@ class BackPanelController internal constructor(
                // but because we can also independently enter this state
                // if touch Y >> touch X, we force it to deactivationSwipeTriggerThreshold
                // so that gesture progress in this state is consistent regardless of entry
                totalTouchDelta = params.deactivationSwipeTriggerThreshold
                totalTouchDeltaInactive = params.deactivationTriggerThreshold

                val startingVelocity = convertVelocityToSpringStartingVelocity(
                        valueOnFastVelocity = -1.05f,
@@ -944,10 +971,12 @@ class BackPanelController internal constructor(
    private fun convertVelocityToSpringStartingVelocity(
            valueOnFastVelocity: Float,
            valueOnSlowVelocity: Float,
            fastVelocityBound: Float = 3f,
            slowVelocityBound: Float = 0f,
    ): Float {
        val factor = velocityTracker?.run {
            computeCurrentVelocity(PX_PER_MS)
            MathUtils.smoothStep(0f, 3f, abs(xVelocity))
            MathUtils.smoothStep(slowVelocityBound, fastVelocityBound, abs(xVelocity))
        } ?: valueOnFastVelocity

        return MathUtils.lerp(valueOnFastVelocity, valueOnSlowVelocity, 1 - factor)
@@ -982,7 +1011,7 @@ class BackPanelController internal constructor(
                    "$currentState",
                    "startX=$startX",
                    "startY=$startY",
                    "xDelta=${"%.1f".format(totalTouchDelta)}",
                    "xDelta=${"%.1f".format(totalTouchDeltaActive)}",
                    "xTranslation=${"%.1f".format(previousXTranslation)}",
                    "pre=${"%.0f".format(staticThresholdProgress(previousXTranslation) * 100)}%",
                    "post=${"%.0f".format(fullScreenProgress(previousXTranslation) * 100)}%"
@@ -1023,7 +1052,7 @@ class BackPanelController internal constructor(
            }

            drawVerticalLine(x = params.staticTriggerThreshold, color = Color.BLUE)
            drawVerticalLine(x = params.deactivationSwipeTriggerThreshold, color = Color.BLUE)
            drawVerticalLine(x = params.deactivationTriggerThreshold, color = Color.BLUE)
            drawVerticalLine(x = startX, color = Color.GREEN)
            drawVerticalLine(x = previousXTranslation, color = Color.DKGRAY)
        }
+13 −10
Original line number Diff line number Diff line
@@ -72,9 +72,11 @@ data class EdgePanelParams(private var resources: Resources) {
        private set
    var reactivationTriggerThreshold: Float = 0f
        private set
    var deactivationSwipeTriggerThreshold: Float = 0f
    var deactivationTriggerThreshold: Float = 0f
        get() = -field
        private set
    lateinit var dynamicTriggerThresholdRange: ClosedRange<Float>
        private set
    var swipeProgressThreshold: Float = 0f
        private set

@@ -122,8 +124,10 @@ data class EdgePanelParams(private var resources: Resources) {
        staticTriggerThreshold = getDimen(R.dimen.navigation_edge_action_drag_threshold)
        reactivationTriggerThreshold =
                getDimen(R.dimen.navigation_edge_action_reactivation_drag_threshold)
        deactivationSwipeTriggerThreshold =
        deactivationTriggerThreshold =
                getDimen(R.dimen.navigation_edge_action_deactivation_drag_threshold)
        dynamicTriggerThresholdRange =
                reactivationTriggerThreshold..deactivationTriggerThreshold
        swipeProgressThreshold = getDimen(R.dimen.navigation_edge_action_progress_threshold)

        entryWidthInterpolator = PathInterpolator(.19f, 1.27f, .71f, .86f)
@@ -136,7 +140,6 @@ data class EdgePanelParams(private var resources: Resources) {
        edgeCornerInterpolator = PathInterpolator(0f, 1.11f, .85f, .84f)
        heightInterpolator = PathInterpolator(1f, .05f, .9f, -0.29f)

        val entryActiveHorizontalTranslationSpring = createSpring(800f, 0.76f)
        val activeCommittedArrowLengthSpring = createSpring(1500f, 0.29f)
        val activeCommittedArrowHeightSpring = createSpring(1500f, 0.29f)
        val flungCommittedEdgeCornerSpring = createSpring(10000f, 1f)
@@ -150,7 +153,7 @@ data class EdgePanelParams(private var resources: Resources) {
                horizontalTranslation = getDimen(R.dimen.navigation_edge_entry_margin),
                scale = getDimenFloat(R.dimen.navigation_edge_entry_scale),
                scalePivotX = getDimen(R.dimen.navigation_edge_pre_threshold_background_width),
                horizontalTranslationSpring = entryActiveHorizontalTranslationSpring,
                horizontalTranslationSpring = createSpring(500f, 0.76f),
                verticalTranslationSpring = createSpring(30000f, 1f),
                scaleSpring = createSpring(120f, 0.8f),
                arrowDimens = ArrowDimens(
@@ -202,7 +205,7 @@ data class EdgePanelParams(private var resources: Resources) {
        activeIndicator = BackIndicatorDimens(
                horizontalTranslation = getDimen(R.dimen.navigation_edge_active_margin),
                scale = getDimenFloat(R.dimen.navigation_edge_active_scale),
                horizontalTranslationSpring = entryActiveHorizontalTranslationSpring,
                horizontalTranslationSpring = createSpring(1000f, 0.7f),
                scaleSpring = createSpring(450f, 0.39f),
                scalePivotX = getDimen(R.dimen.navigation_edge_active_background_width),
                arrowDimens = ArrowDimens(
@@ -222,8 +225,8 @@ data class EdgePanelParams(private var resources: Resources) {
                        farCornerRadius = getDimen(R.dimen.navigation_edge_active_far_corners),
                        widthSpring = createSpring(850f, 0.75f),
                        heightSpring = createSpring(10000f, 1f),
                        edgeCornerRadiusSpring = createSpring(600f, 0.36f),
                        farCornerRadiusSpring = createSpring(2500f, 0.855f),
                        edgeCornerRadiusSpring = createSpring(2600f, 0.855f),
                        farCornerRadiusSpring = createSpring(1200f, 0.30f),
                )
        )

@@ -250,10 +253,10 @@ data class EdgePanelParams(private var resources: Resources) {
                                getDimen(R.dimen.navigation_edge_pre_threshold_edge_corners),
                        farCornerRadius =
                                getDimen(R.dimen.navigation_edge_pre_threshold_far_corners),
                        widthSpring = createSpring(250f, 0.65f),
                        widthSpring = createSpring(400f, 0.65f),
                        heightSpring = createSpring(1500f, 0.45f),
                        farCornerRadiusSpring = createSpring(200f, 1f),
                        edgeCornerRadiusSpring = createSpring(150f, 0.5f),
                        farCornerRadiusSpring = createSpring(300f, 1f),
                        edgeCornerRadiusSpring = createSpring(250f, 0.5f),
                )
        )

+1 −1
Original line number Diff line number Diff line
@@ -124,7 +124,7 @@ class BackPanelControllerTest : SysuiTestCase() {
        continueTouch(START_X + touchSlop.toFloat() + 1)
        continueTouch(
            START_X + touchSlop + triggerThreshold -
                mBackPanelController.params.deactivationSwipeTriggerThreshold
                mBackPanelController.params.deactivationTriggerThreshold
        )
        clearInvocations(backCallback)
        Thread.sleep(MIN_DURATION_ACTIVE_BEFORE_INACTIVE_ANIMATION)