Merge "KeyguardRotateController handles minimum show time" into sc-v2-dev

This commit is contained in:
Beverly Tai
2021-12-01 20:29:03 +00:00
committed by Android (Google) Code Review
5 changed files with 310 additions and 140 deletions

View File

@@ -19,6 +19,7 @@ package com.android.systemui.keyguard;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.content.res.ColorStateList; import android.content.res.ColorStateList;
import android.graphics.Color; import android.graphics.Color;
import android.os.SystemClock;
import android.text.TextUtils; import android.text.TextUtils;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
@@ -40,13 +41,24 @@ import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
* Rotates through messages to show on the keyguard bottom area on the lock screen * Animates 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. * 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 public class KeyguardIndicationRotateTextViewController extends
ViewController<KeyguardIndicationTextView> implements Dumpable { ViewController<KeyguardIndicationTextView> implements Dumpable {
public static String TAG = "KgIndicationRotatingCtrl"; public static String TAG = "KgIndicationRotatingCtrl";
private static final long DEFAULT_INDICATION_SHOW_LENGTH = 3500; // milliseconds 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 StatusBarStateController mStatusBarStateController;
private final float mMaxAlpha; private final float mMaxAlpha;
@@ -62,6 +74,8 @@ public class KeyguardIndicationRotateTextViewController extends
// List of indication types to show. The next indication to show is always at index 0 // List of indication types to show. The next indication to show is always at index 0
private final List<Integer> mIndicationQueue = new LinkedList<>(); private final List<Integer> mIndicationQueue = new LinkedList<>();
private @IndicationType int mCurrIndicationType = INDICATION_TYPE_NONE; private @IndicationType int mCurrIndicationType = INDICATION_TYPE_NONE;
private CharSequence mCurrMessage;
private long mLastIndicationSwitch;
private boolean mIsDozing; private boolean mIsDozing;
@@ -94,17 +108,19 @@ public class KeyguardIndicationRotateTextViewController extends
* Update the indication type with the given String. * Update the indication type with the given String.
* @param type of indication * @param type of indication
* @param newIndication message to associate with this indication type * @param newIndication message to associate with this indication type
* @param showImmediately if true: shows this indication message immediately. Else, the text * @param showAsap if true: shows this indication message as soon as possible. If false,
* associated with this type is updated and will show when its turn in * the text associated with this type is updated and will show when its turn
* the IndicationQueue comes around. * in the IndicationQueue comes around.
*/ */
public void updateIndication(@IndicationType int type, KeyguardIndication newIndication, public void updateIndication(@IndicationType int type, KeyguardIndication newIndication,
boolean updateImmediately) { boolean showAsap) {
if (type == INDICATION_TYPE_REVERSE_CHARGING) { if (type == INDICATION_TYPE_REVERSE_CHARGING) {
// temporarily don't show here, instead use AmbientContainer b/181049781 // temporarily don't show here, instead use AmbientContainer b/181049781
return; 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; final boolean hasNewIndication = newIndication != null;
if (!hasNewIndication) { if (!hasNewIndication) {
mIndicationMessages.remove(type); mIndicationMessages.remove(type);
@@ -121,26 +137,47 @@ public class KeyguardIndicationRotateTextViewController extends
return; return;
} }
final boolean showNow = updateImmediately long currTime = SystemClock.uptimeMillis();
|| mCurrIndicationType == INDICATION_TYPE_NONE long timeSinceLastIndicationSwitch = currTime - mLastIndicationSwitch;
|| mCurrIndicationType == type; boolean currMsgShownForMinTime = timeSinceLastIndicationSwitch >= minShowDuration;
if (hasNewIndication) { if (hasNewIndication) {
if (showNow) { if (mCurrIndicationType == INDICATION_TYPE_NONE || mCurrIndicationType == type) {
showIndication(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()) { } 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; return;
} }
// current indication is updated to empty
if (mCurrIndicationType == type if (mCurrIndicationType == type
&& !hasNewIndication && !hasNewIndication
&& updateImmediately) { && showAsap) {
if (currMsgShownForMinTime) {
if (mShowNextIndicationRunnable != null) { if (mShowNextIndicationRunnable != null) {
mShowNextIndicationRunnable.runImmediately(); mShowNextIndicationRunnable.runImmediately();
} else { } else {
showIndication(INDICATION_TYPE_NONE); showIndication(INDICATION_TYPE_NONE);
} }
} else {
scheduleShowNextIndication(minShowDuration - timeSinceLastIndicationSwitch);
}
} }
} }
@@ -164,11 +201,10 @@ public class KeyguardIndicationRotateTextViewController extends
* - will continue to be in the rotation of messages shown until hideTransient is called. * - will continue to be in the rotation of messages shown until hideTransient is called.
*/ */
public void showTransient(CharSequence newIndication) { public void showTransient(CharSequence newIndication) {
final long inAnimationDuration = 600L; // see KeyguardIndicationTextView.getYInDuration
updateIndication(INDICATION_TYPE_TRANSIENT, updateIndication(INDICATION_TYPE_TRANSIENT,
new KeyguardIndication.Builder() new KeyguardIndication.Builder()
.setMessage(newIndication) .setMessage(newIndication)
.setMinVisibilityMillis(2000L + inAnimationDuration) .setMinVisibilityMillis(IMPORTANT_MSG_MIN_DURATION)
.setTextColor(mInitialTextColorState) .setTextColor(mInitialTextColorState)
.build(), .build(),
/* showImmediately */true); /* showImmediately */true);
@@ -188,6 +224,15 @@ public class KeyguardIndicationRotateTextViewController extends
return mIndicationMessages.keySet().size() > 0; 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. * 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 * Will re-add this indication to be re-shown after all other indications have been
@@ -196,27 +241,52 @@ public class KeyguardIndicationRotateTextViewController extends
private void showIndication(@IndicationType int type) { private void showIndication(@IndicationType int type) {
cancelScheduledIndication(); cancelScheduledIndication();
final CharSequence previousMessage = mCurrMessage;
final @IndicationType int previousIndicationType = mCurrIndicationType;
mCurrIndicationType = type; mCurrIndicationType = type;
mCurrMessage = mIndicationMessages.get(type) != null
? mIndicationMessages.get(type).getMessage()
: null;
mIndicationQueue.removeIf(x -> x == type); mIndicationQueue.removeIf(x -> x == type);
if (mCurrIndicationType != INDICATION_TYPE_NONE) { if (mCurrIndicationType != INDICATION_TYPE_NONE) {
mIndicationQueue.add(type); // re-add to show later mIndicationQueue.add(type); // re-add to show later
} }
mLastIndicationSwitch = SystemClock.uptimeMillis();
if (!TextUtils.equals(previousMessage, mCurrMessage)
|| previousIndicationType != mCurrIndicationType) {
mView.switchIndication(mIndicationMessages.get(type)); mView.switchIndication(mIndicationMessages.get(type));
}
// only schedule next indication if there's more than just this indication in the queue // only schedule next indication if there's more than just this indication in the queue
if (mCurrIndicationType != INDICATION_TYPE_NONE && mIndicationQueue.size() > 1) { 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() { protected boolean isNextIndicationScheduled() {
return mShowNextIndicationRunnable != null; return mShowNextIndicationRunnable != null;
} }
private void scheduleShowNextIndication() {
private void scheduleShowNextIndication(long msUntilShowNextMsg) {
cancelScheduledIndication(); cancelScheduledIndication();
mShowNextIndicationRunnable = new ShowNextIndication(DEFAULT_INDICATION_SHOW_LENGTH); mShowNextIndicationRunnable = new ShowNextIndication(msUntilShowNextMsg);
} }
private void cancelScheduledIndication() { private void cancelScheduledIndication() {
@@ -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; static final int INDICATION_TYPE_NONE = -1;
public static final int INDICATION_TYPE_OWNER_INFO = 0; public static final int INDICATION_TYPE_OWNER_INFO = 0;
public static final int INDICATION_TYPE_DISCLOSURE = 1; public static final int INDICATION_TYPE_DISCLOSURE = 1;
public static final int INDICATION_TYPE_LOGOUT = 2; public static final int INDICATION_TYPE_LOGOUT = 2;
@@ -303,6 +375,7 @@ public class KeyguardIndicationRotateTextViewController extends
public static final int INDICATION_TYPE_RESTING = 7; public static final int INDICATION_TYPE_RESTING = 7;
public static final int INDICATION_TYPE_USER_LOCKED = 8; public static final int INDICATION_TYPE_USER_LOCKED = 8;
public static final int INDICATION_TYPE_REVERSE_CHARGING = 10; public static final int INDICATION_TYPE_REVERSE_CHARGING = 10;
public static final int INDICATION_TYPE_BIOMETRIC_MESSAGE = 11;
@IntDef({ @IntDef({
INDICATION_TYPE_NONE, INDICATION_TYPE_NONE,
@@ -316,6 +389,7 @@ public class KeyguardIndicationRotateTextViewController extends
INDICATION_TYPE_RESTING, INDICATION_TYPE_RESTING,
INDICATION_TYPE_USER_LOCKED, INDICATION_TYPE_USER_LOCKED,
INDICATION_TYPE_REVERSE_CHARGING, INDICATION_TYPE_REVERSE_CHARGING,
INDICATION_TYPE_BIOMETRIC_MESSAGE
}) })
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
public @interface IndicationType{} public @interface IndicationType{}

View File

@@ -21,8 +21,10 @@ import static android.view.View.GONE;
import static android.view.View.VISIBLE; import static android.view.View.VISIBLE;
import static com.android.systemui.DejankUtils.whitelistIpcs; import static com.android.systemui.DejankUtils.whitelistIpcs;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.IMPORTANT_MSG_MIN_DURATION;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ALIGNMENT; 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_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_DISCLOSURE;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_LOGOUT; import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_LOGOUT;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_OWNER_INFO; import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_OWNER_INFO;
@@ -94,6 +96,15 @@ import javax.inject.Inject;
/** /**
* Controls the indications and error messages shown on the Keyguard * Controls the indications and error messages shown on the Keyguard
*
* On AoD, only one message shows with the following priorities:
* 1. Biometric
* 2. Transient
* 3. Charging alignment
* 4. Battery information
*
* On the lock screen, message rotate through different message types.
* See {@link KeyguardIndicationRotateTextViewController.IndicationType} for the list of types.
*/ */
@SysUISingleton @SysUISingleton
public class KeyguardIndicationController { public class KeyguardIndicationController {
@@ -103,6 +114,7 @@ public class KeyguardIndicationController {
private static final int MSG_HIDE_TRANSIENT = 1; private static final int MSG_HIDE_TRANSIENT = 1;
private static final int MSG_SHOW_ACTION_TO_UNLOCK = 2; private static final int MSG_SHOW_ACTION_TO_UNLOCK = 2;
private static final int MSG_HIDE_BIOMETRIC_MESSAGE = 3;
private static final long TRANSIENT_BIOMETRIC_ERROR_TIMEOUT = 1300; private static final long TRANSIENT_BIOMETRIC_ERROR_TIMEOUT = 1300;
private static final float BOUNCE_ANIMATION_FINAL_Y = 0f; private static final float BOUNCE_ANIMATION_FINAL_Y = 0f;
@@ -132,9 +144,9 @@ public class KeyguardIndicationController {
private String mRestingIndication; private String mRestingIndication;
private String mAlignmentIndication; private String mAlignmentIndication;
private CharSequence mTransientIndication; private CharSequence mTransientIndication;
private CharSequence mBiometricMessage;
protected ColorStateList mInitialTextColorState; protected ColorStateList mInitialTextColorState;
private boolean mVisible; private boolean mVisible;
private boolean mHideTransientMessageOnScreenOff;
private boolean mPowerPluggedIn; private boolean mPowerPluggedIn;
private boolean mPowerPluggedInWired; private boolean mPowerPluggedInWired;
@@ -277,13 +289,15 @@ public class KeyguardIndicationController {
} }
/** /**
* Doesn't include disclosure which gets triggered separately. * Doesn't include disclosure (also a persistent indication) which gets triggered separately.
*
* This method also doesn't update transient messages like biometrics since those messages
* are also updated separately.
*/ */
private void updateIndications(boolean animate, int userId) { private void updatePersistentIndications(boolean animate, int userId) {
updateOwnerInfo(); updateOwnerInfo();
updateBattery(animate); updateBattery(animate);
updateUserLocked(userId); updateUserLocked(userId);
updateTransient();
updateTrust(userId, getTrustGrantedIndication(), getTrustManagedIndication()); updateTrust(userId, getTrustGrantedIndication(), getTrustManagedIndication());
updateAlignment(); updateAlignment();
updateLogoutView(); updateLogoutView();
@@ -383,12 +397,36 @@ public class KeyguardIndicationController {
} }
} }
private void updateBiometricMessage() {
if (!TextUtils.isEmpty(mBiometricMessage)) {
mRotateTextViewController.updateIndication(
INDICATION_TYPE_BIOMETRIC_MESSAGE,
new KeyguardIndication.Builder()
.setMessage(mBiometricMessage)
.setMinVisibilityMillis(IMPORTANT_MSG_MIN_DURATION)
.setTextColor(mInitialTextColorState)
.build(),
true
);
} else {
mRotateTextViewController.hideIndication(INDICATION_TYPE_BIOMETRIC_MESSAGE);
}
if (mDozing) {
updateIndication(false);
}
}
private void updateTransient() { private void updateTransient() {
if (!TextUtils.isEmpty(mTransientIndication)) { if (!TextUtils.isEmpty(mTransientIndication)) {
mRotateTextViewController.showTransient(mTransientIndication); mRotateTextViewController.showTransient(mTransientIndication);
} else { } else {
mRotateTextViewController.hideTransient(); mRotateTextViewController.hideTransient();
} }
if (mDozing) {
updateIndication(false);
}
} }
private void updateTrust(int userId, CharSequence trustGrantedIndication, private void updateTrust(int userId, CharSequence trustGrantedIndication,
@@ -576,6 +614,14 @@ public class KeyguardIndicationController {
mHandler.obtainMessage(MSG_HIDE_TRANSIENT), delayMs); mHandler.obtainMessage(MSG_HIDE_TRANSIENT), delayMs);
} }
/**
* Hides biometric indication in {@param delayMs}.
*/
public void hideBiometricMessageDelayed(long delayMs) {
mHandler.sendMessageDelayed(
mHandler.obtainMessage(MSG_HIDE_BIOMETRIC_MESSAGE), delayMs);
}
/** /**
* Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}. * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
*/ */
@@ -586,23 +632,40 @@ public class KeyguardIndicationController {
/** /**
* Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}. * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
*/ */
public void showTransientIndication(CharSequence transientIndication) { private void showTransientIndication(CharSequence transientIndication) {
showTransientIndication(transientIndication, false /* isError */, mTransientIndication = transientIndication;
false /* hideOnScreenOff */); mHandler.removeMessages(MSG_HIDE_TRANSIENT);
hideTransientIndicationDelayed(BaseKeyguardCallback.HIDE_DELAY_MS);
updateTransient();
} }
/** /**
* Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}. * Shows {@param biometricMessage} until it is hidden by {@link #hideBiometricMessage}.
*/ */
private void showTransientIndication(CharSequence transientIndication, public void showBiometricMessage(int biometricMessage) {
boolean isError, boolean hideOnScreenOff) { showBiometricMessage(mContext.getResources().getString(biometricMessage));
mTransientIndication = transientIndication; }
mHideTransientMessageOnScreenOff = hideOnScreenOff && transientIndication != null;
mHandler.removeMessages(MSG_HIDE_TRANSIENT);
mHandler.removeMessages(MSG_SHOW_ACTION_TO_UNLOCK);
hideTransientIndicationDelayed(BaseKeyguardCallback.HIDE_DELAY_MS);
updateIndication(false); /**
* Shows {@param biometricMessage} until it is hidden by {@link #hideBiometricMessage}.
*/
private void showBiometricMessage(CharSequence biometricMessage) {
mBiometricMessage = biometricMessage;
mHandler.removeMessages(MSG_SHOW_ACTION_TO_UNLOCK);
mHandler.removeMessages(MSG_HIDE_BIOMETRIC_MESSAGE);
hideBiometricMessageDelayed(BaseKeyguardCallback.HIDE_DELAY_MS);
updateBiometricMessage();
}
private void hideBiometricMessage() {
if (mBiometricMessage != null) {
mBiometricMessage = null;
mHandler.removeMessages(MSG_HIDE_BIOMETRIC_MESSAGE);
updateBiometricMessage();
}
} }
/** /**
@@ -611,10 +674,8 @@ public class KeyguardIndicationController {
public void hideTransientIndication() { public void hideTransientIndication() {
if (mTransientIndication != null) { if (mTransientIndication != null) {
mTransientIndication = null; mTransientIndication = null;
mHideTransientMessageOnScreenOff = false;
mHandler.removeMessages(MSG_HIDE_TRANSIENT); mHandler.removeMessages(MSG_HIDE_TRANSIENT);
mRotateTextViewController.hideTransient(); updateTransient();
updateIndication(false);
} }
} }
@@ -635,7 +696,11 @@ public class KeyguardIndicationController {
// When dozing we ignore any text color and use white instead, because // When dozing we ignore any text color and use white instead, because
// colors can be hard to read in low brightness. // colors can be hard to read in low brightness.
mTopIndicationView.setTextColor(Color.WHITE); mTopIndicationView.setTextColor(Color.WHITE);
if (!TextUtils.isEmpty(mTransientIndication)) { if (!TextUtils.isEmpty(mBiometricMessage)) {
mWakeLock.setAcquired(true);
mTopIndicationView.switchIndication(mBiometricMessage, null,
true, () -> mWakeLock.setAcquired(false));
} else if (!TextUtils.isEmpty(mTransientIndication)) {
mWakeLock.setAcquired(true); mWakeLock.setAcquired(true);
mTopIndicationView.switchIndication(mTransientIndication, null, mTopIndicationView.switchIndication(mTransientIndication, null,
true, () -> mWakeLock.setAcquired(false)); true, () -> mWakeLock.setAcquired(false));
@@ -669,7 +734,7 @@ public class KeyguardIndicationController {
mTopIndicationView.setVisibility(GONE); mTopIndicationView.setVisibility(GONE);
mTopIndicationView.setText(null); mTopIndicationView.setText(null);
mLockScreenIndicationView.setVisibility(View.VISIBLE); mLockScreenIndicationView.setVisibility(View.VISIBLE);
updateIndications(animate, KeyguardUpdateMonitor.getCurrentUser()); updatePersistentIndications(animate, KeyguardUpdateMonitor.getCurrentUser());
} }
// animates textView - textView moves up and bounces down // animates textView - textView moves up and bounces down
@@ -798,6 +863,8 @@ public class KeyguardIndicationController {
hideTransientIndication(); hideTransientIndication();
} else if (msg.what == MSG_SHOW_ACTION_TO_UNLOCK) { } else if (msg.what == MSG_SHOW_ACTION_TO_UNLOCK) {
showActionToUnlock(); showActionToUnlock();
} else if (msg.what == MSG_HIDE_BIOMETRIC_MESSAGE) {
hideBiometricMessage();
} }
} }
}; };
@@ -820,8 +887,7 @@ public class KeyguardIndicationController {
mStatusBarKeyguardViewManager.showBouncerMessage(message, mInitialTextColorState); mStatusBarKeyguardViewManager.showBouncerMessage(message, mInitialTextColorState);
} }
} else { } else {
showTransientIndication(mContext.getString(R.string.keyguard_unlock), showBiometricMessage(mContext.getString(R.string.keyguard_unlock));
false /* isError */, true /* hideOnScreenOff */);
} }
} }
@@ -830,15 +896,15 @@ public class KeyguardIndicationController {
// if udfps available, there will always be a tappable affordance to unlock // if udfps available, there will always be a tappable affordance to unlock
// For example, the lock icon // For example, the lock icon
if (mKeyguardBypassController.getUserHasDeviceEntryIntent()) { if (mKeyguardBypassController.getUserHasDeviceEntryIntent()) {
showTransientIndication(R.string.keyguard_unlock_press); showBiometricMessage(R.string.keyguard_unlock_press);
} else if (msgId == FaceManager.FACE_ERROR_LOCKOUT_PERMANENT) { } else if (msgId == FaceManager.FACE_ERROR_LOCKOUT_PERMANENT) {
// since face is locked out, simply show "try fingerprint" // since face is locked out, simply show "try fingerprint"
showTransientIndication(R.string.keyguard_try_fingerprint); showBiometricMessage(R.string.keyguard_try_fingerprint);
} else { } else {
showTransientIndication(R.string.keyguard_face_failed_use_fp); showBiometricMessage(R.string.keyguard_face_failed_use_fp);
} }
} else { } else {
showTransientIndication(R.string.keyguard_try_fingerprint); showBiometricMessage(R.string.keyguard_try_fingerprint);
} }
// Although we suppress face auth errors visually, we still announce them for a11y // Although we suppress face auth errors visually, we still announce them for a11y
@@ -857,6 +923,8 @@ public class KeyguardIndicationController {
pw.println(" mChargingWattage: " + mChargingWattage); pw.println(" mChargingWattage: " + mChargingWattage);
pw.println(" mMessageToShowOnScreenOn: " + mMessageToShowOnScreenOn); pw.println(" mMessageToShowOnScreenOn: " + mMessageToShowOnScreenOn);
pw.println(" mDozing: " + mDozing); pw.println(" mDozing: " + mDozing);
pw.println(" mTransientIndication: " + mTransientIndication);
pw.println(" mBiometricMessage: " + mBiometricMessage);
pw.println(" mBatteryLevel: " + mBatteryLevel); pw.println(" mBatteryLevel: " + mBatteryLevel);
pw.println(" mBatteryPresent: " + mBatteryPresent); pw.println(" mBatteryPresent: " + mBatteryPresent);
pw.println(" mTextView.getText(): " + ( pw.println(" mTextView.getText(): " + (
@@ -871,7 +939,7 @@ public class KeyguardIndicationController {
@Override @Override
public void onRefreshBatteryInfo(BatteryStatus status) { public void onRefreshBatteryInfo(BatteryStatus status) {
boolean isChargingOrFull = status.status == BatteryManager.BATTERY_STATUS_CHARGING boolean isChargingOrFull = status.status == BatteryManager.BATTERY_STATUS_CHARGING
|| status.status == BatteryManager.BATTERY_STATUS_FULL; || status.isCharged();
boolean wasPluggedIn = mPowerPluggedIn; boolean wasPluggedIn = mPowerPluggedIn;
mPowerPluggedInWired = status.isPluggedInWired() && isChargingOrFull; mPowerPluggedInWired = status.isPluggedInWired() && isChargingOrFull;
mPowerPluggedInWireless = status.isPluggedInWireless() && isChargingOrFull; mPowerPluggedInWireless = status.isPluggedInWireless() && isChargingOrFull;
@@ -912,7 +980,6 @@ public class KeyguardIndicationController {
.isUnlockingWithBiometricAllowed(true /* isStrongBiometric */)) { .isUnlockingWithBiometricAllowed(true /* isStrongBiometric */)) {
return; return;
} }
boolean showActionToUnlock = boolean showActionToUnlock =
msgId == KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED; msgId == KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
if (mStatusBarKeyguardViewManager.isBouncerShowing()) { if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
@@ -921,14 +988,10 @@ public class KeyguardIndicationController {
} else if (mKeyguardUpdateMonitor.isScreenOn()) { } else if (mKeyguardUpdateMonitor.isScreenOn()) {
if (biometricSourceType == BiometricSourceType.FACE if (biometricSourceType == BiometricSourceType.FACE
&& shouldSuppressFaceMsgAndShowTryFingerprintMsg()) { && shouldSuppressFaceMsgAndShowTryFingerprintMsg()) {
// don't show any help messages, b/c they can come in right before a success showTryFingerprintMsg(msgId, helpString);
// However, continue to announce help messages for a11y
if (!TextUtils.isEmpty(helpString)) {
mLockScreenIndicationView.announceForAccessibility(helpString);
}
return; return;
} }
showTransientIndication(helpString, false /* isError */, showActionToUnlock); showBiometricMessage(helpString);
} else if (showActionToUnlock) { } else if (showActionToUnlock) {
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SHOW_ACTION_TO_UNLOCK), mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_SHOW_ACTION_TO_UNLOCK),
TRANSIENT_BIOMETRIC_ERROR_TIMEOUT); TRANSIENT_BIOMETRIC_ERROR_TIMEOUT);
@@ -967,8 +1030,7 @@ public class KeyguardIndicationController {
} else if (mStatusBarKeyguardViewManager.isBouncerShowing()) { } else if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
mStatusBarKeyguardViewManager.showBouncerMessage(errString, mInitialTextColorState); mStatusBarKeyguardViewManager.showBouncerMessage(errString, mInitialTextColorState);
} else if (mKeyguardUpdateMonitor.isScreenOn()) { } else if (mKeyguardUpdateMonitor.isScreenOn()) {
showTransientIndication(errString, /* isError */ true, showBiometricMessage(errString);
/* hideOnScreenOff */ true);
} else { } else {
mMessageToShowOnScreenOn = errString; mMessageToShowOnScreenOn = errString;
} }
@@ -1014,16 +1076,15 @@ public class KeyguardIndicationController {
@Override @Override
public void onTrustAgentErrorMessage(CharSequence message) { public void onTrustAgentErrorMessage(CharSequence message) {
showTransientIndication(message, true /* isError */, false /* hideOnScreenOff */); showBiometricMessage(message);
} }
@Override @Override
public void onScreenTurnedOn() { public void onScreenTurnedOn() {
if (mMessageToShowOnScreenOn != null) { if (mMessageToShowOnScreenOn != null) {
showTransientIndication(mMessageToShowOnScreenOn, true /* isError */, showBiometricMessage(mMessageToShowOnScreenOn);
false /* hideOnScreenOff */);
// We want to keep this message around in case the screen was off // We want to keep this message around in case the screen was off
hideTransientIndicationDelayed(HIDE_DELAY_MS); hideBiometricMessageDelayed(HIDE_DELAY_MS);
mMessageToShowOnScreenOn = null; mMessageToShowOnScreenOn = null;
} }
} }
@@ -1034,7 +1095,7 @@ public class KeyguardIndicationController {
if (running && biometricSourceType == BiometricSourceType.FACE) { if (running && biometricSourceType == BiometricSourceType.FACE) {
// Let's hide any previous messages when authentication starts, otherwise // Let's hide any previous messages when authentication starts, otherwise
// multiple auth attempts would overlap. // multiple auth attempts would overlap.
hideTransientIndication(); hideBiometricMessage();
mMessageToShowOnScreenOn = null; mMessageToShowOnScreenOn = null;
} }
} }
@@ -1043,11 +1104,11 @@ public class KeyguardIndicationController {
public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType, public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType,
boolean isStrongBiometric) { boolean isStrongBiometric) {
super.onBiometricAuthenticated(userId, biometricSourceType, isStrongBiometric); super.onBiometricAuthenticated(userId, biometricSourceType, isStrongBiometric);
mHandler.sendEmptyMessage(MSG_HIDE_TRANSIENT); hideBiometricMessage();
if (biometricSourceType == BiometricSourceType.FACE if (biometricSourceType == BiometricSourceType.FACE
&& !mKeyguardBypassController.canBypass()) { && !mKeyguardBypassController.canBypass()) {
mHandler.sendEmptyMessage(MSG_SHOW_ACTION_TO_UNLOCK); showActionToUnlock();
} }
} }
@@ -1074,8 +1135,7 @@ public class KeyguardIndicationController {
@Override @Override
public void onRequireUnlockForNfc() { public void onRequireUnlockForNfc() {
showTransientIndication(mContext.getString(R.string.require_unlock_for_nfc), showTransientIndication(mContext.getString(R.string.require_unlock_for_nfc));
false /* isError */, false /* hideOnScreenOff */);
hideTransientIndicationDelayed(HIDE_DELAY_MS); hideTransientIndicationDelayed(HIDE_DELAY_MS);
} }
} }
@@ -1094,8 +1154,8 @@ public class KeyguardIndicationController {
} }
mDozing = dozing; mDozing = dozing;
if (mHideTransientMessageOnScreenOff && mDozing) { if (mDozing) {
hideTransientIndication(); hideBiometricMessage();
} }
updateIndication(false); updateIndication(false);
} }
@@ -1112,7 +1172,7 @@ public class KeyguardIndicationController {
public void onKeyguardShowingChanged() { public void onKeyguardShowingChanged() {
if (!mKeyguardStateController.isShowing()) { if (!mKeyguardStateController.isShowing()) {
mTopIndicationView.clearMessages(); mTopIndicationView.clearMessages();
mLockScreenIndicationView.clearMessages(); mRotateTextViewController.clearMessages();
} }
} }
}; };

View File

@@ -35,23 +35,20 @@ import com.android.systemui.R;
import com.android.systemui.animation.Interpolators; import com.android.systemui.animation.Interpolators;
import com.android.systemui.keyguard.KeyguardIndication; 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"). * A view to show hints on Keyguard ("Swipe up to unlock", "Tap again to open").
*/ */
public class KeyguardIndicationTextView extends TextView { public class KeyguardIndicationTextView extends TextView {
private static final long MSG_MIN_DURATION_MILLIS_DEFAULT = 1500;
@StyleRes @StyleRes
private static int sStyleId = R.style.TextAppearance_Keyguard_BottomArea; private static int sStyleId = R.style.TextAppearance_Keyguard_BottomArea;
@StyleRes @StyleRes
private static int sButtonStyleId = R.style.TextAppearance_Keyguard_BottomArea_Button; private static int sButtonStyleId = R.style.TextAppearance_Keyguard_BottomArea_Button;
private long mNextAnimationTime = 0;
private boolean mAnimationsEnabled = true; private boolean mAnimationsEnabled = true;
private LinkedList<CharSequence> mMessages = new LinkedList<>(); private CharSequence mMessage;
private LinkedList<KeyguardIndication> mKeyguardIndicationInfo = new LinkedList<>(); private KeyguardIndication mKeyguardIndicationInfo;
private Animator mLastAnimator;
public KeyguardIndicationTextView(Context context) { public KeyguardIndicationTextView(Context context) {
super(context); super(context);
@@ -71,22 +68,24 @@ public class KeyguardIndicationTextView extends TextView {
} }
/** /**
* Clears message queue. * Clears message queue and currently shown message.
*/ */
public void clearMessages() { public void clearMessages() {
mMessages.clear(); if (mLastAnimator != null) {
mKeyguardIndicationInfo.clear(); 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) { public void switchIndication(int textResId) {
switchIndication(getResources().getText(textResId), null); 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. * @param indication The text to show.
*/ */
@@ -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) { public void switchIndication(CharSequence text, KeyguardIndication indication) {
switchIndication(text, indication, true, null); switchIndication(text, indication, true, null);
} }
/** /**
* Changes the text with an optional animation. For animating text, makes sure a single * Updates the text with an optional animation.
* indication is shown long enough.
* *
* @param text The text to show. * @param text The text to show.
* @param indication optional display information for the text * @param indication optional display information for the text
@@ -112,33 +110,15 @@ public class KeyguardIndicationTextView extends TextView {
*/ */
public void switchIndication(CharSequence text, KeyguardIndication indication, public void switchIndication(CharSequence text, KeyguardIndication indication,
boolean animate, Runnable onAnimationEndCallback) { boolean animate, Runnable onAnimationEndCallback) {
if (text == null) text = ""; mMessage = text;
mKeyguardIndicationInfo = indication;
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);
if (animate) { if (animate) {
final boolean hasIcon = indication != null && indication.getIcon() != null; 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 // Make sure each animation is visible for a minimum amount of time, while not worrying
// about fading in blank text // about fading in blank text
long timeInMillis = System.currentTimeMillis(); if (!TextUtils.isEmpty(mMessage) || hasIcon) {
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);
Animator inAnimator = getInAnimator(); Animator inAnimator = getInAnimator();
inAnimator.addListener(new AnimatorListenerAdapter() { inAnimator.addListener(new AnimatorListenerAdapter() {
@Override @Override
@@ -164,7 +144,10 @@ public class KeyguardIndicationTextView extends TextView {
animator.play(outAnimator); animator.play(outAnimator);
} }
animator.setStartDelay(delay); if (mLastAnimator != null) {
mLastAnimator.cancel();
}
mLastAnimator = animator;
animator.start(); animator.start();
} else { } else {
setAlpha(1f); setAlpha(1f);
@@ -173,6 +156,10 @@ public class KeyguardIndicationTextView extends TextView {
if (onAnimationEndCallback != null) { if (onAnimationEndCallback != null) {
onAnimationEndCallback.run(); onAnimationEndCallback.run();
} }
if (mLastAnimator != null) {
mLastAnimator.cancel();
mLastAnimator = null;
}
} }
} }
@@ -182,11 +169,21 @@ public class KeyguardIndicationTextView extends TextView {
fadeOut.setDuration(getFadeOutDuration()); fadeOut.setDuration(getFadeOutDuration());
fadeOut.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN); fadeOut.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
fadeOut.addListener(new AnimatorListenerAdapter() { fadeOut.addListener(new AnimatorListenerAdapter() {
private boolean mCancelled = false;
@Override @Override
public void onAnimationEnd(Animator animator) { public void onAnimationEnd(Animator animator) {
super.onAnimationEnd(animator); super.onAnimationEnd(animator);
if (!mCancelled) {
setNextIndication(); setNextIndication();
} }
}
@Override
public void onAnimationCancel(Animator animator) {
super.onAnimationCancel(animator);
mCancelled = true;
setAlpha(0);
}
}); });
Animator yTranslate = Animator yTranslate =
@@ -198,20 +195,19 @@ public class KeyguardIndicationTextView extends TextView {
} }
private void setNextIndication() { private void setNextIndication() {
KeyguardIndication info = mKeyguardIndicationInfo.poll(); if (mKeyguardIndicationInfo != null) {
if (info != null) {
// First, update the style. // First, update the style.
// If a background is set on the text, we don't want shadow on the text // 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); setTextAppearance(sButtonStyleId);
} else { } else {
setTextAppearance(sStyleId); setTextAppearance(sStyleId);
} }
setBackground(info.getBackground()); setBackground(mKeyguardIndicationInfo.getBackground());
setTextColor(info.getTextColor()); setTextColor(mKeyguardIndicationInfo.getTextColor());
setOnClickListener(info.getClickListener()); setOnClickListener(mKeyguardIndicationInfo.getClickListener());
setClickable(info.getClickListener() != null); setClickable(mKeyguardIndicationInfo.getClickListener() != null);
final Drawable icon = info.getIcon(); final Drawable icon = mKeyguardIndicationInfo.getIcon();
if (icon != null) { if (icon != null) {
icon.setTint(getCurrentTextColor()); icon.setTint(getCurrentTextColor());
if (icon instanceof AnimatedVectorDrawable) { if (icon instanceof AnimatedVectorDrawable) {
@@ -220,7 +216,7 @@ public class KeyguardIndicationTextView extends TextView {
} }
setCompoundDrawablesRelativeWithIntrinsicBounds(icon, null, null, null); setCompoundDrawablesRelativeWithIntrinsicBounds(icon, null, null, null);
} }
setText(mMessages.poll()); setText(mMessage);
} }
private AnimatorSet getInAnimator() { private AnimatorSet getInAnimator() {
@@ -238,6 +234,7 @@ public class KeyguardIndicationTextView extends TextView {
public void onAnimationCancel(Animator animation) { public void onAnimationCancel(Animator animation) {
super.onAnimationCancel(animation); super.onAnimationCancel(animation);
setTranslationY(0); setTranslationY(0);
setAlpha(1f);
} }
}); });
animatorSet.playTogether(yTranslate, fadeIn); animatorSet.playTogether(yTranslate, fadeIn);
@@ -270,14 +267,6 @@ public class KeyguardIndicationTextView extends TextView {
return 167L; return 167L;
} }
private void setNextAnimationTime(long time) {
if (mAnimationsEnabled) {
mNextAnimationTime = time;
} else {
mNextAnimationTime = 0L;
}
}
private int getYTranslationPixels() { private int getYTranslationPixels() {
return mContext.getResources().getDimensionPixelSize( return mContext.getResources().getDimensionPixelSize(
com.android.systemui.R.dimen.keyguard_indication_y_translation); com.android.systemui.R.dimen.keyguard_indication_y_translation);

View File

@@ -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_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_DISCLOSURE;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_OWNER_INFO; import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_OWNER_INFO;
@@ -56,7 +57,8 @@ import org.mockito.MockitoAnnotations;
public class KeyguardIndicationRotateTextViewControllerTest extends SysuiTestCase { public class KeyguardIndicationRotateTextViewControllerTest extends SysuiTestCase {
private static final String TEST_MESSAGE = "test message"; 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 @Mock
private DelayableExecutor mExecutor; private DelayableExecutor mExecutor;
@@ -200,6 +202,24 @@ public class KeyguardIndicationRotateTextViewControllerTest extends SysuiTestCas
verify(mExecutor).executeDelayed(any(), anyLong()); 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 @Test
public void testTransientIndication() { public void testTransientIndication() {
// GIVEN we already have two indication messages // GIVEN we already have two indication messages
@@ -223,8 +243,11 @@ public class KeyguardIndicationRotateTextViewControllerTest extends SysuiTestCas
@Test @Test
public void testHideIndicationOneMessage() { public void testHideIndicationOneMessage() {
// GIVEN we have one indication message // GIVEN we have one indication message
KeyguardIndication indication = createIndication();
mController.updateIndication( 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 // WHEN we hide the current indication type
mController.hideIndication(INDICATION_TYPE_OWNER_INFO); mController.hideIndication(INDICATION_TYPE_OWNER_INFO);
@@ -254,6 +277,10 @@ public class KeyguardIndicationRotateTextViewControllerTest extends SysuiTestCas
@Test @Test
public void testStartDozing() { public void testStartDozing() {
// GIVEN a biometric message is showing
mController.updateIndication(INDICATION_TYPE_BIOMETRIC_MESSAGE,
createIndication(), true);
// WHEN the device is dozing // WHEN the device is dozing
mStatusBarStateListener.onDozingChanged(true); mStatusBarStateListener.onDozingChanged(true);
@@ -293,9 +320,19 @@ public class KeyguardIndicationRotateTextViewControllerTest extends SysuiTestCas
verify(mView, never()).switchIndication(any()); verify(mView, never()).switchIndication(any());
} }
/**
* Create an indication with a unique message.
*/
private KeyguardIndication createIndication() { private KeyguardIndication createIndication() {
return createIndication(TEST_MESSAGE + " " + mMsgId++);
}
/**
* Create an indication with the given message.
*/
private KeyguardIndication createIndication(String msg) {
return new KeyguardIndication.Builder() return new KeyguardIndication.Builder()
.setMessage(TEST_MESSAGE) .setMessage(msg)
.setTextColor(ColorStateList.valueOf(Color.WHITE)) .setTextColor(ColorStateList.valueOf(Color.WHITE))
.build(); .build();
} }

View File

@@ -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_ALIGNMENT;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BATTERY; 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_DISCLOSURE;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_OWNER_INFO; import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_OWNER_INFO;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_RESTING; import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_RESTING;
@@ -112,6 +113,8 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
private static final ComponentName DEVICE_OWNER_COMPONENT = new ComponentName("com.android.foo", private static final ComponentName DEVICE_OWNER_COMPONENT = new ComponentName("com.android.foo",
"bar"); "bar");
private static final int TEST_STRING_RES = R.string.keyguard_indication_trust_unlocked;
private String mKeyguardTryFingerprintMsg; private String mKeyguardTryFingerprintMsg;
private String mDisclosureWithOrganization; private String mDisclosureWithOrganization;
private String mDisclosureGeneric; private String mDisclosureGeneric;
@@ -419,7 +422,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
// WHEN transient text is shown // WHEN transient text is shown
mStatusBarStateListener.onDozingChanged(true); mStatusBarStateListener.onDozingChanged(true);
mController.showTransientIndication("Test"); mController.showTransientIndication(TEST_STRING_RES);
// THEN wake lock is held while the animation is running // THEN wake lock is held while the animation is running
assertTrue("WakeLock expected: HELD, was: RELEASED", mWakeLock.isHeld()); assertTrue("WakeLock expected: HELD, was: RELEASED", mWakeLock.isHeld());
@@ -434,7 +437,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
// WHEN we show the transient indication // WHEN we show the transient indication
mStatusBarStateListener.onDozingChanged(true); mStatusBarStateListener.onDozingChanged(true);
mController.showTransientIndication("Test"); mController.showTransientIndication(TEST_STRING_RES);
// THEN wake lock is RELEASED, not held // THEN wake lock is RELEASED, not held
assertFalse("WakeLock expected: RELEASED, was: HELD", mWakeLock.isHeld()); assertFalse("WakeLock expected: RELEASED, was: HELD", mWakeLock.isHeld());
@@ -445,10 +448,11 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
createController(); createController();
mController.setVisible(true); mController.setVisible(true);
mController.showTransientIndication("Test"); mController.showTransientIndication(TEST_STRING_RES);
mStatusBarStateListener.onDozingChanged(true); 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.getCurrentTextColor()).isEqualTo(Color.WHITE);
assertThat(mTextView.getAlpha()).isEqualTo(1f); assertThat(mTextView.getAlpha()).isEqualTo(1f);
} }
@@ -462,11 +466,11 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
mController.getKeyguardCallback().onBiometricHelp( mController.getKeyguardCallback().onBiometricHelp(
KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED, message, KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED, message,
BiometricSourceType.FACE); BiometricSourceType.FACE);
verifyTransientMessage(message); verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, message);
reset(mRotateTextViewController); reset(mRotateTextViewController);
mStatusBarStateListener.onDozingChanged(true); mStatusBarStateListener.onDozingChanged(true);
verifyHideIndication(INDICATION_TYPE_TRANSIENT); verifyHideIndication(INDICATION_TYPE_BIOMETRIC_MESSAGE);
} }
@Test @Test
@@ -478,7 +482,7 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
mController.getKeyguardCallback().onBiometricError(FaceManager.FACE_ERROR_TIMEOUT, mController.getKeyguardCallback().onBiometricError(FaceManager.FACE_ERROR_TIMEOUT,
"A message", BiometricSourceType.FACE); "A message", BiometricSourceType.FACE);
verifyTransientMessage(message); verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, message);
mStatusBarStateListener.onDozingChanged(true); mStatusBarStateListener.onDozingChanged(true);
assertThat(mTextView.getText()).isNotEqualTo(message); assertThat(mTextView.getText()).isNotEqualTo(message);
@@ -497,7 +501,8 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
FingerprintManager.FINGERPRINT_ERROR_CANCELED, "bar", FingerprintManager.FINGERPRINT_ERROR_CANCELED, "bar",
BiometricSourceType.FINGERPRINT); BiometricSourceType.FINGERPRINT);
verifyNoTransientMessage(); verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE);
verifyNoMessage(INDICATION_TYPE_TRANSIENT);
} }
@Test @Test
@@ -757,7 +762,12 @@ public class KeyguardIndicationControllerTest extends SysuiTestCase {
verify(mRotateTextViewController).showTransient(eq(message)); verify(mRotateTextViewController).showTransient(eq(message));
} }
private void verifyNoTransientMessage() { private void verifyNoMessage(int type) {
verify(mRotateTextViewController, never()).showTransient(any()); if (type == INDICATION_TYPE_TRANSIENT) {
verify(mRotateTextViewController, never()).showTransient(anyString());
} else {
verify(mRotateTextViewController, never()).updateIndication(eq(type),
anyObject(), anyBoolean());
}
} }
} }