diff options
2 files changed, 128 insertions, 12 deletions
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt index a4782acaed9b..ee21ea6ee126 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt @@ -55,10 +55,7 @@ class FlexClockFaceController( override val view: View get() = layerController.view - override val config = - ClockFaceConfig( - hasCustomPositionUpdatedAnimation = false // TODO(b/364673982) - ) + override val config = ClockFaceConfig(hasCustomPositionUpdatedAnimation = true) override var theme = ThemeConfig(true, assets.seedColor) @@ -96,6 +93,19 @@ class FlexClockFaceController( layerController.view.layoutParams = lp } + /** See documentation at [FlexClockView.offsetGlyphsForStepClockAnimation]. */ + private fun offsetGlyphsForStepClockAnimation( + clockStartLeft: Int, + direction: Int, + fraction: Float + ) { + (view as? FlexClockView)?.offsetGlyphsForStepClockAnimation( + clockStartLeft, + direction, + fraction, + ) + } + override val layout: ClockFaceLayout = DefaultClockFaceLayout(view).apply { views[0].id = @@ -248,10 +258,12 @@ class FlexClockFaceController( override fun onPositionUpdated(fromLeft: Int, direction: Int, fraction: Float) { layerController.animations.onPositionUpdated(fromLeft, direction, fraction) + if (isLargeClock) offsetGlyphsForStepClockAnimation(fromLeft, direction, fraction) } override fun onPositionUpdated(distance: Float, fraction: Float) { layerController.animations.onPositionUpdated(distance, fraction) + // TODO(b/378128811) port stepping animation } } } diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt index d86c0d664590..593eba9d05cc 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt @@ -19,6 +19,7 @@ package com.android.systemui.shared.clocks.view import android.content.Context import android.graphics.Canvas import android.graphics.Point +import android.util.MathUtils.constrainedMap import android.view.View import android.view.ViewGroup import android.widget.RelativeLayout @@ -50,6 +51,8 @@ class FlexClockView(context: Context, val assets: AssetLoader, messageBuffer: Me ) } + private val digitOffsets = mutableMapOf<Int, Float>() + override fun addView(child: View?) { super.addView(child) (child as SimpleDigitalClockTextView).digitTranslateAnimator = @@ -76,7 +79,7 @@ class FlexClockView(context: Context, val assets: AssetLoader, messageBuffer: Me digitLeftTopMap[R.id.HOUR_SECOND_DIGIT] = Point(maxSingleDigitSize.x, 0) digitLeftTopMap[R.id.MINUTE_FIRST_DIGIT] = Point(0, maxSingleDigitSize.y) digitLeftTopMap[R.id.MINUTE_SECOND_DIGIT] = Point(maxSingleDigitSize) - digitLeftTopMap.forEach { _, point -> + digitLeftTopMap.forEach { (_, point) -> point.x += abs(aodTranslate.x) point.y += abs(aodTranslate.y) } @@ -89,11 +92,17 @@ class FlexClockView(context: Context, val assets: AssetLoader, messageBuffer: Me override fun onDraw(canvas: Canvas) { super.onDraw(canvas) - digitalClockTextViewMap.forEach { (id, _) -> - val textView = digitalClockTextViewMap[id]!! - canvas.translate(digitLeftTopMap[id]!!.x.toFloat(), digitLeftTopMap[id]!!.y.toFloat()) + digitalClockTextViewMap.forEach { (id, textView) -> + // save canvas location in anticipation of restoration later + canvas.save() + val xTranslateAmount = + digitOffsets.getOrDefault(id, 0f) + digitLeftTopMap[id]!!.x.toFloat() + // move canvas to location that the textView would like + canvas.translate(xTranslateAmount, digitLeftTopMap[id]!!.y.toFloat()) + // draw the textView at the location of the canvas above textView.draw(canvas) - canvas.translate(-digitLeftTopMap[id]!!.x.toFloat(), -digitLeftTopMap[id]!!.y.toFloat()) + // reset the canvas location back to 0 without drawing + canvas.restore() } } @@ -157,10 +166,108 @@ class FlexClockView(context: Context, val assets: AssetLoader, messageBuffer: Me } } + /** + * Offsets the textViews of the clock for the step clock animation. + * + * The animation makes the textViews of the clock move at different speeds, when the clock is + * moving horizontally. + * + * @param clockStartLeft the [getLeft] position of the clock, before it started moving. + * @param clockMoveDirection the direction in which it is moving. A positive number means right, + * and negative means left. + * @param moveFraction fraction of the clock movement. 0 means it is at the beginning, and 1 + * means it finished moving. + */ + fun offsetGlyphsForStepClockAnimation( + clockStartLeft: Int, + clockMoveDirection: Int, + moveFraction: Float, + ) { + val isMovingToCenter = if (isLayoutRtl) clockMoveDirection < 0 else clockMoveDirection > 0 + // The sign of moveAmountDeltaForDigit is already set here + // we can interpret (left - clockStartLeft) as (destinationPosition - originPosition) + // so we no longer need to multiply direct sign to moveAmountDeltaForDigit + val currentMoveAmount = left - clockStartLeft + for (i in 0 until NUM_DIGITS) { + val mapIndexToId = + when (i) { + 0 -> R.id.HOUR_FIRST_DIGIT + 1 -> R.id.HOUR_SECOND_DIGIT + 2 -> R.id.MINUTE_FIRST_DIGIT + 3 -> R.id.MINUTE_SECOND_DIGIT + else -> -1 + } + val digitFraction = + getDigitFraction( + digit = i, + isMovingToCenter = isMovingToCenter, + fraction = moveFraction, + ) + // left here is the final left position after the animation is done + val moveAmountForDigit = currentMoveAmount * digitFraction + var moveAmountDeltaForDigit = moveAmountForDigit - currentMoveAmount + if (isMovingToCenter && moveAmountForDigit < 0) moveAmountDeltaForDigit *= -1 + digitOffsets[mapIndexToId] = moveAmountDeltaForDigit + invalidate() + } + } + + private val moveToCenterDelays: List<Int> + get() = if (isLayoutRtl) MOVE_LEFT_DELAYS else MOVE_RIGHT_DELAYS + + private val moveToSideDelays: List<Int> + get() = if (isLayoutRtl) MOVE_RIGHT_DELAYS else MOVE_LEFT_DELAYS + + private fun getDigitFraction(digit: Int, isMovingToCenter: Boolean, fraction: Float): Float { + // The delay for the digit, in terms of fraction. + // (i.e. the digit should not move during 0.0 - 0.1). + val delays = if (isMovingToCenter) moveToCenterDelays else moveToSideDelays + val digitInitialDelay = delays[digit] * MOVE_DIGIT_STEP + return MOVE_INTERPOLATOR.getInterpolation( + constrainedMap( + /* rangeMin= */ 0.0f, + /* rangeMax= */ 1.0f, + /* valueMin= */ digitInitialDelay, + /* valueMax= */ digitInitialDelay + AVAILABLE_ANIMATION_TIME, + /* value= */ fraction, + ) + ) + } + companion object { val AOD_TRANSITION_DURATION = 750L val CHARGING_TRANSITION_DURATION = 300L + // Calculate the positions of all of the digits... + // Offset each digit by, say, 0.1 + // This means that each digit needs to move over a slice of "fractions", i.e. digit 0 should + // move from 0.0 - 0.7, digit 1 from 0.1 - 0.8, digit 2 from 0.2 - 0.9, and digit 3 + // from 0.3 - 1.0. + private const val NUM_DIGITS = 4 + + // Delays. Each digit's animation should have a slight delay, so we get a nice + // "stepping" effect. When moving right, the second digit of the hour should move first. + // When moving left, the first digit of the hour should move first. The lists encode + // the delay for each digit (hour[0], hour[1], minute[0], minute[1]), to be multiplied + // by delayMultiplier. + private val MOVE_LEFT_DELAYS = listOf(0, 1, 2, 3) + private val MOVE_RIGHT_DELAYS = listOf(1, 0, 3, 2) + + // How much delay to apply to each subsequent digit. This is measured in terms of "fraction" + // (i.e. a value of 0.1 would cause a digit to wait until fraction had hit 0.1, or 0.2 etc + // before moving). + // + // The current specs dictate that each digit should have a 33ms gap between them. The + // overall time is 1s right now. + private const val MOVE_DIGIT_STEP = 0.033f + + // Constants for the animation + private val MOVE_INTERPOLATOR = Interpolators.EMPHASIZED + + // Total available transition time for each digit, taking into account the step. If step is + // 0.1, then digit 0 would animate over 0.0 - 0.7, making availableTime 0.7. + private const val AVAILABLE_ANIMATION_TIME = 1.0f - MOVE_DIGIT_STEP * (NUM_DIGITS - 1) + // Use the sign of targetTranslation to control the direction of digit translation fun updateDirectionalTargetTranslate(id: Int, targetTranslation: Point): Point { val outPoint = Point(targetTranslation) @@ -169,17 +276,14 @@ class FlexClockView(context: Context, val assets: AssetLoader, messageBuffer: Me outPoint.x *= -1 outPoint.y *= -1 } - R.id.HOUR_SECOND_DIGIT -> { outPoint.x *= 1 outPoint.y *= -1 } - R.id.MINUTE_FIRST_DIGIT -> { outPoint.x *= -1 outPoint.y *= 1 } - R.id.MINUTE_SECOND_DIGIT -> { outPoint.x *= 1 outPoint.y *= 1 |