diff options
3 files changed, 85 insertions, 53 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt index 3770b2885b18..96e97565d585 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt @@ -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,30 +405,46 @@ class BackPanelController internal constructor( } GestureState.ACTIVE -> { val isPastDynamicDeactivationThreshold = - totalTouchDelta <= params.deactivationSwipeTriggerThreshold + totalTouchDeltaActive <= params.deactivationTriggerThreshold val isMinDurationElapsed = - elapsedTimeSinceEntry > MIN_DURATION_ACTIVE_BEFORE_INACTIVE_ANIMATION + elapsedTimeSinceEntry > MIN_DURATION_ACTIVE_BEFORE_INACTIVE_ANIMATION if (isMinDurationElapsed && (!isWithinYActivationThreshold || - isPastDynamicDeactivationThreshold) + isPastDynamicDeactivationThreshold) ) { updateArrowState(GestureState.INACTIVE) } } GestureState.INACTIVE -> { val isPastStaticThreshold = - xTranslation > params.staticTriggerThreshold - val isPastDynamicReactivationThreshold = totalTouchDelta > 0 && - abs(totalTouchDelta) >= - params.reactivationTriggerThreshold - - if (isPastStaticThreshold && + xTranslation > params.staticTriggerThreshold + 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,21 +894,24 @@ 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 -> { } + + 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) } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt index c9d8c8495dcc..876c74a9f3e3 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt @@ -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), ) ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/BackPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/BackPanelControllerTest.kt index 8e32f81b193f..d9428f897f0d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/BackPanelControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/BackPanelControllerTest.kt @@ -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) |