Loading packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanel.kt +157 −141 Original line number Diff line number Diff line Loading @@ -18,10 +18,7 @@ import com.android.systemui.navigationbar.gestural.BackPanelController.DelayedOn private const val TAG = "BackPanel" private const val DEBUG = false class BackPanel( context: Context, private val latencyTracker: LatencyTracker ) : View(context) { class BackPanel(context: Context, private val latencyTracker: LatencyTracker) : View(context) { var arrowsPointLeft = false set(value) { Loading @@ -42,15 +39,12 @@ class BackPanel( // True if the panel is currently on the left of the screen var isLeftPanel = false /** * Used to track back arrow latency from [android.view.MotionEvent.ACTION_DOWN] to [onDraw] */ /** Used to track back arrow latency from [android.view.MotionEvent.ACTION_DOWN] to [onDraw] */ private var trackingBackArrowLatency = false /** * The length of the arrow measured horizontally. Used for animating [arrowPath] */ private var arrowLength = AnimatedFloat( /** The length of the arrow measured horizontally. Used for animating [arrowPath] */ private var arrowLength = AnimatedFloat( name = "arrowLength", minimumVisibleChange = SpringAnimation.MIN_VISIBLE_CHANGE_PIXELS ) Loading @@ -59,18 +53,21 @@ class BackPanel( * The height of the arrow measured vertically from its center to its top (i.e. half the total * height). Used for animating [arrowPath] */ var arrowHeight = AnimatedFloat( var arrowHeight = AnimatedFloat( name = "arrowHeight", minimumVisibleChange = SpringAnimation.MIN_VISIBLE_CHANGE_ROTATION_DEGREES ) val backgroundWidth = AnimatedFloat( val backgroundWidth = AnimatedFloat( name = "backgroundWidth", minimumVisibleChange = SpringAnimation.MIN_VISIBLE_CHANGE_PIXELS, minimumValue = 0f, ) val backgroundHeight = AnimatedFloat( val backgroundHeight = AnimatedFloat( name = "backgroundHeight", minimumVisibleChange = SpringAnimation.MIN_VISIBLE_CHANGE_PIXELS, minimumValue = 0f, Loading @@ -88,13 +85,15 @@ class BackPanel( */ val backgroundFarCornerRadius = AnimatedFloat("backgroundFarCornerRadius") var scale = AnimatedFloat( var scale = AnimatedFloat( name = "scale", minimumVisibleChange = SpringAnimation.MIN_VISIBLE_CHANGE_SCALE, minimumValue = 0f ) val scalePivotX = AnimatedFloat( val scalePivotX = AnimatedFloat( name = "scalePivotX", minimumVisibleChange = SpringAnimation.MIN_VISIBLE_CHANGE_PIXELS, minimumValue = backgroundWidth.pos / 2, Loading @@ -107,21 +106,24 @@ class BackPanel( */ var horizontalTranslation = AnimatedFloat(name = "horizontalTranslation") var arrowAlpha = AnimatedFloat( var arrowAlpha = AnimatedFloat( name = "arrowAlpha", minimumVisibleChange = SpringAnimation.MIN_VISIBLE_CHANGE_ALPHA, minimumValue = 0f, maximumValue = 1f ) val backgroundAlpha = AnimatedFloat( val backgroundAlpha = AnimatedFloat( name = "backgroundAlpha", minimumVisibleChange = SpringAnimation.MIN_VISIBLE_CHANGE_ALPHA, minimumValue = 0f, maximumValue = 1f ) private val allAnimatedFloat = setOf( private val allAnimatedFloat = setOf( arrowLength, arrowHeight, backgroundWidth, Loading @@ -140,22 +142,22 @@ class BackPanel( */ var verticalTranslation = AnimatedFloat("verticalTranslation") /** * Use for drawing debug info. Can only be set if [DEBUG]=true */ /** Use for drawing debug info. Can only be set if [DEBUG]=true */ var drawDebugInfo: ((canvas: Canvas) -> Unit)? = null set(value) { if (DEBUG) field = value } internal fun updateArrowPaint(arrowThickness: Float) { arrowPaint.strokeWidth = arrowThickness val isDeviceInNightTheme = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES val isDeviceInNightTheme = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES arrowPaint.color = Utils.getColorAttrDefaultColor(context, arrowPaint.color = Utils.getColorAttrDefaultColor( context, if (isDeviceInNightTheme) { com.android.internal.R.attr.materialColorOnSecondaryContainer } else { Loading @@ -163,7 +165,9 @@ class BackPanel( } ) arrowBackgroundPaint.color = Utils.getColorAttrDefaultColor(context, arrowBackgroundPaint.color = Utils.getColorAttrDefaultColor( context, if (isDeviceInNightTheme) { com.android.internal.R.attr.materialColorSecondaryContainer } else { Loading Loading @@ -207,14 +211,16 @@ class BackPanel( } init { val floatProp = object : FloatPropertyCompat<AnimatedFloat>(name) { val floatProp = object : FloatPropertyCompat<AnimatedFloat>(name) { override fun setValue(animatedFloat: AnimatedFloat, value: Float) { animatedFloat.pos = value } override fun getValue(animatedFloat: AnimatedFloat): Float = animatedFloat.pos } animation = SpringAnimation(this, floatProp).apply { animation = SpringAnimation(this, floatProp).apply { spring = SpringForce() this@AnimatedFloat.minimumValue?.let { setMinValue(it) } this@AnimatedFloat.maximumValue?.let { setMaxValue(it) } Loading @@ -233,7 +239,6 @@ class BackPanel( snapTo(restingPosition) } fun stretchTo( stretchAmount: Float, startingVelocity: Float? = null, Loading Loading @@ -373,8 +378,11 @@ class BackPanel( } fun popArrowAlpha(startingVelocity: Float, springForce: SpringForce? = null) { arrowAlpha.stretchTo(stretchAmount = 0f, startingVelocity = startingVelocity, springForce = springForce) arrowAlpha.stretchTo( stretchAmount = 0f, startingVelocity = startingVelocity, springForce = springForce ) } fun resetStretch() { Loading @@ -392,9 +400,7 @@ class BackPanel( backgroundFarCornerRadius.snapToRestingPosition() } /** * Updates resting arrow and background size not accounting for stretch */ /** Updates resting arrow and background size not accounting for stretch */ internal fun setRestingDimens( restingParams: EdgePanelParams.BackIndicatorDimens, animate: Boolean = true Loading @@ -410,10 +416,12 @@ class BackPanel( backgroundWidth.updateRestingPosition(restingParams.backgroundDimens.width, animate) backgroundHeight.updateRestingPosition(restingParams.backgroundDimens.height, animate) backgroundEdgeCornerRadius.updateRestingPosition( restingParams.backgroundDimens.edgeCornerRadius, animate restingParams.backgroundDimens.edgeCornerRadius, animate ) backgroundFarCornerRadius.updateRestingPosition( restingParams.backgroundDimens.farCornerRadius, animate restingParams.backgroundDimens.farCornerRadius, animate ) } Loading Loading @@ -459,26 +467,28 @@ class BackPanel( if (!isLeftPanel) canvas.scale(-1f, 1f, canvasWidth / 2.0f, 0f) canvas.translate( horizontalTranslation.pos, height * 0.5f + verticalTranslation.pos ) canvas.translate(horizontalTranslation.pos, height * 0.5f + verticalTranslation.pos) canvas.scale(scale.pos, scale.pos, scalePivotX, 0f) val arrowBackground = arrowBackgroundRect.apply { val arrowBackground = arrowBackgroundRect .apply { left = 0f top = -halfHeight right = backgroundWidth bottom = halfHeight }.toPathWithRoundCorners( } .toPathWithRoundCorners( topLeft = edgeCorner, bottomLeft = edgeCorner, topRight = farCorner, bottomRight = farCorner ) canvas.drawPath(arrowBackground, arrowBackgroundPaint.apply { alpha = (255 * backgroundAlpha.pos).toInt() }) canvas.drawPath( arrowBackground, arrowBackgroundPaint.apply { alpha = (255 * backgroundAlpha.pos).toInt() } ) val dx = arrowLength.pos val dy = arrowHeight.pos Loading @@ -500,8 +510,8 @@ class BackPanel( } val arrowPath = calculateArrowPath(dx = dx, dy = dy) val arrowPaint = arrowPaint .apply { alpha = (255 * min(arrowAlpha.pos, backgroundAlpha.pos)).toInt() } val arrowPaint = arrowPaint.apply { alpha = (255 * min(arrowAlpha.pos, backgroundAlpha.pos)).toInt() } canvas.drawPath(arrowPath, arrowPaint) canvas.restore() Loading @@ -523,12 +533,18 @@ class BackPanel( topRight: Float = 0f, bottomRight: Float = 0f, bottomLeft: Float = 0f ): Path = Path().apply { val corners = floatArrayOf( topLeft, topLeft, topRight, topRight, bottomRight, bottomRight, bottomLeft, bottomLeft ): Path = Path().apply { val corners = floatArrayOf( topLeft, topLeft, topRight, topRight, bottomRight, bottomRight, bottomLeft, bottomLeft ) addRoundRect(this@toPathWithRoundCorners, corners, Path.Direction.CW) } Loading packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt +8 −9 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ import android.view.Gravity import android.view.HapticFeedbackConstants import android.view.MotionEvent import android.view.VelocityTracker import android.view.View import android.view.ViewConfiguration import android.view.WindowManager import androidx.annotation.VisibleForTesting Loading Loading @@ -164,6 +163,7 @@ internal constructor( private val elapsedTimeSinceInactive get() = systemClock.uptimeMillis() - gestureInactiveTime private val elapsedTimeSinceEntry get() = systemClock.uptimeMillis() - gestureEntryTime Loading Loading @@ -612,6 +612,7 @@ internal constructor( } private var previousPreThresholdWidthInterpolator = params.entryWidthInterpolator private fun preThresholdWidthStretchAmount(progress: Float): Float { val interpolator = run { val isPastSlop = totalTouchDeltaInactive > viewConfiguration.scaledTouchSlop Loading Loading @@ -677,8 +678,7 @@ internal constructor( velocityTracker?.run { computeCurrentVelocity(PX_PER_SEC) xVelocity.takeIf { mView.isLeftPanel } ?: (xVelocity * -1) } ?: 0f } ?: 0f val isPastFlingVelocityThreshold = flingVelocity > viewConfiguration.scaledMinimumFlingVelocity return flingDistance > minFlingDistance && isPastFlingVelocityThreshold Loading Loading @@ -1028,8 +1028,7 @@ internal constructor( velocityTracker?.run { computeCurrentVelocity(PX_PER_MS) MathUtils.smoothStep(slowVelocityBound, fastVelocityBound, abs(xVelocity)) } ?: valueOnFastVelocity } ?: valueOnFastVelocity return MathUtils.lerp(valueOnFastVelocity, valueOnSlowVelocity, 1 - factor) } Loading packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt +132 −86 Original line number Diff line number Diff line Loading @@ -45,57 +45,79 @@ data class EdgePanelParams(private var resources: Resources) { lateinit var entryIndicator: BackIndicatorDimens private set lateinit var activeIndicator: BackIndicatorDimens private set lateinit var cancelledIndicator: BackIndicatorDimens private set lateinit var flungIndicator: BackIndicatorDimens private set lateinit var committedIndicator: BackIndicatorDimens private set lateinit var preThresholdIndicator: BackIndicatorDimens private set lateinit var fullyStretchedIndicator: BackIndicatorDimens private set // navigation bar edge constants var arrowPaddingEnd: Int = 0 private set var arrowThickness: Float = 0f private set // The closest to y var minArrowYPosition: Int = 0 private set var fingerOffset: Int = 0 private set var staticTriggerThreshold: Float = 0f private set var reactivationTriggerThreshold: Float = 0f private set var deactivationTriggerThreshold: Float = 0f get() = -field private set lateinit var dynamicTriggerThresholdRange: ClosedRange<Float> private set var swipeProgressThreshold: Float = 0f private set lateinit var entryWidthInterpolator: Interpolator private set lateinit var entryWidthTowardsEdgeInterpolator: Interpolator private set lateinit var activeWidthInterpolator: Interpolator private set lateinit var arrowAngleInterpolator: Interpolator private set lateinit var horizontalTranslationInterpolator: Interpolator private set lateinit var verticalTranslationInterpolator: Interpolator private set lateinit var farCornerInterpolator: Interpolator private set lateinit var edgeCornerInterpolator: Interpolator private set lateinit var heightInterpolator: Interpolator private set Loading @@ -108,7 +130,10 @@ data class EdgePanelParams(private var resources: Resources) { } private fun getDimenFloat(id: Int): Float { return TypedValue().run { resources.getValue(id, this, true); float } return TypedValue().run { resources.getValue(id, this, true) float } } private fun getPx(id: Int): Int { Loading @@ -126,8 +151,7 @@ data class EdgePanelParams(private var resources: Resources) { getDimen(R.dimen.navigation_edge_action_reactivation_drag_threshold) deactivationTriggerThreshold = getDimen(R.dimen.navigation_edge_action_deactivation_drag_threshold) dynamicTriggerThresholdRange = reactivationTriggerThreshold..deactivationTriggerThreshold dynamicTriggerThresholdRange = reactivationTriggerThreshold..deactivationTriggerThreshold swipeProgressThreshold = getDimen(R.dimen.navigation_edge_action_progress_threshold) entryWidthInterpolator = PathInterpolator(.19f, 1.27f, .71f, .86f) Loading @@ -149,27 +173,31 @@ data class EdgePanelParams(private var resources: Resources) { val commonArrowDimensAlphaThreshold = .165f val commonArrowDimensAlphaFactor = 1.05f val commonArrowDimensAlphaSpring = Step( val commonArrowDimensAlphaSpring = Step( threshold = commonArrowDimensAlphaThreshold, factor = commonArrowDimensAlphaFactor, postThreshold = createSpring(180f, 0.9f), preThreshold = createSpring(2000f, 0.6f) ) val commonArrowDimensAlphaSpringInterpolator = Step( val commonArrowDimensAlphaSpringInterpolator = Step( threshold = commonArrowDimensAlphaThreshold, factor = commonArrowDimensAlphaFactor, postThreshold = 1f, preThreshold = 0f ) entryIndicator = BackIndicatorDimens( entryIndicator = BackIndicatorDimens( 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 = createSpring(800f, 0.76f), verticalTranslationSpring = createSpring(30000f, 1f), scaleSpring = createSpring(120f, 0.8f), arrowDimens = ArrowDimens( arrowDimens = ArrowDimens( length = getDimen(R.dimen.navigation_edge_entry_arrow_length), height = getDimen(R.dimen.navigation_edge_entry_arrow_height), alpha = 0f, Loading @@ -178,7 +206,8 @@ data class EdgePanelParams(private var resources: Resources) { alphaSpring = commonArrowDimensAlphaSpring, alphaInterpolator = commonArrowDimensAlphaSpringInterpolator ), backgroundDimens = BackgroundDimens( backgroundDimens = BackgroundDimens( alpha = 1f, width = getDimen(R.dimen.navigation_edge_entry_background_width), height = getDimen(R.dimen.navigation_edge_entry_background_height), Loading @@ -191,13 +220,15 @@ data class EdgePanelParams(private var resources: Resources) { ) ) activeIndicator = BackIndicatorDimens( activeIndicator = BackIndicatorDimens( horizontalTranslation = getDimen(R.dimen.navigation_edge_active_margin), scale = getDimenFloat(R.dimen.navigation_edge_active_scale), horizontalTranslationSpring = createSpring(1000f, 0.8f), scaleSpring = createSpring(325f, 0.55f), scalePivotX = getDimen(R.dimen.navigation_edge_active_background_width), arrowDimens = ArrowDimens( arrowDimens = ArrowDimens( length = getDimen(R.dimen.navigation_edge_active_arrow_length), height = getDimen(R.dimen.navigation_edge_active_arrow_height), alpha = 1f, Loading @@ -206,7 +237,8 @@ data class EdgePanelParams(private var resources: Resources) { alphaSpring = commonArrowDimensAlphaSpring, alphaInterpolator = commonArrowDimensAlphaSpringInterpolator ), backgroundDimens = BackgroundDimens( backgroundDimens = BackgroundDimens( alpha = 1f, width = getDimen(R.dimen.navigation_edge_active_background_width), height = getDimen(R.dimen.navigation_edge_active_background_height), Loading @@ -219,13 +251,15 @@ data class EdgePanelParams(private var resources: Resources) { ) ) preThresholdIndicator = BackIndicatorDimens( preThresholdIndicator = BackIndicatorDimens( horizontalTranslation = getDimen(R.dimen.navigation_edge_pre_threshold_margin), scale = getDimenFloat(R.dimen.navigation_edge_pre_threshold_scale), scalePivotX = getDimen(R.dimen.navigation_edge_pre_threshold_background_width), scaleSpring = createSpring(120f, 0.8f), horizontalTranslationSpring = createSpring(6000f, 1f), arrowDimens = ArrowDimens( arrowDimens = ArrowDimens( length = getDimen(R.dimen.navigation_edge_pre_threshold_arrow_length), height = getDimen(R.dimen.navigation_edge_pre_threshold_arrow_height), alpha = 1f, Loading @@ -234,7 +268,8 @@ data class EdgePanelParams(private var resources: Resources) { alphaSpring = commonArrowDimensAlphaSpring, alphaInterpolator = commonArrowDimensAlphaSpringInterpolator ), backgroundDimens = BackgroundDimens( backgroundDimens = BackgroundDimens( alpha = 1f, width = getDimen(R.dimen.navigation_edge_pre_threshold_background_width), height = getDimen(R.dimen.navigation_edge_pre_threshold_background_height), Loading @@ -249,16 +284,19 @@ data class EdgePanelParams(private var resources: Resources) { ) ) committedIndicator = activeIndicator.copy( committedIndicator = activeIndicator.copy( horizontalTranslation = null, scalePivotX = null, arrowDimens = activeIndicator.arrowDimens.copy( arrowDimens = activeIndicator.arrowDimens.copy( lengthSpring = activeCommittedArrowLengthSpring, heightSpring = activeCommittedArrowHeightSpring, length = null, height = null, ), backgroundDimens = activeIndicator.backgroundDimens.copy( backgroundDimens = activeIndicator.backgroundDimens.copy( alpha = 0f, // explicitly set to null to preserve previous width upon state change width = null, Loading @@ -272,14 +310,17 @@ data class EdgePanelParams(private var resources: Resources) { scaleSpring = createSpring(5700f, 1f), ) flungIndicator = committedIndicator.copy( arrowDimens = committedIndicator.arrowDimens.copy( flungIndicator = committedIndicator.copy( arrowDimens = committedIndicator.arrowDimens.copy( lengthSpring = createSpring(850f, 0.46f), heightSpring = createSpring(850f, 0.46f), length = activeIndicator.arrowDimens.length, height = activeIndicator.arrowDimens.height ), backgroundDimens = committedIndicator.backgroundDimens.copy( backgroundDimens = committedIndicator.backgroundDimens.copy( widthSpring = flungCommittedWidthSpring, heightSpring = flungCommittedHeightSpring, edgeCornerRadiusSpring = flungCommittedEdgeCornerSpring, Loading @@ -287,21 +328,25 @@ data class EdgePanelParams(private var resources: Resources) { ) ) cancelledIndicator = entryIndicator.copy( backgroundDimens = entryIndicator.backgroundDimens.copy( cancelledIndicator = entryIndicator.copy( backgroundDimens = entryIndicator.backgroundDimens.copy( width = 0f, alpha = 0f, alphaSpring = createSpring(450f, 1f) ) ) fullyStretchedIndicator = BackIndicatorDimens( fullyStretchedIndicator = BackIndicatorDimens( horizontalTranslation = getDimen(R.dimen.navigation_edge_stretch_margin), scale = getDimenFloat(R.dimen.navigation_edge_stretch_scale), horizontalTranslationSpring = null, verticalTranslationSpring = null, scaleSpring = null, arrowDimens = ArrowDimens( arrowDimens = ArrowDimens( length = getDimen(R.dimen.navigation_edge_stretched_arrow_length), height = getDimen(R.dimen.navigation_edge_stretched_arrow_height), alpha = 1f, Loading @@ -309,7 +354,8 @@ data class EdgePanelParams(private var resources: Resources) { heightSpring = null, lengthSpring = null, ), backgroundDimens = BackgroundDimens( backgroundDimens = BackgroundDimens( alpha = 1f, width = getDimen(R.dimen.navigation_edge_stretch_background_width), height = getDimen(R.dimen.navigation_edge_stretch_background_height), Loading packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/BackPanelControllerTest.kt +1 −0 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ class BackPanelControllerTest : SysuiTestCase() { companion object { private const val START_X: Float = 0f } private val kosmos = testKosmos() private lateinit var mBackPanelController: BackPanelController private lateinit var systemClock: FakeSystemClock Loading Loading
packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanel.kt +157 −141 Original line number Diff line number Diff line Loading @@ -18,10 +18,7 @@ import com.android.systemui.navigationbar.gestural.BackPanelController.DelayedOn private const val TAG = "BackPanel" private const val DEBUG = false class BackPanel( context: Context, private val latencyTracker: LatencyTracker ) : View(context) { class BackPanel(context: Context, private val latencyTracker: LatencyTracker) : View(context) { var arrowsPointLeft = false set(value) { Loading @@ -42,15 +39,12 @@ class BackPanel( // True if the panel is currently on the left of the screen var isLeftPanel = false /** * Used to track back arrow latency from [android.view.MotionEvent.ACTION_DOWN] to [onDraw] */ /** Used to track back arrow latency from [android.view.MotionEvent.ACTION_DOWN] to [onDraw] */ private var trackingBackArrowLatency = false /** * The length of the arrow measured horizontally. Used for animating [arrowPath] */ private var arrowLength = AnimatedFloat( /** The length of the arrow measured horizontally. Used for animating [arrowPath] */ private var arrowLength = AnimatedFloat( name = "arrowLength", minimumVisibleChange = SpringAnimation.MIN_VISIBLE_CHANGE_PIXELS ) Loading @@ -59,18 +53,21 @@ class BackPanel( * The height of the arrow measured vertically from its center to its top (i.e. half the total * height). Used for animating [arrowPath] */ var arrowHeight = AnimatedFloat( var arrowHeight = AnimatedFloat( name = "arrowHeight", minimumVisibleChange = SpringAnimation.MIN_VISIBLE_CHANGE_ROTATION_DEGREES ) val backgroundWidth = AnimatedFloat( val backgroundWidth = AnimatedFloat( name = "backgroundWidth", minimumVisibleChange = SpringAnimation.MIN_VISIBLE_CHANGE_PIXELS, minimumValue = 0f, ) val backgroundHeight = AnimatedFloat( val backgroundHeight = AnimatedFloat( name = "backgroundHeight", minimumVisibleChange = SpringAnimation.MIN_VISIBLE_CHANGE_PIXELS, minimumValue = 0f, Loading @@ -88,13 +85,15 @@ class BackPanel( */ val backgroundFarCornerRadius = AnimatedFloat("backgroundFarCornerRadius") var scale = AnimatedFloat( var scale = AnimatedFloat( name = "scale", minimumVisibleChange = SpringAnimation.MIN_VISIBLE_CHANGE_SCALE, minimumValue = 0f ) val scalePivotX = AnimatedFloat( val scalePivotX = AnimatedFloat( name = "scalePivotX", minimumVisibleChange = SpringAnimation.MIN_VISIBLE_CHANGE_PIXELS, minimumValue = backgroundWidth.pos / 2, Loading @@ -107,21 +106,24 @@ class BackPanel( */ var horizontalTranslation = AnimatedFloat(name = "horizontalTranslation") var arrowAlpha = AnimatedFloat( var arrowAlpha = AnimatedFloat( name = "arrowAlpha", minimumVisibleChange = SpringAnimation.MIN_VISIBLE_CHANGE_ALPHA, minimumValue = 0f, maximumValue = 1f ) val backgroundAlpha = AnimatedFloat( val backgroundAlpha = AnimatedFloat( name = "backgroundAlpha", minimumVisibleChange = SpringAnimation.MIN_VISIBLE_CHANGE_ALPHA, minimumValue = 0f, maximumValue = 1f ) private val allAnimatedFloat = setOf( private val allAnimatedFloat = setOf( arrowLength, arrowHeight, backgroundWidth, Loading @@ -140,22 +142,22 @@ class BackPanel( */ var verticalTranslation = AnimatedFloat("verticalTranslation") /** * Use for drawing debug info. Can only be set if [DEBUG]=true */ /** Use for drawing debug info. Can only be set if [DEBUG]=true */ var drawDebugInfo: ((canvas: Canvas) -> Unit)? = null set(value) { if (DEBUG) field = value } internal fun updateArrowPaint(arrowThickness: Float) { arrowPaint.strokeWidth = arrowThickness val isDeviceInNightTheme = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES val isDeviceInNightTheme = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES arrowPaint.color = Utils.getColorAttrDefaultColor(context, arrowPaint.color = Utils.getColorAttrDefaultColor( context, if (isDeviceInNightTheme) { com.android.internal.R.attr.materialColorOnSecondaryContainer } else { Loading @@ -163,7 +165,9 @@ class BackPanel( } ) arrowBackgroundPaint.color = Utils.getColorAttrDefaultColor(context, arrowBackgroundPaint.color = Utils.getColorAttrDefaultColor( context, if (isDeviceInNightTheme) { com.android.internal.R.attr.materialColorSecondaryContainer } else { Loading Loading @@ -207,14 +211,16 @@ class BackPanel( } init { val floatProp = object : FloatPropertyCompat<AnimatedFloat>(name) { val floatProp = object : FloatPropertyCompat<AnimatedFloat>(name) { override fun setValue(animatedFloat: AnimatedFloat, value: Float) { animatedFloat.pos = value } override fun getValue(animatedFloat: AnimatedFloat): Float = animatedFloat.pos } animation = SpringAnimation(this, floatProp).apply { animation = SpringAnimation(this, floatProp).apply { spring = SpringForce() this@AnimatedFloat.minimumValue?.let { setMinValue(it) } this@AnimatedFloat.maximumValue?.let { setMaxValue(it) } Loading @@ -233,7 +239,6 @@ class BackPanel( snapTo(restingPosition) } fun stretchTo( stretchAmount: Float, startingVelocity: Float? = null, Loading Loading @@ -373,8 +378,11 @@ class BackPanel( } fun popArrowAlpha(startingVelocity: Float, springForce: SpringForce? = null) { arrowAlpha.stretchTo(stretchAmount = 0f, startingVelocity = startingVelocity, springForce = springForce) arrowAlpha.stretchTo( stretchAmount = 0f, startingVelocity = startingVelocity, springForce = springForce ) } fun resetStretch() { Loading @@ -392,9 +400,7 @@ class BackPanel( backgroundFarCornerRadius.snapToRestingPosition() } /** * Updates resting arrow and background size not accounting for stretch */ /** Updates resting arrow and background size not accounting for stretch */ internal fun setRestingDimens( restingParams: EdgePanelParams.BackIndicatorDimens, animate: Boolean = true Loading @@ -410,10 +416,12 @@ class BackPanel( backgroundWidth.updateRestingPosition(restingParams.backgroundDimens.width, animate) backgroundHeight.updateRestingPosition(restingParams.backgroundDimens.height, animate) backgroundEdgeCornerRadius.updateRestingPosition( restingParams.backgroundDimens.edgeCornerRadius, animate restingParams.backgroundDimens.edgeCornerRadius, animate ) backgroundFarCornerRadius.updateRestingPosition( restingParams.backgroundDimens.farCornerRadius, animate restingParams.backgroundDimens.farCornerRadius, animate ) } Loading Loading @@ -459,26 +467,28 @@ class BackPanel( if (!isLeftPanel) canvas.scale(-1f, 1f, canvasWidth / 2.0f, 0f) canvas.translate( horizontalTranslation.pos, height * 0.5f + verticalTranslation.pos ) canvas.translate(horizontalTranslation.pos, height * 0.5f + verticalTranslation.pos) canvas.scale(scale.pos, scale.pos, scalePivotX, 0f) val arrowBackground = arrowBackgroundRect.apply { val arrowBackground = arrowBackgroundRect .apply { left = 0f top = -halfHeight right = backgroundWidth bottom = halfHeight }.toPathWithRoundCorners( } .toPathWithRoundCorners( topLeft = edgeCorner, bottomLeft = edgeCorner, topRight = farCorner, bottomRight = farCorner ) canvas.drawPath(arrowBackground, arrowBackgroundPaint.apply { alpha = (255 * backgroundAlpha.pos).toInt() }) canvas.drawPath( arrowBackground, arrowBackgroundPaint.apply { alpha = (255 * backgroundAlpha.pos).toInt() } ) val dx = arrowLength.pos val dy = arrowHeight.pos Loading @@ -500,8 +510,8 @@ class BackPanel( } val arrowPath = calculateArrowPath(dx = dx, dy = dy) val arrowPaint = arrowPaint .apply { alpha = (255 * min(arrowAlpha.pos, backgroundAlpha.pos)).toInt() } val arrowPaint = arrowPaint.apply { alpha = (255 * min(arrowAlpha.pos, backgroundAlpha.pos)).toInt() } canvas.drawPath(arrowPath, arrowPaint) canvas.restore() Loading @@ -523,12 +533,18 @@ class BackPanel( topRight: Float = 0f, bottomRight: Float = 0f, bottomLeft: Float = 0f ): Path = Path().apply { val corners = floatArrayOf( topLeft, topLeft, topRight, topRight, bottomRight, bottomRight, bottomLeft, bottomLeft ): Path = Path().apply { val corners = floatArrayOf( topLeft, topLeft, topRight, topRight, bottomRight, bottomRight, bottomLeft, bottomLeft ) addRoundRect(this@toPathWithRoundCorners, corners, Path.Direction.CW) } Loading
packages/SystemUI/src/com/android/systemui/navigationbar/gestural/BackPanelController.kt +8 −9 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ import android.view.Gravity import android.view.HapticFeedbackConstants import android.view.MotionEvent import android.view.VelocityTracker import android.view.View import android.view.ViewConfiguration import android.view.WindowManager import androidx.annotation.VisibleForTesting Loading Loading @@ -164,6 +163,7 @@ internal constructor( private val elapsedTimeSinceInactive get() = systemClock.uptimeMillis() - gestureInactiveTime private val elapsedTimeSinceEntry get() = systemClock.uptimeMillis() - gestureEntryTime Loading Loading @@ -612,6 +612,7 @@ internal constructor( } private var previousPreThresholdWidthInterpolator = params.entryWidthInterpolator private fun preThresholdWidthStretchAmount(progress: Float): Float { val interpolator = run { val isPastSlop = totalTouchDeltaInactive > viewConfiguration.scaledTouchSlop Loading Loading @@ -677,8 +678,7 @@ internal constructor( velocityTracker?.run { computeCurrentVelocity(PX_PER_SEC) xVelocity.takeIf { mView.isLeftPanel } ?: (xVelocity * -1) } ?: 0f } ?: 0f val isPastFlingVelocityThreshold = flingVelocity > viewConfiguration.scaledMinimumFlingVelocity return flingDistance > minFlingDistance && isPastFlingVelocityThreshold Loading Loading @@ -1028,8 +1028,7 @@ internal constructor( velocityTracker?.run { computeCurrentVelocity(PX_PER_MS) MathUtils.smoothStep(slowVelocityBound, fastVelocityBound, abs(xVelocity)) } ?: valueOnFastVelocity } ?: valueOnFastVelocity return MathUtils.lerp(valueOnFastVelocity, valueOnSlowVelocity, 1 - factor) } Loading
packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgePanelParams.kt +132 −86 Original line number Diff line number Diff line Loading @@ -45,57 +45,79 @@ data class EdgePanelParams(private var resources: Resources) { lateinit var entryIndicator: BackIndicatorDimens private set lateinit var activeIndicator: BackIndicatorDimens private set lateinit var cancelledIndicator: BackIndicatorDimens private set lateinit var flungIndicator: BackIndicatorDimens private set lateinit var committedIndicator: BackIndicatorDimens private set lateinit var preThresholdIndicator: BackIndicatorDimens private set lateinit var fullyStretchedIndicator: BackIndicatorDimens private set // navigation bar edge constants var arrowPaddingEnd: Int = 0 private set var arrowThickness: Float = 0f private set // The closest to y var minArrowYPosition: Int = 0 private set var fingerOffset: Int = 0 private set var staticTriggerThreshold: Float = 0f private set var reactivationTriggerThreshold: Float = 0f private set var deactivationTriggerThreshold: Float = 0f get() = -field private set lateinit var dynamicTriggerThresholdRange: ClosedRange<Float> private set var swipeProgressThreshold: Float = 0f private set lateinit var entryWidthInterpolator: Interpolator private set lateinit var entryWidthTowardsEdgeInterpolator: Interpolator private set lateinit var activeWidthInterpolator: Interpolator private set lateinit var arrowAngleInterpolator: Interpolator private set lateinit var horizontalTranslationInterpolator: Interpolator private set lateinit var verticalTranslationInterpolator: Interpolator private set lateinit var farCornerInterpolator: Interpolator private set lateinit var edgeCornerInterpolator: Interpolator private set lateinit var heightInterpolator: Interpolator private set Loading @@ -108,7 +130,10 @@ data class EdgePanelParams(private var resources: Resources) { } private fun getDimenFloat(id: Int): Float { return TypedValue().run { resources.getValue(id, this, true); float } return TypedValue().run { resources.getValue(id, this, true) float } } private fun getPx(id: Int): Int { Loading @@ -126,8 +151,7 @@ data class EdgePanelParams(private var resources: Resources) { getDimen(R.dimen.navigation_edge_action_reactivation_drag_threshold) deactivationTriggerThreshold = getDimen(R.dimen.navigation_edge_action_deactivation_drag_threshold) dynamicTriggerThresholdRange = reactivationTriggerThreshold..deactivationTriggerThreshold dynamicTriggerThresholdRange = reactivationTriggerThreshold..deactivationTriggerThreshold swipeProgressThreshold = getDimen(R.dimen.navigation_edge_action_progress_threshold) entryWidthInterpolator = PathInterpolator(.19f, 1.27f, .71f, .86f) Loading @@ -149,27 +173,31 @@ data class EdgePanelParams(private var resources: Resources) { val commonArrowDimensAlphaThreshold = .165f val commonArrowDimensAlphaFactor = 1.05f val commonArrowDimensAlphaSpring = Step( val commonArrowDimensAlphaSpring = Step( threshold = commonArrowDimensAlphaThreshold, factor = commonArrowDimensAlphaFactor, postThreshold = createSpring(180f, 0.9f), preThreshold = createSpring(2000f, 0.6f) ) val commonArrowDimensAlphaSpringInterpolator = Step( val commonArrowDimensAlphaSpringInterpolator = Step( threshold = commonArrowDimensAlphaThreshold, factor = commonArrowDimensAlphaFactor, postThreshold = 1f, preThreshold = 0f ) entryIndicator = BackIndicatorDimens( entryIndicator = BackIndicatorDimens( 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 = createSpring(800f, 0.76f), verticalTranslationSpring = createSpring(30000f, 1f), scaleSpring = createSpring(120f, 0.8f), arrowDimens = ArrowDimens( arrowDimens = ArrowDimens( length = getDimen(R.dimen.navigation_edge_entry_arrow_length), height = getDimen(R.dimen.navigation_edge_entry_arrow_height), alpha = 0f, Loading @@ -178,7 +206,8 @@ data class EdgePanelParams(private var resources: Resources) { alphaSpring = commonArrowDimensAlphaSpring, alphaInterpolator = commonArrowDimensAlphaSpringInterpolator ), backgroundDimens = BackgroundDimens( backgroundDimens = BackgroundDimens( alpha = 1f, width = getDimen(R.dimen.navigation_edge_entry_background_width), height = getDimen(R.dimen.navigation_edge_entry_background_height), Loading @@ -191,13 +220,15 @@ data class EdgePanelParams(private var resources: Resources) { ) ) activeIndicator = BackIndicatorDimens( activeIndicator = BackIndicatorDimens( horizontalTranslation = getDimen(R.dimen.navigation_edge_active_margin), scale = getDimenFloat(R.dimen.navigation_edge_active_scale), horizontalTranslationSpring = createSpring(1000f, 0.8f), scaleSpring = createSpring(325f, 0.55f), scalePivotX = getDimen(R.dimen.navigation_edge_active_background_width), arrowDimens = ArrowDimens( arrowDimens = ArrowDimens( length = getDimen(R.dimen.navigation_edge_active_arrow_length), height = getDimen(R.dimen.navigation_edge_active_arrow_height), alpha = 1f, Loading @@ -206,7 +237,8 @@ data class EdgePanelParams(private var resources: Resources) { alphaSpring = commonArrowDimensAlphaSpring, alphaInterpolator = commonArrowDimensAlphaSpringInterpolator ), backgroundDimens = BackgroundDimens( backgroundDimens = BackgroundDimens( alpha = 1f, width = getDimen(R.dimen.navigation_edge_active_background_width), height = getDimen(R.dimen.navigation_edge_active_background_height), Loading @@ -219,13 +251,15 @@ data class EdgePanelParams(private var resources: Resources) { ) ) preThresholdIndicator = BackIndicatorDimens( preThresholdIndicator = BackIndicatorDimens( horizontalTranslation = getDimen(R.dimen.navigation_edge_pre_threshold_margin), scale = getDimenFloat(R.dimen.navigation_edge_pre_threshold_scale), scalePivotX = getDimen(R.dimen.navigation_edge_pre_threshold_background_width), scaleSpring = createSpring(120f, 0.8f), horizontalTranslationSpring = createSpring(6000f, 1f), arrowDimens = ArrowDimens( arrowDimens = ArrowDimens( length = getDimen(R.dimen.navigation_edge_pre_threshold_arrow_length), height = getDimen(R.dimen.navigation_edge_pre_threshold_arrow_height), alpha = 1f, Loading @@ -234,7 +268,8 @@ data class EdgePanelParams(private var resources: Resources) { alphaSpring = commonArrowDimensAlphaSpring, alphaInterpolator = commonArrowDimensAlphaSpringInterpolator ), backgroundDimens = BackgroundDimens( backgroundDimens = BackgroundDimens( alpha = 1f, width = getDimen(R.dimen.navigation_edge_pre_threshold_background_width), height = getDimen(R.dimen.navigation_edge_pre_threshold_background_height), Loading @@ -249,16 +284,19 @@ data class EdgePanelParams(private var resources: Resources) { ) ) committedIndicator = activeIndicator.copy( committedIndicator = activeIndicator.copy( horizontalTranslation = null, scalePivotX = null, arrowDimens = activeIndicator.arrowDimens.copy( arrowDimens = activeIndicator.arrowDimens.copy( lengthSpring = activeCommittedArrowLengthSpring, heightSpring = activeCommittedArrowHeightSpring, length = null, height = null, ), backgroundDimens = activeIndicator.backgroundDimens.copy( backgroundDimens = activeIndicator.backgroundDimens.copy( alpha = 0f, // explicitly set to null to preserve previous width upon state change width = null, Loading @@ -272,14 +310,17 @@ data class EdgePanelParams(private var resources: Resources) { scaleSpring = createSpring(5700f, 1f), ) flungIndicator = committedIndicator.copy( arrowDimens = committedIndicator.arrowDimens.copy( flungIndicator = committedIndicator.copy( arrowDimens = committedIndicator.arrowDimens.copy( lengthSpring = createSpring(850f, 0.46f), heightSpring = createSpring(850f, 0.46f), length = activeIndicator.arrowDimens.length, height = activeIndicator.arrowDimens.height ), backgroundDimens = committedIndicator.backgroundDimens.copy( backgroundDimens = committedIndicator.backgroundDimens.copy( widthSpring = flungCommittedWidthSpring, heightSpring = flungCommittedHeightSpring, edgeCornerRadiusSpring = flungCommittedEdgeCornerSpring, Loading @@ -287,21 +328,25 @@ data class EdgePanelParams(private var resources: Resources) { ) ) cancelledIndicator = entryIndicator.copy( backgroundDimens = entryIndicator.backgroundDimens.copy( cancelledIndicator = entryIndicator.copy( backgroundDimens = entryIndicator.backgroundDimens.copy( width = 0f, alpha = 0f, alphaSpring = createSpring(450f, 1f) ) ) fullyStretchedIndicator = BackIndicatorDimens( fullyStretchedIndicator = BackIndicatorDimens( horizontalTranslation = getDimen(R.dimen.navigation_edge_stretch_margin), scale = getDimenFloat(R.dimen.navigation_edge_stretch_scale), horizontalTranslationSpring = null, verticalTranslationSpring = null, scaleSpring = null, arrowDimens = ArrowDimens( arrowDimens = ArrowDimens( length = getDimen(R.dimen.navigation_edge_stretched_arrow_length), height = getDimen(R.dimen.navigation_edge_stretched_arrow_height), alpha = 1f, Loading @@ -309,7 +354,8 @@ data class EdgePanelParams(private var resources: Resources) { heightSpring = null, lengthSpring = null, ), backgroundDimens = BackgroundDimens( backgroundDimens = BackgroundDimens( alpha = 1f, width = getDimen(R.dimen.navigation_edge_stretch_background_width), height = getDimen(R.dimen.navigation_edge_stretch_background_height), Loading
packages/SystemUI/tests/src/com/android/systemui/navigationbar/gestural/BackPanelControllerTest.kt +1 −0 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ class BackPanelControllerTest : SysuiTestCase() { companion object { private const val START_X: Float = 0f } private val kosmos = testKosmos() private lateinit var mBackPanelController: BackPanelController private lateinit var systemClock: FakeSystemClock Loading