From d3301fdc27d72e2944d0e7a755043855fb4b7920 Mon Sep 17 00:00:00 2001 From: Vincent Wang Date: Wed, 21 Dec 2022 15:47:37 +0000 Subject: [PATCH] Fix BP disappear when devices change to unfold mode from fold mode 1. Remove the logic that close BP when losing window focus. 2. Monitot notification shade status and close BP when users interact with notification shade Bug: 259622034 Test: 1. Show BP in fold mode, check if BP still exists in Unfold mode 2. Show BP and rotate device, check is BP still exists 3. atest AuthContainerViewTest atest AuthControllerTest atest biometrics-simple-test Change-Id: Id9e643dcf166eef35250ea625cd382a0687a84ad --- .../biometrics/AuthContainerView.java | 37 ++++--------- .../systemui/biometrics/AuthController.java | 11 +++- .../systemui/biometrics/AuthDialog.java | 2 - .../AuthDialogPanelInteractionDetector.kt | 53 ++++++++++++++++++ .../biometrics/AuthContainerViewTest.kt | 54 ++----------------- .../biometrics/AuthControllerTest.java | 13 +++-- 6 files changed, 85 insertions(+), 85 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetector.kt diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java index 815ac6801b2ec..e42f051bf3bb9 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java @@ -120,6 +120,7 @@ public class AuthContainerView extends LinearLayout private final Interpolator mLinearOutSlowIn; private final LockPatternUtils mLockPatternUtils; private final WakefulnessLifecycle mWakefulnessLifecycle; + private final AuthDialogPanelInteractionDetector mPanelInteractionDetector; private final InteractionJankMonitor mInteractionJankMonitor; // TODO: these should be migrated out once ready @@ -141,7 +142,6 @@ public class AuthContainerView extends LinearLayout private final OnBackInvokedCallback mBackCallback = this::onBackInvoked; private final @Background DelayableExecutor mBackgroundExecutor; - private boolean mIsOrientationChanged = false; // Non-null only if the dialog is in the act of dismissing and has not sent the reason yet. @Nullable @AuthDialogCallback.DismissedReason private Integer mPendingCallbackReason; @@ -235,6 +235,7 @@ public class AuthContainerView extends LinearLayout @Nullable List fpProps, @Nullable List faceProps, @NonNull WakefulnessLifecycle wakefulnessLifecycle, + @NonNull AuthDialogPanelInteractionDetector panelInteractionDetector, @NonNull UserManager userManager, @NonNull LockPatternUtils lockPatternUtils, @NonNull InteractionJankMonitor jankMonitor, @@ -242,8 +243,9 @@ public class AuthContainerView extends LinearLayout @NonNull Provider credentialViewModelProvider) { mConfig.mSensorIds = sensorIds; return new AuthContainerView(mConfig, fpProps, faceProps, wakefulnessLifecycle, - userManager, lockPatternUtils, jankMonitor, biometricPromptInteractor, - credentialViewModelProvider, new Handler(Looper.getMainLooper()), bgExecutor); + panelInteractionDetector, userManager, lockPatternUtils, jankMonitor, + biometricPromptInteractor, credentialViewModelProvider, + new Handler(Looper.getMainLooper()), bgExecutor); } } @@ -331,6 +333,7 @@ public class AuthContainerView extends LinearLayout @Nullable List fpProps, @Nullable List faceProps, @NonNull WakefulnessLifecycle wakefulnessLifecycle, + @NonNull AuthDialogPanelInteractionDetector panelInteractionDetector, @NonNull UserManager userManager, @NonNull LockPatternUtils lockPatternUtils, @NonNull InteractionJankMonitor jankMonitor, @@ -346,6 +349,7 @@ public class AuthContainerView extends LinearLayout mHandler = mainHandler; mWindowManager = mContext.getSystemService(WindowManager.class); mWakefulnessLifecycle = wakefulnessLifecycle; + mPanelInteractionDetector = panelInteractionDetector; mTranslationY = getResources() .getDimension(R.dimen.biometric_dialog_animation_translation_offset); @@ -490,22 +494,6 @@ public class AuthContainerView extends LinearLayout @Override public void onOrientationChanged() { maybeUpdatePositionForUdfps(true /* invalidate */); - mIsOrientationChanged = true; - } - - @Override - public void onWindowFocusChanged(boolean hasWindowFocus) { - super.onWindowFocusChanged(hasWindowFocus); - if (!hasWindowFocus) { - //it's a workaround to avoid closing BP incorrectly - //BP gets a onWindowFocusChanged(false) and then gets a onWindowFocusChanged(true) - if (mIsOrientationChanged) { - mIsOrientationChanged = false; - return; - } - Log.v(TAG, "Lost window focus, dismissing the dialog"); - animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED); - } } @Override @@ -513,6 +501,8 @@ public class AuthContainerView extends LinearLayout super.onAttachedToWindow(); mWakefulnessLifecycle.addObserver(this); + mPanelInteractionDetector.enable( + () -> animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED)); if (Utils.isBiometricAllowed(mConfig.mPromptInfo)) { mBiometricScrollView.addView(mBiometricView); @@ -666,11 +656,6 @@ public class AuthContainerView extends LinearLayout mBiometricView.restoreState(savedState); } - if (savedState != null) { - mIsOrientationChanged = savedState.getBoolean( - AuthDialog.KEY_BIOMETRIC_ORIENTATION_CHANGED); - } - wm.addView(this, getLayoutParams(mWindowToken, mConfig.mPromptInfo.getTitle())); } @@ -689,6 +674,7 @@ public class AuthContainerView extends LinearLayout @Override public void dismissWithoutCallback(boolean animate) { + mPanelInteractionDetector.disable(); if (animate) { animateAway(false /* sendReason */, 0 /* reason */); } else { @@ -699,6 +685,7 @@ public class AuthContainerView extends LinearLayout @Override public void dismissFromSystemServer() { + mPanelInteractionDetector.disable(); animateAway(false /* sendReason */, 0 /* reason */); } @@ -761,8 +748,6 @@ public class AuthContainerView extends LinearLayout mBiometricView != null && mCredentialView == null); outState.putBoolean(AuthDialog.KEY_CREDENTIAL_SHOWING, mCredentialView != null); - outState.putBoolean(AuthDialog.KEY_BIOMETRIC_ORIENTATION_CHANGED, mIsOrientationChanged); - if (mBiometricView != null) { mBiometricView.onSaveState(outState); } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index a0f3ecb0634bc..dad6ebe401849 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -164,6 +164,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, @NonNull private final SparseBooleanArray mSfpsEnrolledForUser; @NonNull private final SensorPrivacyManager mSensorPrivacyManager; private final WakefulnessLifecycle mWakefulnessLifecycle; + private final AuthDialogPanelInteractionDetector mPanelInteractionDetector; private boolean mAllFingerprintAuthenticatorsRegistered; @NonNull private final UserManager mUserManager; @NonNull private final LockPatternUtils mLockPatternUtils; @@ -721,6 +722,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, Provider sidefpsControllerFactory, @NonNull DisplayManager displayManager, @NonNull WakefulnessLifecycle wakefulnessLifecycle, + @NonNull AuthDialogPanelInteractionDetector panelInteractionDetector, @NonNull UserManager userManager, @NonNull LockPatternUtils lockPatternUtils, @NonNull UdfpsLogger udfpsLogger, @@ -767,6 +769,8 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, }); mWakefulnessLifecycle = wakefulnessLifecycle; + mPanelInteractionDetector = panelInteractionDetector; + mFaceProps = mFaceManager != null ? mFaceManager.getSensorPropertiesInternal() : null; int[] faceAuthLocation = context.getResources().getIntArray( @@ -1149,6 +1153,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, requestId, multiSensorConfig, mWakefulnessLifecycle, + mPanelInteractionDetector, mUserManager, mLockPatternUtils); @@ -1239,6 +1244,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, String opPackageName, boolean skipIntro, long operationId, long requestId, @BiometricMultiSensorMode int multiSensorConfig, @NonNull WakefulnessLifecycle wakefulnessLifecycle, + @NonNull AuthDialogPanelInteractionDetector panelInteractionDetector, @NonNull UserManager userManager, @NonNull LockPatternUtils lockPatternUtils) { return new AuthContainerView.Builder(mContext) @@ -1253,8 +1259,9 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, .setMultiSensorConfig(multiSensorConfig) .setScaleFactorProvider(() -> getScaleFactor()) .build(bgExecutor, sensorIds, mFpProps, mFaceProps, wakefulnessLifecycle, - userManager, lockPatternUtils, mInteractionJankMonitor, - mBiometricPromptInteractor, mCredentialViewModelProvider); + panelInteractionDetector, userManager, lockPatternUtils, + mInteractionJankMonitor, mBiometricPromptInteractor, + mCredentialViewModelProvider); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java index cd0fc37375945..51f39b3586595 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java @@ -48,8 +48,6 @@ public interface AuthDialog extends Dumpable { String KEY_BIOMETRIC_SENSOR_TYPE = "sensor_type"; String KEY_BIOMETRIC_SENSOR_PROPS = "sensor_props"; - String KEY_BIOMETRIC_ORIENTATION_CHANGED = "orientation_changed"; - int SIZE_UNKNOWN = 0; /** * Minimal UI, showing only biometric icon. diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetector.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetector.kt new file mode 100644 index 0000000000000..64211b5b138e1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetector.kt @@ -0,0 +1,53 @@ +package com.android.systemui.biometrics + +import android.annotation.AnyThread +import android.annotation.MainThread +import android.util.Log +import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.shade.ShadeExpansionChangeEvent +import com.android.systemui.shade.ShadeExpansionStateManager +import java.util.concurrent.Executor +import javax.inject.Inject + +class AuthDialogPanelInteractionDetector +@Inject +constructor( + private val shadeExpansionStateManager: ShadeExpansionStateManager, + @Main private val mainExecutor: Executor, +) { + private var action: Action? = null + + @MainThread + fun enable(onPanelInteraction: Runnable) { + if (action == null) { + action = Action(onPanelInteraction) + shadeExpansionStateManager.addExpansionListener(this::onPanelExpansionChanged) + } else { + Log.e(TAG, "Already enabled") + } + } + + @MainThread + fun disable() { + if (action != null) { + action = null + shadeExpansionStateManager.removeExpansionListener(this::onPanelExpansionChanged) + } + } + + @AnyThread + private fun onPanelExpansionChanged(event: ShadeExpansionChangeEvent) = + mainExecutor.execute { + action?.let { + if (event.tracking) { + Log.v(TAG, "Detected panel interaction, event: $event") + it.onPanelInteraction.run() + disable() + } + } + } +} + +private data class Action(val onPanelInteraction: Runnable) + +private const val TAG = "AuthDialogPanelInteractionDetector" diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt index 898f37048eec3..b4696e49e9aa5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt @@ -35,8 +35,6 @@ import android.view.WindowInsets import android.view.WindowManager import android.widget.ScrollView import androidx.test.filters.SmallTest -import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn -import com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn import com.android.internal.jank.InteractionJankMonitor import com.android.internal.widget.LockPatternUtils import com.android.systemui.R @@ -81,6 +79,8 @@ class AuthContainerViewTest : SysuiTestCase() { @Mock lateinit var wakefulnessLifecycle: WakefulnessLifecycle @Mock + lateinit var panelInteractionDetector: AuthDialogPanelInteractionDetector + @Mock lateinit var windowToken: IBinder @Mock lateinit var interactionJankMonitor: InteractionJankMonitor @@ -169,26 +169,6 @@ class AuthContainerViewTest : SysuiTestCase() { verify(callback, times(2)).onDialogAnimatedIn(authContainer?.requestId ?: 0L) } - @Test - fun testDismissesOnFocusLoss() { - val container = initializeFingerprintContainer() - waitForIdleSync() - - val requestID = authContainer?.requestId ?: 0L - - verify(callback).onDialogAnimatedIn(requestID) - - container.onWindowFocusChanged(false) - waitForIdleSync() - - verify(callback).onDismissed( - eq(AuthDialogCallback.DISMISSED_USER_CANCELED), - eq(null), /* credentialAttestation */ - eq(requestID) - ) - assertThat(container.parent).isNull() - } - @Test fun testFocusLossAfterRotating() { val container = initializeFingerprintContainer() @@ -208,35 +188,6 @@ class AuthContainerViewTest : SysuiTestCase() { ) } - @Test - fun testDismissesOnFocusLoss_hidesKeyboardWhenVisible() { - val container = initializeFingerprintContainer( - authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL - ) - waitForIdleSync() - - val requestID = authContainer?.requestId ?: 0L - - // Simulate keyboard was shown on the credential view - val windowInsetsController = container.windowInsetsController - spyOn(windowInsetsController) - spyOn(container.rootWindowInsets) - doReturn(true).`when`(container.rootWindowInsets).isVisible(WindowInsets.Type.ime()) - - container.onWindowFocusChanged(false) - waitForIdleSync() - - // Expect hiding IME request will be invoked when dismissing the view - verify(windowInsetsController)?.hide(WindowInsets.Type.ime()) - - verify(callback).onDismissed( - eq(AuthDialogCallback.DISMISSED_USER_CANCELED), - eq(null), /* credentialAttestation */ - eq(requestID) - ) - assertThat(container.parent).isNull() - } - @Test fun testActionAuthenticated_sendsDismissedAuthenticated() { val container = initializeFingerprintContainer() @@ -519,6 +470,7 @@ class AuthContainerViewTest : SysuiTestCase() { fingerprintProps, faceProps, wakefulnessLifecycle, + panelInteractionDetector, userManager, lockPatternUtils, interactionJankMonitor, 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 67b293f44cf4f..5afe49ea3cb32 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java @@ -152,6 +152,8 @@ public class AuthControllerTest extends SysuiTestCase { @Mock private WakefulnessLifecycle mWakefulnessLifecycle; @Mock + private AuthDialogPanelInteractionDetector mPanelInteractionDetector; + @Mock private UserManager mUserManager; @Mock private LockPatternUtils mLockPatternUtils; @@ -953,9 +955,10 @@ public class AuthControllerTest extends SysuiTestCase { super(context, mExecution, mCommandQueue, mActivityTaskManager, mWindowManager, mFingerprintManager, mFaceManager, () -> mUdfpsController, () -> mSideFpsController, mDisplayManager, mWakefulnessLifecycle, - mUserManager, mLockPatternUtils, mUdfpsLogger, mLogContextInteractor, - () -> mBiometricPromptCredentialInteractor, () -> mCredentialViewModel, - mInteractionJankMonitor, mHandler, mBackgroundExecutor, mVibratorHelper); + mPanelInteractionDetector, mUserManager, mLockPatternUtils, mUdfpsLogger, + mLogContextInteractor, () -> mBiometricPromptCredentialInteractor, + () -> mCredentialViewModel, mInteractionJankMonitor, mHandler, + mBackgroundExecutor, mVibratorHelper); } @Override @@ -963,7 +966,9 @@ public class AuthControllerTest extends SysuiTestCase { boolean requireConfirmation, int userId, int[] sensorIds, String opPackageName, boolean skipIntro, long operationId, long requestId, @BiometricManager.BiometricMultiSensorMode int multiSensorConfig, - WakefulnessLifecycle wakefulnessLifecycle, UserManager userManager, + WakefulnessLifecycle wakefulnessLifecycle, + AuthDialogPanelInteractionDetector panelInteractionDetector, + UserManager userManager, LockPatternUtils lockPatternUtils) { mLastBiometricPromptInfo = promptInfo;