From ba4a8b087ba5a509aad4f96a4ac856d2cdd367f6 Mon Sep 17 00:00:00 2001 From: Robert Snoeberger Date: Fri, 18 Sep 2020 14:39:55 -0400 Subject: [PATCH] Hide UDFPS overlay when bouncer is showing Bug: 165257355 Test: manual - Verify that sensor circle disappears when bouncer is pulled up. Change-Id: I32d56f4637c403839cc8a065915e7404a55a754a --- .../systemui/biometrics/AuthController.java | 32 ++++++++++- .../systemui/biometrics/UdfpsController.java | 39 ++++++++++++- .../statusbar/phone/KeyguardBouncer.java | 56 ++++++++++++++++--- .../biometrics/AuthControllerTest.java | 25 +++++++++ .../biometrics/UdfpsControllerTest.java | 36 ++++++++++++ .../statusbar/phone/KeyguardBouncerTest.java | 43 +++++++++++++- 6 files changed, 219 insertions(+), 12 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index 77afa27b5ccaf..bde9a6e7c7146 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -52,6 +52,7 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.doze.DozeReceiver; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.phone.KeyguardBouncer; import java.util.List; @@ -64,7 +65,7 @@ import javax.inject.Provider; */ @SysUISingleton public class AuthController extends SystemUI implements CommandQueue.Callbacks, - AuthDialogCallback, DozeReceiver { + AuthDialogCallback, DozeReceiver, KeyguardBouncer.BouncerExpansionCallback { private static final String TAG = "AuthController"; private static final boolean DEBUG = true; @@ -426,6 +427,35 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, mCurrentDialog = null; } + /** See {@link KeyguardBouncer.BouncerExpansionCallback#onFullyShown}. */ + @Override + public void onFullyShown() { + if (mUdfpsController != null) { + mUdfpsController.setBouncerVisibility(true); + } + } + + /** See {@link KeyguardBouncer.BouncerExpansionCallback#onStartingToHide}. */ + @Override + public void onStartingToHide() { + } + + /** See {@link KeyguardBouncer.BouncerExpansionCallback#onStartingToShow}. */ + @Override + public void onStartingToShow() { + if (mUdfpsController != null) { + mUdfpsController.setBouncerVisibility(true); + } + } + + /** See {@link KeyguardBouncer.BouncerExpansionCallback#onFullyHidden}. */ + @Override + public void onFullyHidden() { + if (mUdfpsController != null) { + mUdfpsController.setBouncerVisibility(false); + } + } + private void showDialog(SomeArgs args, boolean skipAnimation, Bundle savedState) { mCurrentDialogArgs = args; final @BiometricAuthenticator.Modality int type = args.argi1; diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java index ba78485438ea2..d79c96ea4774a 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java @@ -86,7 +86,13 @@ class UdfpsController implements DozeReceiver { // Default non-HBM backlight value normalized to the range [0, 1.0]. Used as a fallback when the // actual brightness value cannot be retrieved. private final float mDefaultBrightness; + // Indicates whether the overlay is currently showing. Even if it has been requested, it might + // not be showing. private boolean mIsOverlayShowing; + // Indicates whether the overlay has been requested. + private boolean mIsOverlayRequested; + // Indicates whether the bouncer is showing. When it is showing, the overlay needs to be hidden. + private boolean mIsBouncerShowing; // The fingerprint AOD trigger doesn't provide an ACTION_UP/ACTION_CANCEL event to tell us when // to turn off high brightness mode. To get around this limitation, the state of the AOD @@ -98,12 +104,12 @@ class UdfpsController implements DozeReceiver { public class UdfpsOverlayController extends IUdfpsOverlayController.Stub { @Override public void showUdfpsOverlay() { - UdfpsController.this.showUdfpsOverlay(); + UdfpsController.this.setShowOverlay(true); } @Override public void hideUdfpsOverlay() { - UdfpsController.this.hideUdfpsOverlay(); + UdfpsController.this.setShowOverlay(false); } @Override @@ -207,6 +213,35 @@ class UdfpsController implements DozeReceiver { mView.dozeTimeTick(); } + private void setShowOverlay(boolean show) { + if (show == mIsOverlayRequested) { + return; + } + mIsOverlayRequested = show; + updateOverlay(); + } + + /** + * Call when the visibility of the bouncer changes. + * + * @param isShowing Whether or not the bouncer is showing + */ + void setBouncerVisibility(boolean isShowing) { + if (isShowing == mIsBouncerShowing) { + return; + } + mIsBouncerShowing = isShowing; + updateOverlay(); + } + + private void updateOverlay() { + if (mIsOverlayRequested && !mIsBouncerShowing) { + showUdfpsOverlay(); + } else { + hideUdfpsOverlay(); + } + } + private void showUdfpsOverlay() { mFgExecutor.execute(() -> { if (!mIsOverlayShowing) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java index 3665c39bd9ea7..af6ac223ada13 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java @@ -40,12 +40,15 @@ import com.android.keyguard.ViewMediatorCallback; import com.android.keyguard.dagger.KeyguardBouncerComponent; import com.android.keyguard.dagger.RootView; import com.android.systemui.DejankUtils; +import com.android.systemui.biometrics.AuthController; import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.shared.system.SysUiStatsLog; import com.android.systemui.statusbar.policy.KeyguardStateController; import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; import javax.inject.Inject; @@ -66,7 +69,8 @@ public class KeyguardBouncer { private final FalsingManager mFalsingManager; private final DismissCallbackRegistry mDismissCallbackRegistry; private final Handler mHandler; - private final BouncerExpansionCallback mExpansionCallback; + private final List mExpansionCallbacks = new ArrayList<>(); + private final AuthController mAuthController; private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private final KeyguardStateController mKeyguardStateController; private final KeyguardSecurityModel mKeyguardSecurityModel; @@ -100,6 +104,7 @@ public class KeyguardBouncer { ViewGroup container, DismissCallbackRegistry dismissCallbackRegistry, FalsingManager falsingManager, BouncerExpansionCallback expansionCallback, + AuthController authController, KeyguardStateController keyguardStateController, KeyguardUpdateMonitor keyguardUpdateMonitor, KeyguardBypassController keyguardBypassController, Handler handler, @@ -111,13 +116,15 @@ public class KeyguardBouncer { mKeyguardUpdateMonitor = keyguardUpdateMonitor; mFalsingManager = falsingManager; mDismissCallbackRegistry = dismissCallbackRegistry; - mExpansionCallback = expansionCallback; mHandler = handler; mKeyguardStateController = keyguardStateController; mKeyguardSecurityModel = keyguardSecurityModel; mKeyguardBouncerComponentFactory = keyguardBouncerComponentFactory; mKeyguardUpdateMonitor.registerCallback(mUpdateMonitorCallback); mKeyguardBypassController = keyguardBypassController; + mExpansionCallbacks.add(expansionCallback); + mExpansionCallbacks.add(authController); + mAuthController = authController; } public void show(boolean resetSecuritySelection) { @@ -188,7 +195,7 @@ public class KeyguardBouncer { } mCallback.onBouncerVisiblityChanged(true /* shown */); - mExpansionCallback.onStartingToShow(); + dispatchStartingToShow(); } public boolean isScrimmed() { @@ -290,6 +297,11 @@ public class KeyguardBouncer { mIsScrimmed = false; mFalsingManager.onBouncerHidden(); mCallback.onBouncerVisiblityChanged(false /* shown */); + // TODO(b/165257355): `mAuthController.onFullyHidden` should be `dispatchFullyHidden()` + // But, it is causing the UDFPS icon to disappear after SystemUI restarts. I guess the + // ExpansionCallback from StatusBarKeyguardViewManager can't handle the call to + // onFullyHidden after a restart. + mAuthController.onFullyHidden(); cancelShowRunnable(); if (mKeyguardViewController != null) { mKeyguardViewController.cancelDismissAction(); @@ -382,12 +394,12 @@ public class KeyguardBouncer { if (fraction == EXPANSION_VISIBLE && oldExpansion != EXPANSION_VISIBLE) { onFullyShown(); - mExpansionCallback.onFullyShown(); + dispatchFullyShown(); } else if (fraction == EXPANSION_HIDDEN && oldExpansion != EXPANSION_HIDDEN) { onFullyHidden(); - mExpansionCallback.onFullyHidden(); + dispatchFullyHidden(); } else if (fraction != EXPANSION_VISIBLE && oldExpansion == EXPANSION_VISIBLE) { - mExpansionCallback.onStartingToHide(); + dispatchStartingToHide(); if (mKeyguardViewController != null) { mKeyguardViewController.onStartingToHide(); } @@ -492,6 +504,30 @@ public class KeyguardBouncer { mKeyguardViewController.finish(strongAuth, KeyguardUpdateMonitor.getCurrentUser()); } + private void dispatchFullyShown() { + for (BouncerExpansionCallback callback : mExpansionCallbacks) { + callback.onFullyShown(); + } + } + + private void dispatchStartingToHide() { + for (BouncerExpansionCallback callback : mExpansionCallbacks) { + callback.onStartingToHide(); + } + } + + private void dispatchStartingToShow() { + for (BouncerExpansionCallback callback : mExpansionCallbacks) { + callback.onStartingToShow(); + } + } + + private void dispatchFullyHidden() { + for (BouncerExpansionCallback callback : mExpansionCallbacks) { + callback.onFullyHidden(); + } + } + public void dump(PrintWriter pw) { pw.println("KeyguardBouncer"); pw.println(" isShowing(): " + isShowing()); @@ -516,6 +552,7 @@ public class KeyguardBouncer { private final ViewMediatorCallback mCallback; private final DismissCallbackRegistry mDismissCallbackRegistry; private final FalsingManager mFalsingManager; + private final AuthController mAuthController; private final KeyguardStateController mKeyguardStateController; private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private final KeyguardBypassController mKeyguardBypassController; @@ -526,6 +563,7 @@ public class KeyguardBouncer { @Inject public Factory(Context context, ViewMediatorCallback callback, DismissCallbackRegistry dismissCallbackRegistry, FalsingManager falsingManager, + AuthController authController, KeyguardStateController keyguardStateController, KeyguardUpdateMonitor keyguardUpdateMonitor, KeyguardBypassController keyguardBypassController, Handler handler, @@ -535,6 +573,7 @@ public class KeyguardBouncer { mCallback = callback; mDismissCallbackRegistry = dismissCallbackRegistry; mFalsingManager = falsingManager; + mAuthController = authController; mKeyguardStateController = keyguardStateController; mKeyguardUpdateMonitor = keyguardUpdateMonitor; mKeyguardBypassController = keyguardBypassController; @@ -547,8 +586,9 @@ public class KeyguardBouncer { BouncerExpansionCallback expansionCallback) { return new KeyguardBouncer(mContext, mCallback, container, mDismissCallbackRegistry, mFalsingManager, expansionCallback, - mKeyguardStateController, mKeyguardUpdateMonitor, mKeyguardBypassController, - mHandler, mKeyguardSecurityModel, mKeyguardBouncerComponentFactory); + mAuthController, mKeyguardStateController, mKeyguardUpdateMonitor, + mKeyguardBypassController, mHandler, mKeyguardSecurityModel, + mKeyguardBouncerComponentFactory); } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java index 88608ebde5b68..66656c5d251ce 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java @@ -22,6 +22,7 @@ import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; @@ -505,6 +506,30 @@ public class AuthControllerTest extends SysuiTestCase { verify(mUdfpsController).onCancelAodInterrupt(); } + @Test + public void testOnFullyShown_DelegatesToUdfpsController() { + mAuthController.onFullyShown(); + verify(mUdfpsController).setBouncerVisibility(eq(true)); + } + + @Test + public void testOnFullyHidden_DelegatesToUdfpsController() { + mAuthController.onFullyHidden(); + verify(mUdfpsController).setBouncerVisibility(eq(false)); + } + + @Test + public void testOnStartingToShow_NeverDelegatesToUdfpsController() { + mAuthController.onStartingToShow(); + verify(mUdfpsController).setBouncerVisibility(eq(true)); + } + + @Test + public void testOnStartingToHide_NeverDelegatesToUdfpsController() { + mAuthController.onStartingToHide(); + verify(mUdfpsController, never()).setBouncerVisibility(anyBoolean()); + } + // Helpers private void showDialog(int authenticators, int biometricModality) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java index 87ec72fe0a018..9b9f840e5383f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java @@ -19,6 +19,7 @@ package com.android.systemui.biometrics; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyFloat; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -150,6 +151,41 @@ public class UdfpsControllerTest extends SysuiTestCase { verify(mWindowManager).removeView(eq(mUdfpsView)); } + @Test + public void showUdfpsOverlay_bouncerShowing() throws RemoteException { + // GIVEN that the bouncer is showing + mUdfpsController.setBouncerVisibility(/* isShowing */ true); + // WHEN a request to show the overlay is received + mOverlayController.showUdfpsOverlay(); + mFgExecutor.runAllReady(); + // THEN the overlay is not attached + verify(mWindowManager, never()).addView(eq(mUdfpsView), any()); + } + + @Test + public void setBouncerVisibility_overlayDetached() throws RemoteException { + // GIVEN that the overlay has been requested + mOverlayController.showUdfpsOverlay(); + // WHEN the bouncer becomes visible + mUdfpsController.setBouncerVisibility(/* isShowing */ true); + mFgExecutor.runAllReady(); + // THEN the overlay is detached + verify(mWindowManager).removeView(eq(mUdfpsView)); + } + + @Test + public void setBouncerVisibility_overlayAttached() throws RemoteException { + // GIVEN that the bouncer is visible + mUdfpsController.setBouncerVisibility(/* isShowing */ true); + // AND the overlay has been requested + mOverlayController.showUdfpsOverlay(); + // WHEN the bouncer is closed + mUdfpsController.setBouncerVisibility(/* isShowing */ false); + mFgExecutor.runAllReady(); + // THEN the overlay is attached + verify(mWindowManager).addView(eq(mUdfpsView), any()); + } + @Test public void fingerDown() throws RemoteException { // Configure UdfpsView to accept the ACTION_DOWN event diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java index 1b05ad7f8b5b3..4fb45ec181781 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java @@ -50,6 +50,7 @@ import com.android.keyguard.ViewMediatorCallback; import com.android.keyguard.dagger.KeyguardBouncerComponent; import com.android.systemui.DejankUtils; import com.android.systemui.SysuiTestCase; +import com.android.systemui.biometrics.AuthController; import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.plugins.ActivityStarter.OnDismissAction; import com.android.systemui.plugins.FalsingManager; @@ -78,6 +79,8 @@ public class KeyguardBouncerTest extends SysuiTestCase { @Mock private DismissCallbackRegistry mDismissCallbackRegistry; @Mock + private AuthController mAuthController; + @Mock private KeyguardHostViewController mKeyguardHostViewController; @Mock private KeyguardBouncer.BouncerExpansionCallback mExpansionCallback; @@ -128,7 +131,7 @@ public class KeyguardBouncerTest extends SysuiTestCase { final ViewGroup container = new FrameLayout(getContext()); mBouncer = new KeyguardBouncer.Factory(getContext(), mViewMediatorCallback, - mDismissCallbackRegistry, mFalsingManager, + mDismissCallbackRegistry, mFalsingManager, mAuthController, mKeyguardStateController, mKeyguardUpdateMonitor, mKeyguardBypassController, mHandler, mKeyguardSecurityModel, mKeyguardBouncerComponentFactory) @@ -206,6 +209,12 @@ public class KeyguardBouncerTest extends SysuiTestCase { verify(mKeyguardHostViewController).showErrorMessage(eq(errorMessage)); } + @Test + public void testShow_notifiesAuthControllerStartingToShow() { + mBouncer.show(/* resetSecuritySelection */ false); + verify(mAuthController).onStartingToShow(); + } + @Test public void testSetExpansion_notifiesFalsingManager() { mBouncer.ensureView(); @@ -236,6 +245,38 @@ public class KeyguardBouncerTest extends SysuiTestCase { verify(mRootView).announceForAccessibility(any()); } + @Test + public void testSetExpansion_notifiesAuthControllerFullyShown() { + mBouncer.ensureView(); + mBouncer.setExpansion(0.1f); + mBouncer.setExpansion(0f); + verify(mAuthController).onFullyShown(); + } + + @Test + public void testSetExpansion_notifiesAuthControllerStartingToHide() { + mBouncer.ensureView(); + mBouncer.setExpansion(0f); + mBouncer.setExpansion(0.1f); + verify(mAuthController).onStartingToHide(); + } + + @Test + public void testSetExpansion_notifiesAuthControllerFullyHidden() { + mBouncer.ensureView(); + mBouncer.setExpansion(0.9f); + mBouncer.setExpansion(1f); + verify(mAuthController).onFullyHidden(); + } + + @Test + public void testSetExpansion_negativeAuthControllerStartingToShow() { + mBouncer.ensureView(); + mBouncer.setExpansion(1f); + mBouncer.setExpansion(0.9f); + verify(mAuthController, never()).onStartingToShow(); + } + @Test public void testHide_notifiesFalsingManager() { mBouncer.hide(false);