Merge "Add large screen clock motion - method 2." into tm-qpr-dev

This commit is contained in:
Jamie Garside
2022-10-21 14:57:42 +00:00
committed by Android (Google) Code Review
13 changed files with 376 additions and 39 deletions

View File

@@ -88,6 +88,11 @@ class TextAnimator(
*/
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.
*/

View File

@@ -244,7 +244,7 @@ class TextInterpolator(
canvas.translate(origin, layout.getLineBaseline(lineNo).toFloat())
run.fontRuns.forEach { fontRun ->
drawFontRun(canvas, run, fontRun, tmpPaint)
drawFontRun(canvas, run, fontRun, lineNo, tmpPaint)
}
} finally {
canvas.restore()
@@ -349,7 +349,7 @@ class TextInterpolator(
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)
@@ -368,11 +368,13 @@ class TextInterpolator(
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)

View File

@@ -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 */

View File

@@ -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

View File

@@ -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)
@@ -316,7 +317,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.
@@ -432,6 +450,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 {
@@ -469,5 +605,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)
}
}

View File

@@ -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(

View File

@@ -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,10 @@ public class KeyguardClockSwitchController extends ViewController<KeyguardClockS
clock.dump(pw);
}
}
/** Gets the animations for the current clock. */
public ClockAnimations getClockAnimations() {
return getClock().getAnimations();
}
}

View File

@@ -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();
}
}

View File

@@ -143,6 +143,12 @@ public class Flags {
// TODO(b/254513102): Tracking Bug
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(212);
/***************************************/
// 300 - power menu
// TODO(b/254512600): Tracking Bug

View File

@@ -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;
@@ -1667,9 +1670,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() != null
&& 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);
@@ -4166,8 +4200,8 @@ public final class NotificationPanelViewController {
/**
* Sets the dozing state.
*
* @param dozing {@code true} when dozing.
* @param animate if transition should be animated.
* @param dozing {@code true} when dozing.
* @param animate if transition should be animated.
*/
public void setDozing(boolean dozing, boolean animate) {
if (dozing == mDozing) return;
@@ -4307,35 +4341,35 @@ public final class NotificationPanelViewController {
/**
* Starts fold to AOD animation.
*
* @param startAction invoked when the animation starts.
* @param endAction invoked when the animation finishes, also if it was cancelled.
* @param startAction invoked when the animation starts.
* @param endAction invoked when the animation finishes, also if it was cancelled.
* @param cancelAction invoked when the animation is cancelled, before endAction.
*/
public void startFoldToAodAnimation(Runnable startAction, Runnable endAction,
Runnable cancelAction) {
mView.animate()
.translationX(0)
.alpha(1f)
.setDuration(ANIMATION_DURATION_FOLD_TO_AOD)
.setInterpolator(EMPHASIZED_DECELERATE)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
startAction.run();
}
.translationX(0)
.alpha(1f)
.setDuration(ANIMATION_DURATION_FOLD_TO_AOD)
.setInterpolator(EMPHASIZED_DECELERATE)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
startAction.run();
}
@Override
public void onAnimationCancel(Animator animation) {
cancelAction.run();
}
@Override
public void onAnimationCancel(Animator animation) {
cancelAction.run();
}
@Override
public void onAnimationEnd(Animator animation) {
endAction.run();
}
}).setUpdateListener(anim -> {
mKeyguardStatusViewController.animateFoldToAod(anim.getAnimatedFraction());
}).start();
@Override
public void onAnimationEnd(Animator animation) {
endAction.run();
}
}).setUpdateListener(anim -> {
mKeyguardStatusViewController.animateFoldToAod(anim.getAnimatedFraction());
}).start();
}
/**
@@ -4695,8 +4729,10 @@ public final class NotificationPanelViewController {
/**
* Maybe vibrate as panel is opened.
*
* @param openingWithTouch Whether the panel is being opened with touch. If the panel is instead
* being opened programmatically (such as by the open panel gesture), we always play haptic.
* @param openingWithTouch Whether the panel is being opened with touch. If the panel is
* instead
* being opened programmatically (such as by the open panel gesture), we
* always play haptic.
*/
private void maybeVibrateOnOpening(boolean openingWithTouch) {
if (mVibrateOnOpening) {
@@ -4861,10 +4897,12 @@ public final class NotificationPanelViewController {
animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
animator.addListener(new AnimatorListenerAdapter() {
private boolean mCancelled;
@Override
public void onAnimationCancel(Animator animation) {
mCancelled = true;
}
@Override
public void onAnimationEnd(Animator animation) {
mIsSpringBackAnimation = false;
@@ -4912,7 +4950,7 @@ public final class NotificationPanelViewController {
if (isNaN(h)) {
Log.wtf(TAG, "ExpandedHeight set to NaN");
}
mNotificationShadeWindowController.batchApplyWindowLayoutParams(()-> {
mNotificationShadeWindowController.batchApplyWindowLayoutParams(() -> {
if (mExpandLatencyTracking && h != 0f) {
DejankUtils.postAfterTraversal(
() -> mLatencyTracker.onActionEnd(LatencyTracker.ACTION_EXPAND_PANEL));
@@ -5103,7 +5141,7 @@ public final class NotificationPanelViewController {
/**
* Create an animator that can also overshoot
*
* @param targetHeight the target height
* @param targetHeight the target height
* @param overshootAmount the amount of overshoot desired
*/
private ValueAnimator createHeightAnimator(float targetHeight, float overshootAmount) {
@@ -5900,7 +5938,7 @@ public final class NotificationPanelViewController {
public final class TouchHandler implements View.OnTouchListener {
private long mLastTouchDownTime = -1L;
/** @see ViewGroup#onInterceptTouchEvent(MotionEvent) */
/** @see ViewGroup#onInterceptTouchEvent(MotionEvent) */
public boolean onInterceptTouchEvent(MotionEvent event) {
if (SPEW_LOGCAT) {
Log.v(TAG,
@@ -6099,7 +6137,7 @@ public final class NotificationPanelViewController {
mShadeLog.logMotionEvent(event, "onTouch: touch ignored due to instant expanding");
return false;
}
if (mTouchDisabled && event.getActionMasked() != MotionEvent.ACTION_CANCEL) {
if (mTouchDisabled && event.getActionMasked() != MotionEvent.ACTION_CANCEL) {
mShadeLog.logMotionEvent(event, "onTouch: non-cancel action, touch disabled");
return false;
}
@@ -6256,4 +6294,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;
}
}
}

View File

@@ -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));

View File

@@ -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);
}
}

View File

@@ -22,6 +22,7 @@ import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.TextAnimator
import com.android.systemui.util.mockito.any
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -55,7 +56,7 @@ class AnimatableClockViewTest : SysuiTestCase() {
clockView.animateAppearOnLockscreen()
clockView.measure(50, 50)
verify(mockTextAnimator).glyphFilter = null
verify(mockTextAnimator).glyphFilter = any()
verify(mockTextAnimator).setTextStyle(300, -1.0f, 200, false, 350L, null, 0L, null)
verifyNoMoreInteractions(mockTextAnimator)
}
@@ -66,7 +67,7 @@ class AnimatableClockViewTest : SysuiTestCase() {
clockView.measure(50, 50)
clockView.animateAppearOnLockscreen()
verify(mockTextAnimator, times(2)).glyphFilter = null
verify(mockTextAnimator, times(2)).glyphFilter = any()
verify(mockTextAnimator).setTextStyle(100, -1.0f, 200, false, 0L, null, 0L, null)
verify(mockTextAnimator).setTextStyle(300, -1.0f, 200, true, 350L, null, 0L, null)
verifyNoMoreInteractions(mockTextAnimator)