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 |