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
This commit is contained in:
@@ -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<FingerprintSensorPropertiesInternal> fpProps,
|
||||
@Nullable List<FaceSensorPropertiesInternal> 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<CredentialViewModel> 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<FingerprintSensorPropertiesInternal> fpProps,
|
||||
@Nullable List<FaceSensorPropertiesInternal> 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);
|
||||
}
|
||||
|
||||
@@ -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<SideFpsController> 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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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"
|
||||
@@ -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<ByteArray?>(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<ByteArray?>(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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user