Loading packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java +96 −22 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.systemui.keyguard; import android.annotation.Nullable; import android.content.res.ColorStateList; import android.graphics.Color; import android.os.SystemClock; import android.text.TextUtils; import androidx.annotation.IntDef; Loading @@ -40,13 +41,24 @@ import java.util.List; import java.util.Map; /** * Rotates through messages to show on the keyguard bottom area on the lock screen * NOTE: This controller should not be used on AoD to avoid waking up the AP too often. * Animates through messages to show on the keyguard bottom area on the lock screen. * Utilizes a {@link KeyguardIndicationTextView} for animations. This class handles the rotating * nature of the messages including: * - ensuring a message is shown for its minimum amount of time. Minimum time is determined by * {@link KeyguardIndication#getMinVisibilityMillis()} * - showing the next message after a default of 3.5 seconds before animating to the next * - statically showing a single message if there is only one message to show * - showing certain messages immediately, assuming te current message has been shown for * at least {@link KeyguardIndication#getMinVisibilityMillis()}. For example, transient and * biometric messages are meant to be shown immediately. * - ending animations when dozing begins, and resuming when dozing ends. Rotating messages on * AoD is undesirable since it wakes up the AP too often. */ public class KeyguardIndicationRotateTextViewController extends ViewController<KeyguardIndicationTextView> implements Dumpable { public static String TAG = "KgIndicationRotatingCtrl"; private static final long DEFAULT_INDICATION_SHOW_LENGTH = 3500; // milliseconds public static final long IMPORTANT_MSG_MIN_DURATION = 2000L + 600L; // 2000ms + [Y in duration] private final StatusBarStateController mStatusBarStateController; private final float mMaxAlpha; Loading @@ -62,6 +74,8 @@ public class KeyguardIndicationRotateTextViewController extends // List of indication types to show. The next indication to show is always at index 0 private final List<Integer> mIndicationQueue = new LinkedList<>(); private @IndicationType int mCurrIndicationType = INDICATION_TYPE_NONE; private CharSequence mCurrMessage; private long mLastIndicationSwitch; private boolean mIsDozing; Loading Loading @@ -94,17 +108,19 @@ public class KeyguardIndicationRotateTextViewController extends * Update the indication type with the given String. * @param type of indication * @param newIndication message to associate with this indication type * @param showImmediately if true: shows this indication message immediately. Else, the text * associated with this type is updated and will show when its turn in * the IndicationQueue comes around. * @param showAsap if true: shows this indication message as soon as possible. If false, * the text associated with this type is updated and will show when its turn * in the IndicationQueue comes around. */ public void updateIndication(@IndicationType int type, KeyguardIndication newIndication, boolean updateImmediately) { boolean showAsap) { if (type == INDICATION_TYPE_REVERSE_CHARGING) { // temporarily don't show here, instead use AmbientContainer b/181049781 return; } final boolean hasPreviousIndication = mIndicationMessages.get(type) != null; long minShowDuration = getMinVisibilityMillis(mIndicationMessages.get(mCurrIndicationType)); final boolean hasPreviousIndication = mIndicationMessages.get(type) != null && !TextUtils.isEmpty(mIndicationMessages.get(type).getMessage()); final boolean hasNewIndication = newIndication != null; if (!hasNewIndication) { mIndicationMessages.remove(type); Loading @@ -121,26 +137,47 @@ public class KeyguardIndicationRotateTextViewController extends return; } final boolean showNow = updateImmediately || mCurrIndicationType == INDICATION_TYPE_NONE || mCurrIndicationType == type; long currTime = SystemClock.uptimeMillis(); long timeSinceLastIndicationSwitch = currTime - mLastIndicationSwitch; boolean currMsgShownForMinTime = timeSinceLastIndicationSwitch >= minShowDuration; if (hasNewIndication) { if (showNow) { if (mCurrIndicationType == INDICATION_TYPE_NONE || mCurrIndicationType == type) { showIndication(type); } else if (showAsap) { if (currMsgShownForMinTime) { showIndication(type); } else { mIndicationQueue.removeIf(x -> x == type); mIndicationQueue.add(0 /* index */, type /* type */); scheduleShowNextIndication(minShowDuration - timeSinceLastIndicationSwitch); } } else if (!isNextIndicationScheduled()) { scheduleShowNextIndication(); long nextShowTime = Math.max( getMinVisibilityMillis(mIndicationMessages.get(type)), DEFAULT_INDICATION_SHOW_LENGTH); if (timeSinceLastIndicationSwitch >= nextShowTime) { showIndication(type); } else { scheduleShowNextIndication( nextShowTime - timeSinceLastIndicationSwitch); } } return; } // current indication is updated to empty if (mCurrIndicationType == type && !hasNewIndication && updateImmediately) { && showAsap) { if (currMsgShownForMinTime) { if (mShowNextIndicationRunnable != null) { mShowNextIndicationRunnable.runImmediately(); } else { showIndication(INDICATION_TYPE_NONE); } } else { scheduleShowNextIndication(minShowDuration - timeSinceLastIndicationSwitch); } } } Loading @@ -164,11 +201,10 @@ public class KeyguardIndicationRotateTextViewController extends * - will continue to be in the rotation of messages shown until hideTransient is called. */ public void showTransient(CharSequence newIndication) { final long inAnimationDuration = 600L; // see KeyguardIndicationTextView.getYInDuration updateIndication(INDICATION_TYPE_TRANSIENT, new KeyguardIndication.Builder() .setMessage(newIndication) .setMinVisibilityMillis(2000L + inAnimationDuration) .setMinVisibilityMillis(IMPORTANT_MSG_MIN_DURATION) .setTextColor(mInitialTextColorState) .build(), /* showImmediately */true); Loading @@ -188,6 +224,15 @@ public class KeyguardIndicationRotateTextViewController extends return mIndicationMessages.keySet().size() > 0; } /** * Clears all messages in the queue and sets the current message to an empty string. */ public void clearMessages() { mCurrIndicationType = INDICATION_TYPE_NONE; mIndicationQueue.clear(); mView.clearMessages(); } /** * Immediately show the passed indication type and schedule the next indication to show. * Will re-add this indication to be re-shown after all other indications have been Loading @@ -196,27 +241,52 @@ public class KeyguardIndicationRotateTextViewController extends private void showIndication(@IndicationType int type) { cancelScheduledIndication(); final CharSequence previousMessage = mCurrMessage; final @IndicationType int previousIndicationType = mCurrIndicationType; mCurrIndicationType = type; mCurrMessage = mIndicationMessages.get(type) != null ? mIndicationMessages.get(type).getMessage() : null; mIndicationQueue.removeIf(x -> x == type); if (mCurrIndicationType != INDICATION_TYPE_NONE) { mIndicationQueue.add(type); // re-add to show later } mLastIndicationSwitch = SystemClock.uptimeMillis(); if (!TextUtils.equals(previousMessage, mCurrMessage) || previousIndicationType != mCurrIndicationType) { mView.switchIndication(mIndicationMessages.get(type)); } // only schedule next indication if there's more than just this indication in the queue if (mCurrIndicationType != INDICATION_TYPE_NONE && mIndicationQueue.size() > 1) { scheduleShowNextIndication(); scheduleShowNextIndication(Math.max( getMinVisibilityMillis(mIndicationMessages.get(type)), DEFAULT_INDICATION_SHOW_LENGTH)); } } private long getMinVisibilityMillis(KeyguardIndication indication) { if (indication == null) { return 0; } if (indication.getMinVisibilityMillis() == null) { return 0; } return indication.getMinVisibilityMillis(); } protected boolean isNextIndicationScheduled() { return mShowNextIndicationRunnable != null; } private void scheduleShowNextIndication() { private void scheduleShowNextIndication(long msUntilShowNextMsg) { cancelScheduledIndication(); mShowNextIndicationRunnable = new ShowNextIndication(DEFAULT_INDICATION_SHOW_LENGTH); mShowNextIndicationRunnable = new ShowNextIndication(msUntilShowNextMsg); } private void cancelScheduledIndication() { Loading Loading @@ -292,7 +362,9 @@ public class KeyguardIndicationRotateTextViewController extends } } // only used locally to stop showing any messages & stop the rotating messages static final int INDICATION_TYPE_NONE = -1; public static final int INDICATION_TYPE_OWNER_INFO = 0; public static final int INDICATION_TYPE_DISCLOSURE = 1; public static final int INDICATION_TYPE_LOGOUT = 2; Loading @@ -303,6 +375,7 @@ public class KeyguardIndicationRotateTextViewController extends public static final int INDICATION_TYPE_RESTING = 7; public static final int INDICATION_TYPE_USER_LOCKED = 8; public static final int INDICATION_TYPE_REVERSE_CHARGING = 10; public static final int INDICATION_TYPE_BIOMETRIC_MESSAGE = 11; @IntDef({ INDICATION_TYPE_NONE, Loading @@ -316,6 +389,7 @@ public class KeyguardIndicationRotateTextViewController extends INDICATION_TYPE_RESTING, INDICATION_TYPE_USER_LOCKED, INDICATION_TYPE_REVERSE_CHARGING, INDICATION_TYPE_BIOMETRIC_MESSAGE }) @Retention(RetentionPolicy.SOURCE) public @interface IndicationType{} Loading packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +108 −48 File changed.Preview size limit exceeded, changes collapsed. Show changes packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java +45 −56 Original line number Diff line number Diff line Loading @@ -35,23 +35,20 @@ import com.android.systemui.R; import com.android.systemui.animation.Interpolators; import com.android.systemui.keyguard.KeyguardIndication; import java.util.LinkedList; /** * A view to show hints on Keyguard ("Swipe up to unlock", "Tap again to open"). */ public class KeyguardIndicationTextView extends TextView { private static final long MSG_MIN_DURATION_MILLIS_DEFAULT = 1500; @StyleRes private static int sStyleId = R.style.TextAppearance_Keyguard_BottomArea; @StyleRes private static int sButtonStyleId = R.style.TextAppearance_Keyguard_BottomArea_Button; private long mNextAnimationTime = 0; private boolean mAnimationsEnabled = true; private LinkedList<CharSequence> mMessages = new LinkedList<>(); private LinkedList<KeyguardIndication> mKeyguardIndicationInfo = new LinkedList<>(); private CharSequence mMessage; private KeyguardIndication mKeyguardIndicationInfo; private Animator mLastAnimator; public KeyguardIndicationTextView(Context context) { super(context); Loading @@ -71,22 +68,24 @@ public class KeyguardIndicationTextView extends TextView { } /** * Clears message queue. * Clears message queue and currently shown message. */ public void clearMessages() { mMessages.clear(); mKeyguardIndicationInfo.clear(); if (mLastAnimator != null) { mLastAnimator.cancel(); } setText(""); } /** * Changes the text with an animation and makes sure a single indication is shown long enough. * Changes the text with an animation. */ public void switchIndication(int textResId) { switchIndication(getResources().getText(textResId), null); } /** * Changes the text with an animation and makes sure a single indication is shown long enough. * Changes the text with an animation. * * @param indication The text to show. */ Loading @@ -95,15 +94,14 @@ public class KeyguardIndicationTextView extends TextView { } /** * Changes the text with an animation. Makes sure a single indication is shown long enough. * Changes the text with an animation. */ public void switchIndication(CharSequence text, KeyguardIndication indication) { switchIndication(text, indication, true, null); } /** * Changes the text with an optional animation. For animating text, makes sure a single * indication is shown long enough. * Updates the text with an optional animation. * * @param text The text to show. * @param indication optional display information for the text Loading @@ -112,33 +110,15 @@ public class KeyguardIndicationTextView extends TextView { */ public void switchIndication(CharSequence text, KeyguardIndication indication, boolean animate, Runnable onAnimationEndCallback) { if (text == null) text = ""; CharSequence lastPendingMessage = mMessages.peekLast(); if (TextUtils.equals(lastPendingMessage, text) || (lastPendingMessage == null && TextUtils.equals(text, getText()))) { if (onAnimationEndCallback != null) { onAnimationEndCallback.run(); } return; } mMessages.add(text); mKeyguardIndicationInfo.add(indication); mMessage = text; mKeyguardIndicationInfo = indication; if (animate) { final boolean hasIcon = indication != null && indication.getIcon() != null; final AnimatorSet animator = new AnimatorSet(); AnimatorSet animator = new AnimatorSet(); // Make sure each animation is visible for a minimum amount of time, while not worrying // about fading in blank text long timeInMillis = System.currentTimeMillis(); long delay = Math.max(0, mNextAnimationTime - timeInMillis); setNextAnimationTime(timeInMillis + delay + getFadeOutDuration()); final long minDurationMillis = (indication != null && indication.getMinVisibilityMillis() != null) ? indication.getMinVisibilityMillis() : MSG_MIN_DURATION_MILLIS_DEFAULT; if (!text.equals("") || hasIcon) { setNextAnimationTime(mNextAnimationTime + minDurationMillis); if (!TextUtils.isEmpty(mMessage) || hasIcon) { Animator inAnimator = getInAnimator(); inAnimator.addListener(new AnimatorListenerAdapter() { @Override Loading @@ -164,7 +144,10 @@ public class KeyguardIndicationTextView extends TextView { animator.play(outAnimator); } animator.setStartDelay(delay); if (mLastAnimator != null) { mLastAnimator.cancel(); } mLastAnimator = animator; animator.start(); } else { setAlpha(1f); Loading @@ -173,6 +156,10 @@ public class KeyguardIndicationTextView extends TextView { if (onAnimationEndCallback != null) { onAnimationEndCallback.run(); } if (mLastAnimator != null) { mLastAnimator.cancel(); mLastAnimator = null; } } } Loading @@ -182,11 +169,21 @@ public class KeyguardIndicationTextView extends TextView { fadeOut.setDuration(getFadeOutDuration()); fadeOut.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN); fadeOut.addListener(new AnimatorListenerAdapter() { private boolean mCancelled = false; @Override public void onAnimationEnd(Animator animator) { super.onAnimationEnd(animator); if (!mCancelled) { setNextIndication(); } } @Override public void onAnimationCancel(Animator animator) { super.onAnimationCancel(animator); mCancelled = true; setAlpha(0); } }); Animator yTranslate = Loading @@ -198,20 +195,19 @@ public class KeyguardIndicationTextView extends TextView { } private void setNextIndication() { KeyguardIndication info = mKeyguardIndicationInfo.poll(); if (info != null) { if (mKeyguardIndicationInfo != null) { // First, update the style. // If a background is set on the text, we don't want shadow on the text if (info.getBackground() != null) { if (mKeyguardIndicationInfo.getBackground() != null) { setTextAppearance(sButtonStyleId); } else { setTextAppearance(sStyleId); } setBackground(info.getBackground()); setTextColor(info.getTextColor()); setOnClickListener(info.getClickListener()); setClickable(info.getClickListener() != null); final Drawable icon = info.getIcon(); setBackground(mKeyguardIndicationInfo.getBackground()); setTextColor(mKeyguardIndicationInfo.getTextColor()); setOnClickListener(mKeyguardIndicationInfo.getClickListener()); setClickable(mKeyguardIndicationInfo.getClickListener() != null); final Drawable icon = mKeyguardIndicationInfo.getIcon(); if (icon != null) { icon.setTint(getCurrentTextColor()); if (icon instanceof AnimatedVectorDrawable) { Loading @@ -220,7 +216,7 @@ public class KeyguardIndicationTextView extends TextView { } setCompoundDrawablesRelativeWithIntrinsicBounds(icon, null, null, null); } setText(mMessages.poll()); setText(mMessage); } private AnimatorSet getInAnimator() { Loading @@ -238,6 +234,7 @@ public class KeyguardIndicationTextView extends TextView { public void onAnimationCancel(Animator animation) { super.onAnimationCancel(animation); setTranslationY(0); setAlpha(1f); } }); animatorSet.playTogether(yTranslate, fadeIn); Loading Loading @@ -270,14 +267,6 @@ public class KeyguardIndicationTextView extends TextView { return 167L; } private void setNextAnimationTime(long time) { if (mAnimationsEnabled) { mNextAnimationTime = time; } else { mNextAnimationTime = 0L; } } private int getYTranslationPixels() { return mContext.getResources().getDimensionPixelSize( com.android.systemui.R.dimen.keyguard_indication_y_translation); Loading packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewControllerTest.java +40 −3 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.keyguard; import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BATTERY; import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BIOMETRIC_MESSAGE; import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_DISCLOSURE; import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_OWNER_INFO; Loading Loading @@ -56,7 +57,8 @@ import org.mockito.MockitoAnnotations; public class KeyguardIndicationRotateTextViewControllerTest extends SysuiTestCase { private static final String TEST_MESSAGE = "test message"; private static final String TEST_MESSAGE_2 = "test message 2"; private static final String TEST_MESSAGE_2 = "test message two"; private int mMsgId = 0; @Mock private DelayableExecutor mExecutor; Loading Loading @@ -200,6 +202,24 @@ public class KeyguardIndicationRotateTextViewControllerTest extends SysuiTestCas verify(mExecutor).executeDelayed(any(), anyLong()); } @Test public void testSameMessage_noIndicationUpdate() { // GIVEN we are showing and indication with a test message mController.updateIndication( INDICATION_TYPE_OWNER_INFO, createIndication(TEST_MESSAGE), true); reset(mView); reset(mExecutor); // WHEN the same type tries to show the same exact message final KeyguardIndication sameIndication = createIndication(TEST_MESSAGE); mController.updateIndication( INDICATION_TYPE_OWNER_INFO, sameIndication, true); // THEN // - we don't update the indication b/c there's no reason the animate the same text verify(mView, never()).switchIndication(sameIndication); } @Test public void testTransientIndication() { // GIVEN we already have two indication messages Loading @@ -223,8 +243,11 @@ public class KeyguardIndicationRotateTextViewControllerTest extends SysuiTestCas @Test public void testHideIndicationOneMessage() { // GIVEN we have one indication message KeyguardIndication indication = createIndication(); mController.updateIndication( INDICATION_TYPE_OWNER_INFO, createIndication(), false); INDICATION_TYPE_OWNER_INFO, indication, false); verify(mView).switchIndication(indication); reset(mView); // WHEN we hide the current indication type mController.hideIndication(INDICATION_TYPE_OWNER_INFO); Loading Loading @@ -254,6 +277,10 @@ public class KeyguardIndicationRotateTextViewControllerTest extends SysuiTestCas @Test public void testStartDozing() { // GIVEN a biometric message is showing mController.updateIndication(INDICATION_TYPE_BIOMETRIC_MESSAGE, createIndication(), true); // WHEN the device is dozing mStatusBarStateListener.onDozingChanged(true); Loading Loading @@ -293,9 +320,19 @@ public class KeyguardIndicationRotateTextViewControllerTest extends SysuiTestCas verify(mView, never()).switchIndication(any()); } /** * Create an indication with a unique message. */ private KeyguardIndication createIndication() { return createIndication(TEST_MESSAGE + " " + mMsgId++); } /** * Create an indication with the given message. */ private KeyguardIndication createIndication(String msg) { return new KeyguardIndication.Builder() .setMessage(TEST_MESSAGE) .setMessage(msg) .setTextColor(ColorStateList.valueOf(Color.WHITE)) .build(); } Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java +20 −10 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE; import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ALIGNMENT; import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BATTERY; import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BIOMETRIC_MESSAGE; import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_DISCLOSURE; import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_OWNER_INFO; import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_RESTING; Loading Loading @@ -112,6 +113,8 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { private static final ComponentName DEVICE_OWNER_COMPONENT = new ComponentName("com.android.foo", "bar"); private static final int TEST_STRING_RES = R.string.keyguard_indication_trust_unlocked; private String mKeyguardTryFingerprintMsg; private String mDisclosureWithOrganization; private String mDisclosureGeneric; Loading Loading @@ -419,7 +422,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { // WHEN transient text is shown mStatusBarStateListener.onDozingChanged(true); mController.showTransientIndication("Test"); mController.showTransientIndication(TEST_STRING_RES); // THEN wake lock is held while the animation is running assertTrue("WakeLock expected: HELD, was: RELEASED", mWakeLock.isHeld()); Loading @@ -434,7 +437,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { // WHEN we show the transient indication mStatusBarStateListener.onDozingChanged(true); mController.showTransientIndication("Test"); mController.showTransientIndication(TEST_STRING_RES); // THEN wake lock is RELEASED, not held assertFalse("WakeLock expected: RELEASED, was: HELD", mWakeLock.isHeld()); Loading @@ -445,10 +448,11 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { createController(); mController.setVisible(true); mController.showTransientIndication("Test"); mController.showTransientIndication(TEST_STRING_RES); mStatusBarStateListener.onDozingChanged(true); assertThat(mTextView.getText()).isEqualTo("Test"); assertThat(mTextView.getText()).isEqualTo( mContext.getResources().getString(TEST_STRING_RES)); assertThat(mTextView.getCurrentTextColor()).isEqualTo(Color.WHITE); assertThat(mTextView.getAlpha()).isEqualTo(1f); } Loading @@ -462,11 +466,11 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { mController.getKeyguardCallback().onBiometricHelp( KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED, message, BiometricSourceType.FACE); verifyTransientMessage(message); verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, message); reset(mRotateTextViewController); mStatusBarStateListener.onDozingChanged(true); verifyHideIndication(INDICATION_TYPE_TRANSIENT); verifyHideIndication(INDICATION_TYPE_BIOMETRIC_MESSAGE); } @Test Loading @@ -478,7 +482,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { mController.getKeyguardCallback().onBiometricError(FaceManager.FACE_ERROR_TIMEOUT, "A message", BiometricSourceType.FACE); verifyTransientMessage(message); verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, message); mStatusBarStateListener.onDozingChanged(true); assertThat(mTextView.getText()).isNotEqualTo(message); Loading @@ -497,7 +501,8 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { FingerprintManager.FINGERPRINT_ERROR_CANCELED, "bar", BiometricSourceType.FINGERPRINT); verifyNoTransientMessage(); verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE); verifyNoMessage(INDICATION_TYPE_TRANSIENT); } @Test Loading Loading @@ -757,7 +762,12 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { verify(mRotateTextViewController).showTransient(eq(message)); } private void verifyNoTransientMessage() { verify(mRotateTextViewController, never()).showTransient(any()); private void verifyNoMessage(int type) { if (type == INDICATION_TYPE_TRANSIENT) { verify(mRotateTextViewController, never()).showTransient(anyString()); } else { verify(mRotateTextViewController, never()).updateIndication(eq(type), anyObject(), anyBoolean()); } } } Loading
packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java +96 −22 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.systemui.keyguard; import android.annotation.Nullable; import android.content.res.ColorStateList; import android.graphics.Color; import android.os.SystemClock; import android.text.TextUtils; import androidx.annotation.IntDef; Loading @@ -40,13 +41,24 @@ import java.util.List; import java.util.Map; /** * Rotates through messages to show on the keyguard bottom area on the lock screen * NOTE: This controller should not be used on AoD to avoid waking up the AP too often. * Animates through messages to show on the keyguard bottom area on the lock screen. * Utilizes a {@link KeyguardIndicationTextView} for animations. This class handles the rotating * nature of the messages including: * - ensuring a message is shown for its minimum amount of time. Minimum time is determined by * {@link KeyguardIndication#getMinVisibilityMillis()} * - showing the next message after a default of 3.5 seconds before animating to the next * - statically showing a single message if there is only one message to show * - showing certain messages immediately, assuming te current message has been shown for * at least {@link KeyguardIndication#getMinVisibilityMillis()}. For example, transient and * biometric messages are meant to be shown immediately. * - ending animations when dozing begins, and resuming when dozing ends. Rotating messages on * AoD is undesirable since it wakes up the AP too often. */ public class KeyguardIndicationRotateTextViewController extends ViewController<KeyguardIndicationTextView> implements Dumpable { public static String TAG = "KgIndicationRotatingCtrl"; private static final long DEFAULT_INDICATION_SHOW_LENGTH = 3500; // milliseconds public static final long IMPORTANT_MSG_MIN_DURATION = 2000L + 600L; // 2000ms + [Y in duration] private final StatusBarStateController mStatusBarStateController; private final float mMaxAlpha; Loading @@ -62,6 +74,8 @@ public class KeyguardIndicationRotateTextViewController extends // List of indication types to show. The next indication to show is always at index 0 private final List<Integer> mIndicationQueue = new LinkedList<>(); private @IndicationType int mCurrIndicationType = INDICATION_TYPE_NONE; private CharSequence mCurrMessage; private long mLastIndicationSwitch; private boolean mIsDozing; Loading Loading @@ -94,17 +108,19 @@ public class KeyguardIndicationRotateTextViewController extends * Update the indication type with the given String. * @param type of indication * @param newIndication message to associate with this indication type * @param showImmediately if true: shows this indication message immediately. Else, the text * associated with this type is updated and will show when its turn in * the IndicationQueue comes around. * @param showAsap if true: shows this indication message as soon as possible. If false, * the text associated with this type is updated and will show when its turn * in the IndicationQueue comes around. */ public void updateIndication(@IndicationType int type, KeyguardIndication newIndication, boolean updateImmediately) { boolean showAsap) { if (type == INDICATION_TYPE_REVERSE_CHARGING) { // temporarily don't show here, instead use AmbientContainer b/181049781 return; } final boolean hasPreviousIndication = mIndicationMessages.get(type) != null; long minShowDuration = getMinVisibilityMillis(mIndicationMessages.get(mCurrIndicationType)); final boolean hasPreviousIndication = mIndicationMessages.get(type) != null && !TextUtils.isEmpty(mIndicationMessages.get(type).getMessage()); final boolean hasNewIndication = newIndication != null; if (!hasNewIndication) { mIndicationMessages.remove(type); Loading @@ -121,26 +137,47 @@ public class KeyguardIndicationRotateTextViewController extends return; } final boolean showNow = updateImmediately || mCurrIndicationType == INDICATION_TYPE_NONE || mCurrIndicationType == type; long currTime = SystemClock.uptimeMillis(); long timeSinceLastIndicationSwitch = currTime - mLastIndicationSwitch; boolean currMsgShownForMinTime = timeSinceLastIndicationSwitch >= minShowDuration; if (hasNewIndication) { if (showNow) { if (mCurrIndicationType == INDICATION_TYPE_NONE || mCurrIndicationType == type) { showIndication(type); } else if (showAsap) { if (currMsgShownForMinTime) { showIndication(type); } else { mIndicationQueue.removeIf(x -> x == type); mIndicationQueue.add(0 /* index */, type /* type */); scheduleShowNextIndication(minShowDuration - timeSinceLastIndicationSwitch); } } else if (!isNextIndicationScheduled()) { scheduleShowNextIndication(); long nextShowTime = Math.max( getMinVisibilityMillis(mIndicationMessages.get(type)), DEFAULT_INDICATION_SHOW_LENGTH); if (timeSinceLastIndicationSwitch >= nextShowTime) { showIndication(type); } else { scheduleShowNextIndication( nextShowTime - timeSinceLastIndicationSwitch); } } return; } // current indication is updated to empty if (mCurrIndicationType == type && !hasNewIndication && updateImmediately) { && showAsap) { if (currMsgShownForMinTime) { if (mShowNextIndicationRunnable != null) { mShowNextIndicationRunnable.runImmediately(); } else { showIndication(INDICATION_TYPE_NONE); } } else { scheduleShowNextIndication(minShowDuration - timeSinceLastIndicationSwitch); } } } Loading @@ -164,11 +201,10 @@ public class KeyguardIndicationRotateTextViewController extends * - will continue to be in the rotation of messages shown until hideTransient is called. */ public void showTransient(CharSequence newIndication) { final long inAnimationDuration = 600L; // see KeyguardIndicationTextView.getYInDuration updateIndication(INDICATION_TYPE_TRANSIENT, new KeyguardIndication.Builder() .setMessage(newIndication) .setMinVisibilityMillis(2000L + inAnimationDuration) .setMinVisibilityMillis(IMPORTANT_MSG_MIN_DURATION) .setTextColor(mInitialTextColorState) .build(), /* showImmediately */true); Loading @@ -188,6 +224,15 @@ public class KeyguardIndicationRotateTextViewController extends return mIndicationMessages.keySet().size() > 0; } /** * Clears all messages in the queue and sets the current message to an empty string. */ public void clearMessages() { mCurrIndicationType = INDICATION_TYPE_NONE; mIndicationQueue.clear(); mView.clearMessages(); } /** * Immediately show the passed indication type and schedule the next indication to show. * Will re-add this indication to be re-shown after all other indications have been Loading @@ -196,27 +241,52 @@ public class KeyguardIndicationRotateTextViewController extends private void showIndication(@IndicationType int type) { cancelScheduledIndication(); final CharSequence previousMessage = mCurrMessage; final @IndicationType int previousIndicationType = mCurrIndicationType; mCurrIndicationType = type; mCurrMessage = mIndicationMessages.get(type) != null ? mIndicationMessages.get(type).getMessage() : null; mIndicationQueue.removeIf(x -> x == type); if (mCurrIndicationType != INDICATION_TYPE_NONE) { mIndicationQueue.add(type); // re-add to show later } mLastIndicationSwitch = SystemClock.uptimeMillis(); if (!TextUtils.equals(previousMessage, mCurrMessage) || previousIndicationType != mCurrIndicationType) { mView.switchIndication(mIndicationMessages.get(type)); } // only schedule next indication if there's more than just this indication in the queue if (mCurrIndicationType != INDICATION_TYPE_NONE && mIndicationQueue.size() > 1) { scheduleShowNextIndication(); scheduleShowNextIndication(Math.max( getMinVisibilityMillis(mIndicationMessages.get(type)), DEFAULT_INDICATION_SHOW_LENGTH)); } } private long getMinVisibilityMillis(KeyguardIndication indication) { if (indication == null) { return 0; } if (indication.getMinVisibilityMillis() == null) { return 0; } return indication.getMinVisibilityMillis(); } protected boolean isNextIndicationScheduled() { return mShowNextIndicationRunnable != null; } private void scheduleShowNextIndication() { private void scheduleShowNextIndication(long msUntilShowNextMsg) { cancelScheduledIndication(); mShowNextIndicationRunnable = new ShowNextIndication(DEFAULT_INDICATION_SHOW_LENGTH); mShowNextIndicationRunnable = new ShowNextIndication(msUntilShowNextMsg); } private void cancelScheduledIndication() { Loading Loading @@ -292,7 +362,9 @@ public class KeyguardIndicationRotateTextViewController extends } } // only used locally to stop showing any messages & stop the rotating messages static final int INDICATION_TYPE_NONE = -1; public static final int INDICATION_TYPE_OWNER_INFO = 0; public static final int INDICATION_TYPE_DISCLOSURE = 1; public static final int INDICATION_TYPE_LOGOUT = 2; Loading @@ -303,6 +375,7 @@ public class KeyguardIndicationRotateTextViewController extends public static final int INDICATION_TYPE_RESTING = 7; public static final int INDICATION_TYPE_USER_LOCKED = 8; public static final int INDICATION_TYPE_REVERSE_CHARGING = 10; public static final int INDICATION_TYPE_BIOMETRIC_MESSAGE = 11; @IntDef({ INDICATION_TYPE_NONE, Loading @@ -316,6 +389,7 @@ public class KeyguardIndicationRotateTextViewController extends INDICATION_TYPE_RESTING, INDICATION_TYPE_USER_LOCKED, INDICATION_TYPE_REVERSE_CHARGING, INDICATION_TYPE_BIOMETRIC_MESSAGE }) @Retention(RetentionPolicy.SOURCE) public @interface IndicationType{} Loading
packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +108 −48 File changed.Preview size limit exceeded, changes collapsed. Show changes
packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java +45 −56 Original line number Diff line number Diff line Loading @@ -35,23 +35,20 @@ import com.android.systemui.R; import com.android.systemui.animation.Interpolators; import com.android.systemui.keyguard.KeyguardIndication; import java.util.LinkedList; /** * A view to show hints on Keyguard ("Swipe up to unlock", "Tap again to open"). */ public class KeyguardIndicationTextView extends TextView { private static final long MSG_MIN_DURATION_MILLIS_DEFAULT = 1500; @StyleRes private static int sStyleId = R.style.TextAppearance_Keyguard_BottomArea; @StyleRes private static int sButtonStyleId = R.style.TextAppearance_Keyguard_BottomArea_Button; private long mNextAnimationTime = 0; private boolean mAnimationsEnabled = true; private LinkedList<CharSequence> mMessages = new LinkedList<>(); private LinkedList<KeyguardIndication> mKeyguardIndicationInfo = new LinkedList<>(); private CharSequence mMessage; private KeyguardIndication mKeyguardIndicationInfo; private Animator mLastAnimator; public KeyguardIndicationTextView(Context context) { super(context); Loading @@ -71,22 +68,24 @@ public class KeyguardIndicationTextView extends TextView { } /** * Clears message queue. * Clears message queue and currently shown message. */ public void clearMessages() { mMessages.clear(); mKeyguardIndicationInfo.clear(); if (mLastAnimator != null) { mLastAnimator.cancel(); } setText(""); } /** * Changes the text with an animation and makes sure a single indication is shown long enough. * Changes the text with an animation. */ public void switchIndication(int textResId) { switchIndication(getResources().getText(textResId), null); } /** * Changes the text with an animation and makes sure a single indication is shown long enough. * Changes the text with an animation. * * @param indication The text to show. */ Loading @@ -95,15 +94,14 @@ public class KeyguardIndicationTextView extends TextView { } /** * Changes the text with an animation. Makes sure a single indication is shown long enough. * Changes the text with an animation. */ public void switchIndication(CharSequence text, KeyguardIndication indication) { switchIndication(text, indication, true, null); } /** * Changes the text with an optional animation. For animating text, makes sure a single * indication is shown long enough. * Updates the text with an optional animation. * * @param text The text to show. * @param indication optional display information for the text Loading @@ -112,33 +110,15 @@ public class KeyguardIndicationTextView extends TextView { */ public void switchIndication(CharSequence text, KeyguardIndication indication, boolean animate, Runnable onAnimationEndCallback) { if (text == null) text = ""; CharSequence lastPendingMessage = mMessages.peekLast(); if (TextUtils.equals(lastPendingMessage, text) || (lastPendingMessage == null && TextUtils.equals(text, getText()))) { if (onAnimationEndCallback != null) { onAnimationEndCallback.run(); } return; } mMessages.add(text); mKeyguardIndicationInfo.add(indication); mMessage = text; mKeyguardIndicationInfo = indication; if (animate) { final boolean hasIcon = indication != null && indication.getIcon() != null; final AnimatorSet animator = new AnimatorSet(); AnimatorSet animator = new AnimatorSet(); // Make sure each animation is visible for a minimum amount of time, while not worrying // about fading in blank text long timeInMillis = System.currentTimeMillis(); long delay = Math.max(0, mNextAnimationTime - timeInMillis); setNextAnimationTime(timeInMillis + delay + getFadeOutDuration()); final long minDurationMillis = (indication != null && indication.getMinVisibilityMillis() != null) ? indication.getMinVisibilityMillis() : MSG_MIN_DURATION_MILLIS_DEFAULT; if (!text.equals("") || hasIcon) { setNextAnimationTime(mNextAnimationTime + minDurationMillis); if (!TextUtils.isEmpty(mMessage) || hasIcon) { Animator inAnimator = getInAnimator(); inAnimator.addListener(new AnimatorListenerAdapter() { @Override Loading @@ -164,7 +144,10 @@ public class KeyguardIndicationTextView extends TextView { animator.play(outAnimator); } animator.setStartDelay(delay); if (mLastAnimator != null) { mLastAnimator.cancel(); } mLastAnimator = animator; animator.start(); } else { setAlpha(1f); Loading @@ -173,6 +156,10 @@ public class KeyguardIndicationTextView extends TextView { if (onAnimationEndCallback != null) { onAnimationEndCallback.run(); } if (mLastAnimator != null) { mLastAnimator.cancel(); mLastAnimator = null; } } } Loading @@ -182,11 +169,21 @@ public class KeyguardIndicationTextView extends TextView { fadeOut.setDuration(getFadeOutDuration()); fadeOut.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN); fadeOut.addListener(new AnimatorListenerAdapter() { private boolean mCancelled = false; @Override public void onAnimationEnd(Animator animator) { super.onAnimationEnd(animator); if (!mCancelled) { setNextIndication(); } } @Override public void onAnimationCancel(Animator animator) { super.onAnimationCancel(animator); mCancelled = true; setAlpha(0); } }); Animator yTranslate = Loading @@ -198,20 +195,19 @@ public class KeyguardIndicationTextView extends TextView { } private void setNextIndication() { KeyguardIndication info = mKeyguardIndicationInfo.poll(); if (info != null) { if (mKeyguardIndicationInfo != null) { // First, update the style. // If a background is set on the text, we don't want shadow on the text if (info.getBackground() != null) { if (mKeyguardIndicationInfo.getBackground() != null) { setTextAppearance(sButtonStyleId); } else { setTextAppearance(sStyleId); } setBackground(info.getBackground()); setTextColor(info.getTextColor()); setOnClickListener(info.getClickListener()); setClickable(info.getClickListener() != null); final Drawable icon = info.getIcon(); setBackground(mKeyguardIndicationInfo.getBackground()); setTextColor(mKeyguardIndicationInfo.getTextColor()); setOnClickListener(mKeyguardIndicationInfo.getClickListener()); setClickable(mKeyguardIndicationInfo.getClickListener() != null); final Drawable icon = mKeyguardIndicationInfo.getIcon(); if (icon != null) { icon.setTint(getCurrentTextColor()); if (icon instanceof AnimatedVectorDrawable) { Loading @@ -220,7 +216,7 @@ public class KeyguardIndicationTextView extends TextView { } setCompoundDrawablesRelativeWithIntrinsicBounds(icon, null, null, null); } setText(mMessages.poll()); setText(mMessage); } private AnimatorSet getInAnimator() { Loading @@ -238,6 +234,7 @@ public class KeyguardIndicationTextView extends TextView { public void onAnimationCancel(Animator animation) { super.onAnimationCancel(animation); setTranslationY(0); setAlpha(1f); } }); animatorSet.playTogether(yTranslate, fadeIn); Loading Loading @@ -270,14 +267,6 @@ public class KeyguardIndicationTextView extends TextView { return 167L; } private void setNextAnimationTime(long time) { if (mAnimationsEnabled) { mNextAnimationTime = time; } else { mNextAnimationTime = 0L; } } private int getYTranslationPixels() { return mContext.getResources().getDimensionPixelSize( com.android.systemui.R.dimen.keyguard_indication_y_translation); Loading
packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewControllerTest.java +40 −3 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.systemui.keyguard; import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BATTERY; import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BIOMETRIC_MESSAGE; import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_DISCLOSURE; import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_OWNER_INFO; Loading Loading @@ -56,7 +57,8 @@ import org.mockito.MockitoAnnotations; public class KeyguardIndicationRotateTextViewControllerTest extends SysuiTestCase { private static final String TEST_MESSAGE = "test message"; private static final String TEST_MESSAGE_2 = "test message 2"; private static final String TEST_MESSAGE_2 = "test message two"; private int mMsgId = 0; @Mock private DelayableExecutor mExecutor; Loading Loading @@ -200,6 +202,24 @@ public class KeyguardIndicationRotateTextViewControllerTest extends SysuiTestCas verify(mExecutor).executeDelayed(any(), anyLong()); } @Test public void testSameMessage_noIndicationUpdate() { // GIVEN we are showing and indication with a test message mController.updateIndication( INDICATION_TYPE_OWNER_INFO, createIndication(TEST_MESSAGE), true); reset(mView); reset(mExecutor); // WHEN the same type tries to show the same exact message final KeyguardIndication sameIndication = createIndication(TEST_MESSAGE); mController.updateIndication( INDICATION_TYPE_OWNER_INFO, sameIndication, true); // THEN // - we don't update the indication b/c there's no reason the animate the same text verify(mView, never()).switchIndication(sameIndication); } @Test public void testTransientIndication() { // GIVEN we already have two indication messages Loading @@ -223,8 +243,11 @@ public class KeyguardIndicationRotateTextViewControllerTest extends SysuiTestCas @Test public void testHideIndicationOneMessage() { // GIVEN we have one indication message KeyguardIndication indication = createIndication(); mController.updateIndication( INDICATION_TYPE_OWNER_INFO, createIndication(), false); INDICATION_TYPE_OWNER_INFO, indication, false); verify(mView).switchIndication(indication); reset(mView); // WHEN we hide the current indication type mController.hideIndication(INDICATION_TYPE_OWNER_INFO); Loading Loading @@ -254,6 +277,10 @@ public class KeyguardIndicationRotateTextViewControllerTest extends SysuiTestCas @Test public void testStartDozing() { // GIVEN a biometric message is showing mController.updateIndication(INDICATION_TYPE_BIOMETRIC_MESSAGE, createIndication(), true); // WHEN the device is dozing mStatusBarStateListener.onDozingChanged(true); Loading Loading @@ -293,9 +320,19 @@ public class KeyguardIndicationRotateTextViewControllerTest extends SysuiTestCas verify(mView, never()).switchIndication(any()); } /** * Create an indication with a unique message. */ private KeyguardIndication createIndication() { return createIndication(TEST_MESSAGE + " " + mMsgId++); } /** * Create an indication with the given message. */ private KeyguardIndication createIndication(String msg) { return new KeyguardIndication.Builder() .setMessage(TEST_MESSAGE) .setMessage(msg) .setTextColor(ColorStateList.valueOf(Color.WHITE)) .build(); } Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java +20 −10 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE; import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ALIGNMENT; import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BATTERY; import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BIOMETRIC_MESSAGE; import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_DISCLOSURE; import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_OWNER_INFO; import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_RESTING; Loading Loading @@ -112,6 +113,8 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { private static final ComponentName DEVICE_OWNER_COMPONENT = new ComponentName("com.android.foo", "bar"); private static final int TEST_STRING_RES = R.string.keyguard_indication_trust_unlocked; private String mKeyguardTryFingerprintMsg; private String mDisclosureWithOrganization; private String mDisclosureGeneric; Loading Loading @@ -419,7 +422,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { // WHEN transient text is shown mStatusBarStateListener.onDozingChanged(true); mController.showTransientIndication("Test"); mController.showTransientIndication(TEST_STRING_RES); // THEN wake lock is held while the animation is running assertTrue("WakeLock expected: HELD, was: RELEASED", mWakeLock.isHeld()); Loading @@ -434,7 +437,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { // WHEN we show the transient indication mStatusBarStateListener.onDozingChanged(true); mController.showTransientIndication("Test"); mController.showTransientIndication(TEST_STRING_RES); // THEN wake lock is RELEASED, not held assertFalse("WakeLock expected: RELEASED, was: HELD", mWakeLock.isHeld()); Loading @@ -445,10 +448,11 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { createController(); mController.setVisible(true); mController.showTransientIndication("Test"); mController.showTransientIndication(TEST_STRING_RES); mStatusBarStateListener.onDozingChanged(true); assertThat(mTextView.getText()).isEqualTo("Test"); assertThat(mTextView.getText()).isEqualTo( mContext.getResources().getString(TEST_STRING_RES)); assertThat(mTextView.getCurrentTextColor()).isEqualTo(Color.WHITE); assertThat(mTextView.getAlpha()).isEqualTo(1f); } Loading @@ -462,11 +466,11 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { mController.getKeyguardCallback().onBiometricHelp( KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED, message, BiometricSourceType.FACE); verifyTransientMessage(message); verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, message); reset(mRotateTextViewController); mStatusBarStateListener.onDozingChanged(true); verifyHideIndication(INDICATION_TYPE_TRANSIENT); verifyHideIndication(INDICATION_TYPE_BIOMETRIC_MESSAGE); } @Test Loading @@ -478,7 +482,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { mController.getKeyguardCallback().onBiometricError(FaceManager.FACE_ERROR_TIMEOUT, "A message", BiometricSourceType.FACE); verifyTransientMessage(message); verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, message); mStatusBarStateListener.onDozingChanged(true); assertThat(mTextView.getText()).isNotEqualTo(message); Loading @@ -497,7 +501,8 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { FingerprintManager.FINGERPRINT_ERROR_CANCELED, "bar", BiometricSourceType.FINGERPRINT); verifyNoTransientMessage(); verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE); verifyNoMessage(INDICATION_TYPE_TRANSIENT); } @Test Loading Loading @@ -757,7 +762,12 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase { verify(mRotateTextViewController).showTransient(eq(message)); } private void verifyNoTransientMessage() { verify(mRotateTextViewController, never()).showTransient(any()); private void verifyNoMessage(int type) { if (type == INDICATION_TYPE_TRANSIENT) { verify(mRotateTextViewController, never()).showTransient(anyString()); } else { verify(mRotateTextViewController, never()).updateIndication(eq(type), anyObject(), anyBoolean()); } } }