Add large screen clock motion - method 2.
When the clock moves on a large screen (e.g. when locking/unlocking the device), this adds a subtle offset for each digit of the clock. This hooks a new transition in to the existing clock move transition, which just forwards progress through to the actual clock. This also adds a feature flag (210) to enable/disable this, since it needs a little more polish yet. As above, this needs more polish (tweaking the time and/or easing), but this at least gets something moving to start with :). Bug: 199051139 Test: Manually verified. Change-Id: Icec0bcfdb431d24b9405c5dfe8993016f687cac5
This commit is contained in:
@@ -82,6 +82,14 @@ class TextAnimator(layout: Layout, private val invalidateCallback: () -> Unit) {
|
||||
/** Mutable Y coordinate of the glyph position relative from the baseline. */
|
||||
var y: Float = 0f
|
||||
|
||||
/**
|
||||
* The current line of text being drawn, in a multi-line TextView.
|
||||
*/
|
||||
var lineNo: Int = 0
|
||||
|
||||
/**
|
||||
* Mutable text size of the glyph in pixels.
|
||||
*/
|
||||
/** Mutable text size of the glyph in pixels. */
|
||||
var textSize: Float = 0f
|
||||
|
||||
|
||||
@@ -231,7 +231,9 @@ class TextInterpolator(layout: Layout) {
|
||||
val origin = layout.getDrawOrigin(lineNo)
|
||||
canvas.translate(origin, layout.getLineBaseline(lineNo).toFloat())
|
||||
|
||||
run.fontRuns.forEach { fontRun -> drawFontRun(canvas, run, fontRun, tmpPaint) }
|
||||
run.fontRuns.forEach { fontRun ->
|
||||
drawFontRun(canvas, run, fontRun, lineNo, tmpPaint)
|
||||
}
|
||||
} finally {
|
||||
canvas.restore()
|
||||
}
|
||||
@@ -341,7 +343,7 @@ class TextInterpolator(layout: Layout) {
|
||||
var glyphFilter: GlyphCallback? = null
|
||||
|
||||
// Draws single font run.
|
||||
private fun drawFontRun(c: Canvas, line: Run, run: FontRun, paint: Paint) {
|
||||
private fun drawFontRun(c: Canvas, line: Run, run: FontRun, lineNo: Int, paint: Paint) {
|
||||
var arrayIndex = 0
|
||||
val font = fontInterpolator.lerp(run.baseFont, run.targetFont, progress)
|
||||
|
||||
@@ -360,11 +362,13 @@ class TextInterpolator(layout: Layout) {
|
||||
tmpGlyph.font = font
|
||||
tmpGlyph.runStart = run.start
|
||||
tmpGlyph.runLength = run.end - run.start
|
||||
tmpGlyph.lineNo = lineNo
|
||||
|
||||
tmpPaintForGlyph.set(paint)
|
||||
var prevStart = run.start
|
||||
|
||||
for (i in run.start until run.end) {
|
||||
tmpGlyph.glyphIndex = i
|
||||
tmpGlyph.glyphId = line.glyphIds[i]
|
||||
tmpGlyph.x = MathUtils.lerp(line.baseX[i], line.targetX[i], progress)
|
||||
tmpGlyph.y = MathUtils.lerp(line.baseY[i], line.targetY[i], progress)
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
package com.android.systemui.plugins
|
||||
|
||||
import android.content.res.Resources
|
||||
import android.graphics.Rect
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.view.View
|
||||
import com.android.systemui.plugins.annotations.ProvidesInterface
|
||||
@@ -114,6 +115,17 @@ interface ClockAnimations {
|
||||
|
||||
/** Runs the battery animation (if any). */
|
||||
fun charge() { }
|
||||
|
||||
/** Move the clock, for example, if the notification tray appears in split-shade mode. */
|
||||
fun onPositionUpdated(fromRect: Rect, toRect: Rect, fraction: Float) { }
|
||||
|
||||
/**
|
||||
* Whether this clock has a custom position update animation. If true, the keyguard will call
|
||||
* `onPositionUpdated` to notify the clock of a position update animation. If false, a default
|
||||
* animation will be used (e.g. a simple translation).
|
||||
*/
|
||||
val hasCustomPositionUpdatedAnimation
|
||||
get() = false
|
||||
}
|
||||
|
||||
/** Events that have specific data about the related face */
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="@dimen/keyguard_large_clock_top_margin"
|
||||
android:clipChildren="false"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- Not quite optimal but needed to translate these items as a group. The
|
||||
|
||||
@@ -20,16 +20,15 @@ import android.annotation.ColorInt
|
||||
import android.annotation.FloatRange
|
||||
import android.annotation.IntRange
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.compat.ChangeIdStateCache.invalidate
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Rect
|
||||
import android.text.Layout
|
||||
import android.text.TextUtils
|
||||
import android.text.format.DateFormat
|
||||
import android.util.AttributeSet
|
||||
import android.util.MathUtils
|
||||
import android.widget.TextView
|
||||
import com.android.internal.R.attr.contentDescription
|
||||
import com.android.internal.R.attr.format
|
||||
import com.android.internal.annotations.VisibleForTesting
|
||||
import com.android.systemui.animation.GlyphCallback
|
||||
import com.android.systemui.animation.Interpolators
|
||||
@@ -39,6 +38,8 @@ import java.io.PrintWriter
|
||||
import java.util.Calendar
|
||||
import java.util.Locale
|
||||
import java.util.TimeZone
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
* Displays the time with the hour positioned above the minutes. (ie: 09 above 30 is 9:30)
|
||||
@@ -311,7 +312,24 @@ class AnimatableClockView @JvmOverloads constructor(
|
||||
)
|
||||
}
|
||||
|
||||
private val glyphFilter: GlyphCallback? = null // Add text animation tweak here.
|
||||
// The offset of each glyph from where it should be.
|
||||
private var glyphOffsets = mutableListOf(0.0f, 0.0f, 0.0f, 0.0f)
|
||||
|
||||
private var lastSeenAnimationProgress = 1.0f
|
||||
|
||||
// If the animation is being reversed, the target offset for each glyph for the "stop".
|
||||
private var animationCancelStartPosition = mutableListOf(0.0f, 0.0f, 0.0f, 0.0f)
|
||||
private var animationCancelStopPosition = 0.0f
|
||||
|
||||
// Whether the currently playing animation needed a stop (and thus, is shortened).
|
||||
private var currentAnimationNeededStop = false
|
||||
|
||||
private val glyphFilter: GlyphCallback = { positionedGlyph, _ ->
|
||||
val offset = positionedGlyph.lineNo * DIGITS_PER_LINE + positionedGlyph.glyphIndex
|
||||
if (offset < glyphOffsets.size) {
|
||||
positionedGlyph.x += glyphOffsets[offset]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set text style with an optional animation.
|
||||
@@ -421,6 +439,124 @@ class AnimatableClockView @JvmOverloads constructor(
|
||||
pw.println(" time=$time")
|
||||
}
|
||||
|
||||
fun moveForSplitShade(fromRect: Rect, toRect: Rect, fraction: Float) {
|
||||
// Do we need to cancel an in-flight animation?
|
||||
// Need to also check against 0.0f here; we can sometimes get two calls with fraction == 0,
|
||||
// which trips up the check otherwise.
|
||||
if (lastSeenAnimationProgress != 1.0f &&
|
||||
lastSeenAnimationProgress != 0.0f &&
|
||||
fraction == 0.0f) {
|
||||
// New animation, but need to stop the old one. Figure out where each glyph currently
|
||||
// is in relation to the box position. After that, use the leading digit's current
|
||||
// position as the stop target.
|
||||
currentAnimationNeededStop = true
|
||||
|
||||
// We assume that the current glyph offsets would be relative to the "from" position.
|
||||
val moveAmount = toRect.left - fromRect.left
|
||||
|
||||
// Remap the current glyph offsets to be relative to the new "end" position, and figure
|
||||
// out the start/end positions for the stop animation.
|
||||
for (i in 0 until NUM_DIGITS) {
|
||||
glyphOffsets[i] = -moveAmount + glyphOffsets[i]
|
||||
animationCancelStartPosition[i] = glyphOffsets[i]
|
||||
}
|
||||
|
||||
// Use the leading digit's offset as the stop position.
|
||||
if (toRect.left > fromRect.left) {
|
||||
// It _was_ moving left
|
||||
animationCancelStopPosition = glyphOffsets[0]
|
||||
} else {
|
||||
// It was moving right
|
||||
animationCancelStopPosition = glyphOffsets[1]
|
||||
}
|
||||
}
|
||||
|
||||
// Is there a cancellation in progress?
|
||||
if (currentAnimationNeededStop && fraction < ANIMATION_CANCELLATION_TIME) {
|
||||
val animationStopProgress = MathUtils.constrainedMap(
|
||||
0.0f, 1.0f, 0.0f, ANIMATION_CANCELLATION_TIME, fraction
|
||||
)
|
||||
|
||||
// One of the digits has already stopped.
|
||||
val animationStopStep = 1.0f / (NUM_DIGITS - 1)
|
||||
|
||||
for (i in 0 until NUM_DIGITS) {
|
||||
val stopAmount = if (toRect.left > fromRect.left) {
|
||||
// It was moving left (before flipping)
|
||||
MOVE_LEFT_DELAYS[i] * animationStopStep
|
||||
} else {
|
||||
// It was moving right (before flipping)
|
||||
MOVE_RIGHT_DELAYS[i] * animationStopStep
|
||||
}
|
||||
|
||||
// Leading digit stops immediately.
|
||||
if (stopAmount == 0.0f) {
|
||||
glyphOffsets[i] = animationCancelStopPosition
|
||||
} else {
|
||||
val actualStopAmount = MathUtils.constrainedMap(
|
||||
0.0f, 1.0f, 0.0f, stopAmount, animationStopProgress
|
||||
)
|
||||
val easedProgress = MOVE_INTERPOLATOR.getInterpolation(actualStopAmount)
|
||||
val glyphMoveAmount =
|
||||
animationCancelStopPosition - animationCancelStartPosition[i]
|
||||
glyphOffsets[i] =
|
||||
animationCancelStartPosition[i] + glyphMoveAmount * easedProgress
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Normal part of the animation.
|
||||
// Do we need to remap the animation progress to take account of the cancellation?
|
||||
val actualFraction = if (currentAnimationNeededStop) {
|
||||
MathUtils.constrainedMap(
|
||||
0.0f, 1.0f, ANIMATION_CANCELLATION_TIME, 1.0f, fraction
|
||||
)
|
||||
} else {
|
||||
fraction
|
||||
}
|
||||
|
||||
val digitFractions = (0 until NUM_DIGITS).map {
|
||||
// The delay for each digit, in terms of fraction (i.e. the digit should not move
|
||||
// during 0.0 - 0.1).
|
||||
val initialDelay = if (toRect.left > fromRect.left) {
|
||||
MOVE_RIGHT_DELAYS[it] * MOVE_DIGIT_STEP
|
||||
} else {
|
||||
MOVE_LEFT_DELAYS[it] * MOVE_DIGIT_STEP
|
||||
}
|
||||
|
||||
val f = MathUtils.constrainedMap(
|
||||
0.0f, 1.0f,
|
||||
initialDelay, initialDelay + AVAILABLE_ANIMATION_TIME,
|
||||
actualFraction
|
||||
)
|
||||
MOVE_INTERPOLATOR.getInterpolation(max(min(f, 1.0f), 0.0f))
|
||||
}
|
||||
|
||||
// Was there an animation halt?
|
||||
val moveAmount = if (currentAnimationNeededStop) {
|
||||
// Only need to animate over the remaining space if the animation was aborted.
|
||||
-animationCancelStopPosition
|
||||
} else {
|
||||
toRect.left.toFloat() - fromRect.left.toFloat()
|
||||
}
|
||||
|
||||
for (i in 0 until NUM_DIGITS) {
|
||||
glyphOffsets[i] = -moveAmount + (moveAmount * digitFractions[i])
|
||||
}
|
||||
}
|
||||
|
||||
invalidate()
|
||||
|
||||
if (fraction == 1.0f) {
|
||||
// Reset
|
||||
currentAnimationNeededStop = false
|
||||
}
|
||||
|
||||
lastSeenAnimationProgress = fraction
|
||||
|
||||
// Ensure that the actual clock container is always in the "end" position.
|
||||
this.setLeftTopRightBottom(toRect.left, toRect.top, toRect.right, toRect.bottom)
|
||||
}
|
||||
|
||||
// DateFormat.getBestDateTimePattern is extremely expensive, and refresh is called often.
|
||||
// This is an optimization to ensure we only recompute the patterns when the inputs change.
|
||||
private object Patterns {
|
||||
@@ -458,5 +594,36 @@ class AnimatableClockView @JvmOverloads constructor(
|
||||
private const val APPEAR_ANIM_DURATION: Long = 350
|
||||
private const val CHARGE_ANIM_DURATION_PHASE_0: Long = 500
|
||||
private const val CHARGE_ANIM_DURATION_PHASE_1: Long = 1000
|
||||
|
||||
// Constants for the animation
|
||||
private val MOVE_INTERPOLATOR = Interpolators.STANDARD
|
||||
|
||||
// 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
|
||||
private const val DIGITS_PER_LINE = 2
|
||||
|
||||
// How much of "fraction" to spend on canceling the animation, if needed
|
||||
private const val ANIMATION_CANCELLATION_TIME = 0.4f
|
||||
|
||||
// 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).
|
||||
private const val MOVE_DIGIT_STEP = 0.1f
|
||||
|
||||
// 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 val AVAILABLE_ANIMATION_TIME = 1.0f - MOVE_DIGIT_STEP * (NUM_DIGITS - 1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ package com.android.systemui.shared.clocks
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import android.graphics.Color
|
||||
import android.graphics.Rect
|
||||
import android.icu.text.NumberFormat
|
||||
import android.util.TypedValue
|
||||
import android.view.LayoutInflater
|
||||
@@ -130,6 +131,10 @@ class DefaultClockController(
|
||||
lp.topMargin = (-0.5f * view.bottom).toInt()
|
||||
view.setLayoutParams(lp)
|
||||
}
|
||||
|
||||
fun moveForSplitShade(fromRect: Rect, toRect: Rect, fraction: Float) {
|
||||
view.moveForSplitShade(fromRect, toRect, fraction)
|
||||
}
|
||||
}
|
||||
|
||||
inner class DefaultClockEvents : ClockEvents {
|
||||
@@ -209,6 +214,13 @@ class DefaultClockController(
|
||||
clocks.forEach { it.animateDoze(dozeState.isActive, !hasJumped) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPositionUpdated(fromRect: Rect, toRect: Rect, fraction: Float) {
|
||||
largeClock.moveForSplitShade(fromRect, toRect, fraction)
|
||||
}
|
||||
|
||||
override val hasCustomPositionUpdatedAnimation: Boolean
|
||||
get() = true
|
||||
}
|
||||
|
||||
private class AnimationState(
|
||||
|
||||
@@ -40,6 +40,7 @@ import com.android.systemui.dump.DumpManager;
|
||||
import com.android.systemui.flags.FeatureFlags;
|
||||
import com.android.systemui.flags.Flags;
|
||||
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
|
||||
import com.android.systemui.plugins.ClockAnimations;
|
||||
import com.android.systemui.plugins.ClockController;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.shared.clocks.ClockRegistry;
|
||||
@@ -404,5 +405,9 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
|
||||
clock.dump(pw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets the animations for the current clock. */
|
||||
public ClockAnimations getClockAnimations() {
|
||||
return getClock().getAnimations();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.graphics.Rect;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.keyguard.KeyguardClockSwitch.ClockSize;
|
||||
import com.android.systemui.plugins.ClockAnimations;
|
||||
import com.android.systemui.statusbar.notification.AnimatableProperty;
|
||||
import com.android.systemui.statusbar.notification.PropertyAnimator;
|
||||
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
|
||||
@@ -232,4 +233,9 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
|
||||
mView.setClipBounds(null);
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets the animations for the current clock. */
|
||||
public ClockAnimations getClockAnimations() {
|
||||
return mKeyguardClockSwitchController.getClockAnimations();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,6 +129,12 @@ public class Flags {
|
||||
*/
|
||||
public static final ReleasedFlag USER_CONTROLLER_USES_INTERACTOR = new ReleasedFlag(211);
|
||||
|
||||
/**
|
||||
* Whether the clock on a wide lock screen should use the new "stepping" animation for moving
|
||||
* the digits when the clock moves.
|
||||
*/
|
||||
public static final UnreleasedFlag STEP_CLOCK_ANIMATION = new UnreleasedFlag(211);
|
||||
|
||||
/***************************************/
|
||||
// 300 - power menu
|
||||
public static final ReleasedFlag POWER_MENU_LITE =
|
||||
|
||||
@@ -79,7 +79,10 @@ import android.os.UserManager;
|
||||
import android.os.VibrationEffect;
|
||||
import android.provider.Settings;
|
||||
import android.transition.ChangeBounds;
|
||||
import android.transition.Transition;
|
||||
import android.transition.TransitionManager;
|
||||
import android.transition.TransitionSet;
|
||||
import android.transition.TransitionValues;
|
||||
import android.util.IndentingPrintWriter;
|
||||
import android.util.Log;
|
||||
import android.util.MathUtils;
|
||||
@@ -1664,9 +1667,40 @@ public final class NotificationPanelViewController {
|
||||
// horizontally properly.
|
||||
transition.excludeTarget(R.id.status_view_media_container, true);
|
||||
}
|
||||
|
||||
transition.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
|
||||
transition.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
|
||||
TransitionManager.beginDelayedTransition(mNotificationContainerParent, transition);
|
||||
|
||||
boolean customClockAnimation =
|
||||
mKeyguardStatusViewController
|
||||
.getClockAnimations()
|
||||
.getHasCustomPositionUpdatedAnimation();
|
||||
|
||||
if (mFeatureFlags.isEnabled(Flags.STEP_CLOCK_ANIMATION) && customClockAnimation) {
|
||||
// Find the clock, so we can exclude it from this transition.
|
||||
FrameLayout clockContainerView =
|
||||
mView.findViewById(R.id.lockscreen_clock_view_large);
|
||||
View clockView = clockContainerView.getChildAt(0);
|
||||
|
||||
transition.excludeTarget(clockView, /* exclude= */ true);
|
||||
|
||||
TransitionSet set = new TransitionSet();
|
||||
set.addTransition(transition);
|
||||
|
||||
SplitShadeTransitionAdapter adapter =
|
||||
new SplitShadeTransitionAdapter(mKeyguardStatusViewController);
|
||||
|
||||
// Use linear here, so the actual clock can pick its own interpolator.
|
||||
adapter.setInterpolator(Interpolators.LINEAR);
|
||||
adapter.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
|
||||
adapter.addTarget(clockView);
|
||||
set.addTransition(adapter);
|
||||
|
||||
TransitionManager.beginDelayedTransition(mNotificationContainerParent, set);
|
||||
} else {
|
||||
TransitionManager.beginDelayedTransition(
|
||||
mNotificationContainerParent, transition);
|
||||
}
|
||||
}
|
||||
|
||||
constraintSet.applyTo(mNotificationContainerParent);
|
||||
@@ -6238,4 +6272,54 @@ public final class NotificationPanelViewController {
|
||||
loadDimens();
|
||||
}
|
||||
}
|
||||
|
||||
static class SplitShadeTransitionAdapter extends Transition {
|
||||
private static final String PROP_BOUNDS = "splitShadeTransitionAdapter:bounds";
|
||||
private static final String[] TRANSITION_PROPERTIES = { PROP_BOUNDS };
|
||||
|
||||
private final KeyguardStatusViewController mController;
|
||||
|
||||
SplitShadeTransitionAdapter(KeyguardStatusViewController controller) {
|
||||
mController = controller;
|
||||
}
|
||||
|
||||
private void captureValues(TransitionValues transitionValues) {
|
||||
Rect boundsRect = new Rect();
|
||||
boundsRect.left = transitionValues.view.getLeft();
|
||||
boundsRect.top = transitionValues.view.getTop();
|
||||
boundsRect.right = transitionValues.view.getRight();
|
||||
boundsRect.bottom = transitionValues.view.getBottom();
|
||||
transitionValues.values.put(PROP_BOUNDS, boundsRect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void captureEndValues(TransitionValues transitionValues) {
|
||||
captureValues(transitionValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void captureStartValues(TransitionValues transitionValues) {
|
||||
captureValues(transitionValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
|
||||
TransitionValues endValues) {
|
||||
ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
|
||||
|
||||
Rect from = (Rect) startValues.values.get(PROP_BOUNDS);
|
||||
Rect to = (Rect) endValues.values.get(PROP_BOUNDS);
|
||||
|
||||
anim.addUpdateListener(
|
||||
animation -> mController.getClockAnimations().onPositionUpdated(
|
||||
from, to, animation.getAnimatedFraction()));
|
||||
|
||||
return anim;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getTransitionProperties() {
|
||||
return TRANSITION_PROPERTIES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.database.ContentObserver;
|
||||
import android.graphics.Rect;
|
||||
import android.net.Uri;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
@@ -45,6 +46,7 @@ import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.dump.DumpManager;
|
||||
import com.android.systemui.flags.FeatureFlags;
|
||||
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
|
||||
import com.android.systemui.plugins.ClockAnimations;
|
||||
import com.android.systemui.plugins.ClockController;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.shared.clocks.AnimatableClockView;
|
||||
@@ -262,6 +264,19 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
|
||||
verify(mView).switchToClock(KeyguardClockSwitch.SMALL, /* animate */ true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetClockAnimationsForwardsToClock() {
|
||||
ClockController mockClockController = mock(ClockController.class);
|
||||
ClockAnimations mockClockAnimations = mock(ClockAnimations.class);
|
||||
when(mClockEventController.getClock()).thenReturn(mockClockController);
|
||||
when(mockClockController.getAnimations()).thenReturn(mockClockAnimations);
|
||||
|
||||
Rect r1 = new Rect(1, 2, 3, 4);
|
||||
Rect r2 = new Rect(5, 6, 7, 8);
|
||||
mController.getClockAnimations().onPositionUpdated(r1, r2, 0.2f);
|
||||
verify(mockClockAnimations).onPositionUpdated(r1, r2, 0.2f);
|
||||
}
|
||||
|
||||
private void verifyAttachment(VerificationMode times) {
|
||||
verify(mClockRegistry, times).registerClockChangeListener(
|
||||
any(ClockRegistry.ClockChangeListener.class));
|
||||
|
||||
@@ -16,12 +16,16 @@
|
||||
|
||||
package com.android.keyguard;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.plugins.ClockAnimations;
|
||||
import com.android.systemui.statusbar.phone.DozeParameters;
|
||||
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||
@@ -108,4 +112,16 @@ public class KeyguardStatusViewControllerTest extends SysuiTestCase {
|
||||
configurationListenerArgumentCaptor.getValue().onLocaleListChanged();
|
||||
verify(mKeyguardClockSwitchController).onLocaleListChanged();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getClockAnimations_forwardsToClockSwitch() {
|
||||
ClockAnimations mockClockAnimations = mock(ClockAnimations.class);
|
||||
when(mKeyguardClockSwitchController.getClockAnimations()).thenReturn(mockClockAnimations);
|
||||
|
||||
Rect r1 = new Rect(1, 2, 3, 4);
|
||||
Rect r2 = new Rect(5, 6, 7, 8);
|
||||
mController.getClockAnimations().onPositionUpdated(r1, r2, 0.3f);
|
||||
|
||||
verify(mockClockAnimations).onPositionUpdated(r1, r2, 0.3f);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user