From c8c9cf6ff1c5a3f0a07a22f6ea4fbcc618369c4d Mon Sep 17 00:00:00 2001 From: Beverly Date: Thu, 14 Oct 2021 15:00:25 -0400 Subject: [PATCH] Devices with UDPFS shows lock icon on AOD ...when biometrics aren't available due to lockdown/reboot, etc. Note: on devices with udfps, if the device is unlocked (ie: smart unlock), then we still show the udfps icon on AOD to prevent from advertising the device's unlocked state. Main changes in this CL: - use super_lock_icon.xml for both static icons and the transitions between the icon states - move icon resources to res-keyguard - add AOD lock icon resource + transition from AOD <=> lock screen - add logic to show a lock icon on AOD (previously would show fp) Test: manual, atest SystemUITests Fixes: 194183870 Fixes: 199562477 Change-Id: I7239cc768e3725aa61797f8b0a0fb3d28760962d --- .../drawable}/fp_to_unlock.xml | 10 +- .../res-keyguard/drawable/ic_fingerprint.xml | 48 +++ .../res-keyguard/drawable/ic_lock.xml | 95 ++++++ .../res-keyguard/drawable/ic_lock_aod.xml | 41 +++ .../res-keyguard/drawable/ic_unlocked.xml | 48 +++ .../res-keyguard/drawable/lock_aod_to_ls.xml | 151 +++++++++ .../res-keyguard/drawable/lock_ls_to_aod.xml | 151 +++++++++ .../drawable}/lock_to_unlock.xml | 6 +- .../res-keyguard/drawable/super_lock_icon.xml | 82 +++++ .../res-keyguard/drawable/unlock_to_fp.xml | 298 ++++++++++++++++++ .../com/android/keyguard/LockIconView.java | 84 +++++ .../keyguard/LockIconViewController.java | 80 +++-- .../keyguard/LockIconViewControllerTest.java | 114 ++++++- 13 files changed, 1163 insertions(+), 45 deletions(-) rename packages/SystemUI/{res/anim => res-keyguard/drawable}/fp_to_unlock.xml (88%) create mode 100644 packages/SystemUI/res-keyguard/drawable/ic_fingerprint.xml create mode 100644 packages/SystemUI/res-keyguard/drawable/ic_lock.xml create mode 100644 packages/SystemUI/res-keyguard/drawable/ic_lock_aod.xml create mode 100644 packages/SystemUI/res-keyguard/drawable/ic_unlocked.xml create mode 100644 packages/SystemUI/res-keyguard/drawable/lock_aod_to_ls.xml create mode 100644 packages/SystemUI/res-keyguard/drawable/lock_ls_to_aod.xml rename packages/SystemUI/{res/anim => res-keyguard/drawable}/lock_to_unlock.xml (91%) create mode 100644 packages/SystemUI/res-keyguard/drawable/super_lock_icon.xml create mode 100644 packages/SystemUI/res-keyguard/drawable/unlock_to_fp.xml diff --git a/packages/SystemUI/res/anim/fp_to_unlock.xml b/packages/SystemUI/res-keyguard/drawable/fp_to_unlock.xml similarity index 88% rename from packages/SystemUI/res/anim/fp_to_unlock.xml rename to packages/SystemUI/res-keyguard/drawable/fp_to_unlock.xml index a5f75b6726c85..b93ccc6ac1062 100644 --- a/packages/SystemUI/res/anim/fp_to_unlock.xml +++ b/packages/SystemUI/res-keyguard/drawable/fp_to_unlock.xml @@ -19,15 +19,15 @@ - - - - + + + + - + diff --git a/packages/SystemUI/res-keyguard/drawable/ic_fingerprint.xml b/packages/SystemUI/res-keyguard/drawable/ic_fingerprint.xml new file mode 100644 index 0000000000000..2063d21bb5d65 --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/ic_fingerprint.xml @@ -0,0 +1,48 @@ + + + + + + + + + + \ No newline at end of file diff --git a/packages/SystemUI/res-keyguard/drawable/ic_lock.xml b/packages/SystemUI/res-keyguard/drawable/ic_lock.xml new file mode 100644 index 0000000000000..14a8d0bdf8e8d --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/ic_lock.xml @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/SystemUI/res-keyguard/drawable/ic_lock_aod.xml b/packages/SystemUI/res-keyguard/drawable/ic_lock_aod.xml new file mode 100644 index 0000000000000..cdae306cfc261 --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/ic_lock_aod.xml @@ -0,0 +1,41 @@ + + + + + + + + + \ No newline at end of file diff --git a/packages/SystemUI/res-keyguard/drawable/ic_unlocked.xml b/packages/SystemUI/res-keyguard/drawable/ic_unlocked.xml new file mode 100644 index 0000000000000..54242781cd731 --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/ic_unlocked.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + diff --git a/packages/SystemUI/res-keyguard/drawable/lock_aod_to_ls.xml b/packages/SystemUI/res-keyguard/drawable/lock_aod_to_ls.xml new file mode 100644 index 0000000000000..d35f69589c392 --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/lock_aod_to_ls.xml @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/SystemUI/res-keyguard/drawable/lock_ls_to_aod.xml b/packages/SystemUI/res-keyguard/drawable/lock_ls_to_aod.xml new file mode 100644 index 0000000000000..8a728ee7b46ab --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/lock_ls_to_aod.xml @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/SystemUI/res/anim/lock_to_unlock.xml b/packages/SystemUI/res-keyguard/drawable/lock_to_unlock.xml similarity index 91% rename from packages/SystemUI/res/anim/lock_to_unlock.xml rename to packages/SystemUI/res-keyguard/drawable/lock_to_unlock.xml index 76f7a05866d9e..ab7e9d9e582b2 100644 --- a/packages/SystemUI/res/anim/lock_to_unlock.xml +++ b/packages/SystemUI/res-keyguard/drawable/lock_to_unlock.xml @@ -21,7 +21,7 @@ - + @@ -30,7 +30,7 @@ - + @@ -39,7 +39,7 @@ - + diff --git a/packages/SystemUI/res-keyguard/drawable/super_lock_icon.xml b/packages/SystemUI/res-keyguard/drawable/super_lock_icon.xml new file mode 100644 index 0000000000000..7f0f68f4fc06b --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/super_lock_icon.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/SystemUI/res-keyguard/drawable/unlock_to_fp.xml b/packages/SystemUI/res-keyguard/drawable/unlock_to_fp.xml new file mode 100644 index 0000000000000..620c71a73121b --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/unlock_to_fp.xml @@ -0,0 +1,298 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconView.java b/packages/SystemUI/src/com/android/keyguard/LockIconView.java index ef4353b931793..68132f4c598b0 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconView.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconView.java @@ -26,6 +26,7 @@ import android.view.View; import android.widget.FrameLayout; import android.widget.ImageView; +import androidx.annotation.IntDef; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; @@ -40,6 +41,17 @@ import java.io.PrintWriter; * A view positioned under the notification shade. */ public class LockIconView extends FrameLayout implements Dumpable { + @IntDef({ICON_NONE, ICON_LOCK, ICON_FINGERPRINT, ICON_UNLOCK}) + public @interface IconType {} + + public static final int ICON_NONE = -1; + public static final int ICON_LOCK = 0; + public static final int ICON_FINGERPRINT = 1; + public static final int ICON_UNLOCK = 2; + + private @IconType int mIconType; + private boolean mAod; + @NonNull private final RectF mSensorRect; @NonNull private PointF mLockIconCenter = new PointF(0f, 0f); private int mRadius; @@ -49,6 +61,7 @@ public class LockIconView extends FrameLayout implements Dumpable { private int mLockIconColor; private boolean mUseBackground = false; + private float mDozeAmount = 0f; public LockIconView(Context context, AttributeSet attrs) { super(context, attrs); @@ -62,11 +75,17 @@ public class LockIconView extends FrameLayout implements Dumpable { mBgView = findViewById(R.id.lock_icon_bg); } + void setDozeAmount(float dozeAmount) { + mDozeAmount = dozeAmount; + updateColorAndBackgroundVisibility(); + } + void updateColorAndBackgroundVisibility() { if (mUseBackground && mLockIcon.getDrawable() != null) { mLockIconColor = Utils.getColorAttrDefaultColor(getContext(), android.R.attr.textColorPrimary); mBgView.setBackground(getContext().getDrawable(R.drawable.fingerprint_bg)); + mBgView.setAlpha(1f - mDozeAmount); mBgView.setVisibility(View.VISIBLE); } else { mLockIconColor = Utils.getColorAttrDefaultColor(getContext(), @@ -129,10 +148,75 @@ public class LockIconView extends FrameLayout implements Dumpable { return mLockIconCenter.y - mRadius; } + /** + * Updates the icon its default state where no visual is shown. + */ + public void clearIcon() { + updateIcon(ICON_NONE, false); + } + + /** + * Transition the current icon to a new state + * @param icon type (ie: lock icon, unlock icon, fingerprint icon) + * @param aod whether to use the aod icon variant (some icons don't have aod variants and will + * therefore show no icon) + */ + public void updateIcon(@IconType int icon, boolean aod) { + mIconType = icon; + mAod = aod; + + mLockIcon.setImageState(getLockIconState(mIconType, mAod), true); + } + + private static int[] getLockIconState(@IconType int icon, boolean aod) { + if (icon == ICON_NONE) { + return new int[0]; + } + + int[] lockIconState = new int[2]; + switch (icon) { + case ICON_LOCK: + lockIconState[0] = android.R.attr.state_first; + break; + case ICON_FINGERPRINT: + lockIconState[0] = android.R.attr.state_middle; + break; + case ICON_UNLOCK: + lockIconState[0] = android.R.attr.state_last; + break; + } + + if (aod) { + lockIconState[1] = android.R.attr.state_single; + } else { + lockIconState[1] = -android.R.attr.state_single; + } + + return lockIconState; + } + + private String typeToString(@IconType int type) { + switch (type) { + case ICON_NONE: + return "none"; + case ICON_LOCK: + return "lock"; + case ICON_FINGERPRINT: + return "fingerprint"; + case ICON_UNLOCK: + return "unlock"; + } + + return "invalid"; + } + @Override public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { pw.println("Center in px (x, y)= (" + mLockIconCenter.x + ", " + mLockIconCenter.y + ")"); pw.println("Radius in pixels: " + mRadius); pw.println("topLeft= (" + getX() + ", " + getY() + ")"); + pw.println("topLeft= (" + getX() + ", " + getY() + ")"); + pw.println("mIconType=" + typeToString(mIconType)); + pw.println("mAod=" + mAod); } } diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java index 321c1a309cb51..94b1728b34ae5 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java @@ -18,6 +18,9 @@ package com.android.keyguard; import static android.hardware.biometrics.BiometricSourceType.FINGERPRINT; +import static com.android.keyguard.LockIconView.ICON_FINGERPRINT; +import static com.android.keyguard.LockIconView.ICON_LOCK; +import static com.android.keyguard.LockIconView.ICON_UNLOCK; import static com.android.systemui.classifier.Classifier.LOCK_ICON; import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset; import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInProgressOffset; @@ -26,8 +29,7 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.PointF; import android.graphics.Rect; -import android.graphics.drawable.AnimatedVectorDrawable; -import android.graphics.drawable.Drawable; +import android.graphics.drawable.AnimatedStateListDrawable; import android.hardware.biometrics.BiometricSourceType; import android.hardware.biometrics.SensorLocationInternal; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; @@ -103,11 +105,8 @@ public class LockIconViewController extends ViewController impleme private boolean mUdfpsEnrolled; @Nullable private LottieAnimationView mAodFp; + @NonNull private final AnimatedStateListDrawable mIcon; - @NonNull private final AnimatedVectorDrawable mFpToUnlockIcon; - @NonNull private final AnimatedVectorDrawable mLockToUnlockIcon; - @NonNull private final Drawable mLockIcon; - @NonNull private final Drawable mUnlockIcon; @NonNull private CharSequence mUnlockedLabel; @NonNull private CharSequence mLockedLabel; @Nullable private final Vibrator mVibrator; @@ -133,13 +132,13 @@ public class LockIconViewController extends ViewController impleme private boolean mShowLockIcon; // for udfps when strong auth is required or unlocked on AOD + private boolean mShowAodLockIcon; private boolean mShowAODFpIcon; private final int mMaxBurnInOffsetX; private final int mMaxBurnInOffsetY; private float mInterpolatedDarkAmount; private boolean mDownDetected; - private boolean mDetectedLongPress; private final Rect mSensorTouchLocation = new Rect(); @Inject @@ -177,12 +176,9 @@ public class LockIconViewController extends ViewController impleme mMaxBurnInOffsetX = resources.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_x); mMaxBurnInOffsetY = resources.getDimensionPixelSize(R.dimen.udfps_burn_in_offset_y); - mUnlockIcon = resources.getDrawable(R.drawable.ic_unlock, mView.getContext().getTheme()); - mLockIcon = resources.getDrawable(R.anim.lock_to_unlock, mView.getContext().getTheme()); - mFpToUnlockIcon = (AnimatedVectorDrawable) resources.getDrawable( - R.anim.fp_to_unlock, mView.getContext().getTheme()); - mLockToUnlockIcon = (AnimatedVectorDrawable) resources.getDrawable(R.anim.lock_to_unlock, - mView.getContext().getTheme()); + mIcon = (AnimatedStateListDrawable) + resources.getDrawable(R.drawable.super_lock_icon, mView.getContext().getTheme()); + mView.setImageDrawable(mIcon); mUnlockedLabel = resources.getString(R.string.accessibility_unlock_button); mLockedLabel = resources.getString(R.string.accessibility_lock_icon); dumpManager.registerDumpable("LockIconViewController", this); @@ -256,42 +252,47 @@ public class LockIconViewController extends ViewController impleme return; } + boolean wasShowingUnlock = mShowUnlockIcon; boolean wasShowingFpIcon = mUdfpsEnrolled && !mShowUnlockIcon && !mShowLockIcon; - boolean wasShowingLockIcon = mShowLockIcon; - boolean wasShowingUnlockIcon = mShowUnlockIcon; mShowLockIcon = !mCanDismissLockScreen && !mUserUnlockedWithBiometric && isLockScreen() && (!mUdfpsEnrolled || !mRunningFPS); mShowUnlockIcon = (mCanDismissLockScreen || mUserUnlockedWithBiometric) && isLockScreen(); - mShowAODFpIcon = mIsDozing && mUdfpsEnrolled && !mRunningFPS; + mShowAODFpIcon = mIsDozing && mUdfpsEnrolled && !mRunningFPS && mCanDismissLockScreen; + mShowAodLockIcon = mIsDozing && mUdfpsEnrolled && !mRunningFPS && !mCanDismissLockScreen; final CharSequence prevContentDescription = mView.getContentDescription(); if (mShowLockIcon) { - mView.setImageDrawable(mLockIcon); - mView.setVisibility(View.VISIBLE); + mView.updateIcon(ICON_LOCK, false); mView.setContentDescription(mLockedLabel); - } else if (mShowUnlockIcon) { - if (!wasShowingUnlockIcon) { - if (wasShowingFpIcon) { - mView.setImageDrawable(mFpToUnlockIcon); - mFpToUnlockIcon.forceAnimationOnUI(); - mFpToUnlockIcon.start(); - } else if (wasShowingLockIcon) { - mView.setImageDrawable(mLockToUnlockIcon); - mLockToUnlockIcon.forceAnimationOnUI(); - mLockToUnlockIcon.start(); - } else { - mView.setImageDrawable(mUnlockIcon); - } - } mView.setVisibility(View.VISIBLE); + } else if (mShowUnlockIcon) { + if (wasShowingFpIcon) { + // fp icon was shown by UdfpsView, and now we still want to animate the transition + // in this drawable + mView.updateIcon(ICON_FINGERPRINT, false); + } + mView.updateIcon(ICON_UNLOCK, false); mView.setContentDescription(mUnlockedLabel); + mView.setVisibility(View.VISIBLE); } else if (mShowAODFpIcon) { - mView.setImageDrawable(null); + // AOD fp icon is special cased as a lottie view (it updates for each burn-in offset), + // this state shows a transparent view mView.setContentDescription(null); mAodFp.setVisibility(View.VISIBLE); mAodFp.setContentDescription(mCanDismissLockScreen ? mUnlockedLabel : mLockedLabel); + + mView.updateIcon(ICON_FINGERPRINT, true); // this shows no icon + mView.setVisibility(View.VISIBLE); + } else if (mShowAodLockIcon) { + if (wasShowingUnlock) { + // transition to the unlock icon first + mView.updateIcon(ICON_LOCK, false); + } + mView.updateIcon(ICON_LOCK, true); + mView.setContentDescription(mLockedLabel); mView.setVisibility(View.VISIBLE); } else { + mView.clearIcon(); mView.setVisibility(View.INVISIBLE); mView.setContentDescription(null); } @@ -381,6 +382,11 @@ public class LockIconViewController extends ViewController impleme pw.println("mUdfpsSupported: " + mUdfpsSupported); pw.println("mUdfpsEnrolled: " + mUdfpsEnrolled); pw.println("mIsKeyguardShowing: " + mIsKeyguardShowing); + pw.println(" mIcon: "); + for (int state : mIcon.getState()) { + pw.print(" " + state); + } + pw.println(); pw.println(" mShowUnlockIcon: " + mShowUnlockIcon); pw.println(" mShowLockIcon: " + mShowLockIcon); pw.println(" mShowAODFpIcon: " + mShowAODFpIcon); @@ -418,6 +424,11 @@ public class LockIconViewController extends ViewController impleme mAodFp.setProgress(progress); mAodFp.setAlpha(255 * mInterpolatedDarkAmount); } + + if (mShowAodLockIcon) { + mView.setTranslationX(offsetX); + mView.setTranslationY(offsetY); + } } private void updateIsUdfpsEnrolled() { @@ -442,6 +453,7 @@ public class LockIconViewController extends ViewController impleme @Override public void onDozeAmountChanged(float linear, float eased) { mInterpolatedDarkAmount = eased; + mView.setDozeAmount(eased); updateBurnInOffsets(); } @@ -562,7 +574,6 @@ public class LockIconViewController extends ViewController impleme private final GestureDetector mGestureDetector = new GestureDetector(new SimpleOnGestureListener() { public boolean onDown(MotionEvent e) { - mDetectedLongPress = false; if (!isClickable()) { mDownDetected = false; return false; @@ -587,7 +598,6 @@ public class LockIconViewController extends ViewController impleme if (!wasClickableOnDownEvent()) { return; } - mDetectedLongPress = true; if (onAffordanceClick() && mVibrator != null) { // only vibrate if the click went through and wasn't intercepted by falsing diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java index 90e3db7750bcf..c5436ef6f04b5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java @@ -16,6 +16,9 @@ package com.android.systemui.keyguard; +import static com.android.keyguard.LockIconView.ICON_LOCK; +import static com.android.keyguard.LockIconView.ICON_UNLOCK; + import static junit.framework.Assert.assertEquals; import static org.mockito.Mockito.any; @@ -29,7 +32,7 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.res.Resources; import android.graphics.PointF; -import android.graphics.drawable.AnimatedVectorDrawable; +import android.graphics.drawable.AnimatedStateListDrawable; import android.hardware.biometrics.BiometricSourceType; import android.hardware.biometrics.SensorLocationInternal; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; @@ -81,7 +84,7 @@ public class LockIconViewControllerTest extends SysuiTestCase { private static final String UNLOCKED_LABEL = "unlocked"; private @Mock LockIconView mLockIconView; - private @Mock AnimatedVectorDrawable mIconDrawable; + private @Mock AnimatedStateListDrawable mIconDrawable; private @Mock Context mContext; private @Mock Resources mResources; private @Mock DisplayMetrics mDisplayMetrics; @@ -107,6 +110,14 @@ public class LockIconViewControllerTest extends SysuiTestCase { ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class); private View.OnAttachStateChangeListener mAttachListener; + @Captor private ArgumentCaptor mKeyguardStateCaptor = + ArgumentCaptor.forClass(KeyguardStateController.Callback.class); + private KeyguardStateController.Callback mKeyguardStateCallback; + + @Captor private ArgumentCaptor mStatusBarStateCaptor = + ArgumentCaptor.forClass(StatusBarStateController.StateListener.class); + private StatusBarStateController.StateListener mStatusBarStateListener; + @Captor private ArgumentCaptor mAuthControllerCallbackCaptor; private AuthController.Callback mAuthControllerCallback; @@ -271,6 +282,86 @@ public class LockIconViewControllerTest extends SysuiTestCase { verify(mLockIconView).setContentDescription(UNLOCKED_LABEL); } + @Test + public void testLockIconStartState() { + // GIVEN lock icon state + setupShowLockIcon(); + + // WHEN lock icon controller is initialized + mLockIconViewController.init(); + captureAttachListener(); + mAttachListener.onViewAttachedToWindow(mLockIconView); + + // THEN the lock icon should show + verify(mLockIconView).updateIcon(ICON_LOCK, false); + } + + @Test + public void testLockIcon_updateToUnlock() { + // GIVEN starting state for the lock icon + setupShowLockIcon(); + + // GIVEN lock icon controller is initialized and view is attached + mLockIconViewController.init(); + captureAttachListener(); + mAttachListener.onViewAttachedToWindow(mLockIconView); + captureKeyguardStateCallback(); + reset(mLockIconView); + + // WHEN the unlocked state changes to canDismissLockScreen=true + when(mKeyguardStateController.canDismissLockScreen()).thenReturn(true); + mKeyguardStateCallback.onUnlockedChanged(); + + // THEN the unlock should show + verify(mLockIconView).updateIcon(ICON_UNLOCK, false); + } + + @Test + public void testLockIcon_clearsIconOnAod_whenUdfpsNotEnrolled() { + // GIVEN udfps not enrolled + setupUdfps(); + when(mKeyguardUpdateMonitor.isUdfpsEnrolled()).thenReturn(false); + + // GIVEN starting state for the lock icon + setupShowLockIcon(); + + // GIVEN lock icon controller is initialized and view is attached + mLockIconViewController.init(); + captureAttachListener(); + mAttachListener.onViewAttachedToWindow(mLockIconView); + captureStatusBarStateListener(); + reset(mLockIconView); + + // WHEN the dozing state changes + mStatusBarStateListener.onDozingChanged(true /* isDozing */); + + // THEN the icon is cleared + verify(mLockIconView).clearIcon(); + } + + @Test + public void testLockIcon_updateToAodLock_whenUdfpsEnrolled() { + // GIVEN udfps enrolled + setupUdfps(); + when(mKeyguardUpdateMonitor.isUdfpsEnrolled()).thenReturn(true); + + // GIVEN starting state for the lock icon + setupShowLockIcon(); + + // GIVEN lock icon controller is initialized and view is attached + mLockIconViewController.init(); + captureAttachListener(); + mAttachListener.onViewAttachedToWindow(mLockIconView); + captureStatusBarStateListener(); + reset(mLockIconView); + + // WHEN the dozing state changes + mStatusBarStateListener.onDozingChanged(true /* isDozing */); + + // THEN the AOD lock icon should show + verify(mLockIconView).updateIcon(ICON_LOCK, true); + } + private Pair setupUdfps() { final PointF udfpsLocation = new PointF(50, 75); final int radius = 33; @@ -290,6 +381,15 @@ public class LockIconViewControllerTest extends SysuiTestCase { return new Pair(radius, udfpsLocation); } + private void setupShowLockIcon() { + when(mKeyguardStateController.isShowing()).thenReturn(true); + when(mKeyguardStateController.isKeyguardGoingAway()).thenReturn(false); + when(mStatusBarStateController.isDozing()).thenReturn(false); + when(mStatusBarStateController.getDozeAmount()).thenReturn(0f); + when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD); + when(mKeyguardStateController.canDismissLockScreen()).thenReturn(false); + } + private void captureAuthControllerCallback() { verify(mAuthController).addCallback(mAuthControllerCallbackCaptor.capture()); mAuthControllerCallback = mAuthControllerCallbackCaptor.getValue(); @@ -300,6 +400,16 @@ public class LockIconViewControllerTest extends SysuiTestCase { mAttachListener = mAttachCaptor.getValue(); } + private void captureKeyguardStateCallback() { + verify(mKeyguardStateController).addCallback(mKeyguardStateCaptor.capture()); + mKeyguardStateCallback = mKeyguardStateCaptor.getValue(); + } + + private void captureStatusBarStateListener() { + verify(mStatusBarStateController).addCallback(mStatusBarStateCaptor.capture()); + mStatusBarStateListener = mStatusBarStateCaptor.getValue(); + } + private void captureKeyguardUpdateMonitorCallback() { verify(mKeyguardUpdateMonitor).registerCallback( mKeyguardUpdateMonitorCallbackCaptor.capture());