Loading packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt +16 −4 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -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 = Loading Loading @@ -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 } } } packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt +112 −8 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 = Loading @@ -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) } Loading @@ -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() } } Loading Loading @@ -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) Loading @@ -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 Loading Loading
packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt +16 −4 Original line number Diff line number Diff line Loading @@ -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) Loading Loading @@ -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 = Loading Loading @@ -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 } } }
packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt +112 −8 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 = Loading @@ -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) } Loading @@ -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() } } Loading Loading @@ -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) Loading @@ -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 Loading