Merge "Add support for Predictive Back in AuthCredentialPasswordView" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
b0614930ea
@@ -129,6 +129,7 @@ public class AuthContainerView extends LinearLayout
|
|||||||
private final float mTranslationY;
|
private final float mTranslationY;
|
||||||
@VisibleForTesting @ContainerState int mContainerState = STATE_UNKNOWN;
|
@VisibleForTesting @ContainerState int mContainerState = STATE_UNKNOWN;
|
||||||
private final Set<Integer> mFailedModalities = new HashSet<Integer>();
|
private final Set<Integer> mFailedModalities = new HashSet<Integer>();
|
||||||
|
private OnBackInvokedDispatcher mOnBackInvokedDispatcher;
|
||||||
private final OnBackInvokedCallback mBackCallback = this::onBackInvoked;
|
private final OnBackInvokedCallback mBackCallback = this::onBackInvoked;
|
||||||
|
|
||||||
private final @Background DelayableExecutor mBackgroundExecutor;
|
private final @Background DelayableExecutor mBackgroundExecutor;
|
||||||
@@ -497,9 +498,9 @@ public class AuthContainerView extends LinearLayout
|
|||||||
.start();
|
.start();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
OnBackInvokedDispatcher dispatcher = findOnBackInvokedDispatcher();
|
mOnBackInvokedDispatcher = findOnBackInvokedDispatcher();
|
||||||
if (dispatcher != null) {
|
if (mOnBackInvokedDispatcher != null) {
|
||||||
dispatcher.registerOnBackInvokedCallback(
|
mOnBackInvokedDispatcher.registerOnBackInvokedCallback(
|
||||||
OnBackInvokedDispatcher.PRIORITY_DEFAULT, mBackCallback);
|
OnBackInvokedDispatcher.PRIORITY_DEFAULT, mBackCallback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -600,11 +601,11 @@ public class AuthContainerView extends LinearLayout
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDetachedFromWindow() {
|
public void onDetachedFromWindow() {
|
||||||
OnBackInvokedDispatcher dispatcher = findOnBackInvokedDispatcher();
|
|
||||||
if (dispatcher != null) {
|
|
||||||
findOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(mBackCallback);
|
|
||||||
}
|
|
||||||
super.onDetachedFromWindow();
|
super.onDetachedFromWindow();
|
||||||
|
if (mOnBackInvokedDispatcher != null) {
|
||||||
|
mOnBackInvokedDispatcher.unregisterOnBackInvokedCallback(mBackCallback);
|
||||||
|
mOnBackInvokedDispatcher = null;
|
||||||
|
}
|
||||||
mWakefulnessLifecycle.removeObserver(this);
|
mWakefulnessLifecycle.removeObserver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ import android.view.inputmethod.EditorInfo;
|
|||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
import android.widget.ImeAwareEditText;
|
import android.widget.ImeAwareEditText;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
import android.window.OnBackInvokedCallback;
|
||||||
|
import android.window.OnBackInvokedDispatcher;
|
||||||
|
|
||||||
import com.android.internal.widget.LockPatternChecker;
|
import com.android.internal.widget.LockPatternChecker;
|
||||||
import com.android.internal.widget.LockPatternUtils;
|
import com.android.internal.widget.LockPatternUtils;
|
||||||
@@ -58,6 +60,8 @@ public class AuthCredentialPasswordView extends AuthCredentialView
|
|||||||
private ViewGroup mAuthCredentialHeader;
|
private ViewGroup mAuthCredentialHeader;
|
||||||
private ViewGroup mAuthCredentialInput;
|
private ViewGroup mAuthCredentialInput;
|
||||||
private int mBottomInset = 0;
|
private int mBottomInset = 0;
|
||||||
|
private OnBackInvokedDispatcher mOnBackInvokedDispatcher;
|
||||||
|
private final OnBackInvokedCallback mBackCallback = this::onBackInvoked;
|
||||||
|
|
||||||
public AuthCredentialPasswordView(Context context,
|
public AuthCredentialPasswordView(Context context,
|
||||||
AttributeSet attrs) {
|
AttributeSet attrs) {
|
||||||
@@ -79,8 +83,7 @@ public class AuthCredentialPasswordView extends AuthCredentialView
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (event.getAction() == KeyEvent.ACTION_UP) {
|
if (event.getAction() == KeyEvent.ACTION_UP) {
|
||||||
mContainerView.sendEarlyUserCanceled();
|
onBackInvoked();
|
||||||
mContainerView.animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED);
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
@@ -88,6 +91,11 @@ public class AuthCredentialPasswordView extends AuthCredentialView
|
|||||||
setOnApplyWindowInsetsListener(this);
|
setOnApplyWindowInsetsListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onBackInvoked() {
|
||||||
|
mContainerView.sendEarlyUserCanceled();
|
||||||
|
mContainerView.animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onAttachedToWindow() {
|
protected void onAttachedToWindow() {
|
||||||
super.onAttachedToWindow();
|
super.onAttachedToWindow();
|
||||||
@@ -100,6 +108,12 @@ public class AuthCredentialPasswordView extends AuthCredentialView
|
|||||||
|
|
||||||
mPasswordField.requestFocus();
|
mPasswordField.requestFocus();
|
||||||
mPasswordField.scheduleShowSoftInput();
|
mPasswordField.scheduleShowSoftInput();
|
||||||
|
|
||||||
|
mOnBackInvokedDispatcher = findOnBackInvokedDispatcher();
|
||||||
|
if (mOnBackInvokedDispatcher != null) {
|
||||||
|
mOnBackInvokedDispatcher.registerOnBackInvokedCallback(
|
||||||
|
OnBackInvokedDispatcher.PRIORITY_DEFAULT, mBackCallback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -136,6 +150,15 @@ public class AuthCredentialPasswordView extends AuthCredentialView
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDetachedFromWindow() {
|
||||||
|
super.onDetachedFromWindow();
|
||||||
|
if (mOnBackInvokedDispatcher != null) {
|
||||||
|
mOnBackInvokedDispatcher.unregisterOnBackInvokedCallback(mBackCallback);
|
||||||
|
mOnBackInvokedDispatcher = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCredentialVerified(@NonNull VerifyCredentialResponse response,
|
protected void onCredentialVerified(@NonNull VerifyCredentialResponse response,
|
||||||
int timeoutMs) {
|
int timeoutMs) {
|
||||||
|
|||||||
@@ -110,6 +110,21 @@ class AuthContainerViewTest : SysuiTestCase() {
|
|||||||
assertThat(root.isAttachedToWindow).isFalse()
|
assertThat(root.isAttachedToWindow).isFalse()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testCredentialPasswordDismissesOnBack() {
|
||||||
|
val container = initializeCredentialPasswordContainer(addToView = true)
|
||||||
|
assertThat(container.parent).isNotNull()
|
||||||
|
val root = container.rootView
|
||||||
|
|
||||||
|
// Simulate back invocation
|
||||||
|
container.dispatchKeyEvent(KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK))
|
||||||
|
container.dispatchKeyEvent(KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK))
|
||||||
|
waitForIdleSync()
|
||||||
|
|
||||||
|
assertThat(container.parent).isNull()
|
||||||
|
assertThat(root.isAttachedToWindow).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testIgnoresAnimatedInWhenDismissed() {
|
fun testIgnoresAnimatedInWhenDismissed() {
|
||||||
val container = initializeFingerprintContainer(addToView = false)
|
val container = initializeFingerprintContainer(addToView = false)
|
||||||
@@ -355,20 +370,7 @@ class AuthContainerViewTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testCredentialUI_disablesClickingOnBackground() {
|
fun testCredentialUI_disablesClickingOnBackground() {
|
||||||
whenever(userManager.getCredentialOwnerProfile(anyInt())).thenReturn(20)
|
val container = initializeCredentialPasswordContainer()
|
||||||
whenever(lockPatternUtils.getKeyguardStoredPasswordQuality(eq(20))).thenReturn(
|
|
||||||
DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
|
|
||||||
)
|
|
||||||
|
|
||||||
// In the credential view, clicking on the background (to cancel authentication) is not
|
|
||||||
// valid. Thus, the listener should be null, and it should not be in the accessibility
|
|
||||||
// hierarchy.
|
|
||||||
val container = initializeFingerprintContainer(
|
|
||||||
authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL
|
|
||||||
)
|
|
||||||
waitForIdleSync()
|
|
||||||
|
|
||||||
assertThat(container.hasCredentialPasswordView()).isTrue()
|
|
||||||
assertThat(container.hasBiometricPrompt()).isFalse()
|
assertThat(container.hasBiometricPrompt()).isFalse()
|
||||||
assertThat(
|
assertThat(
|
||||||
container.findViewById<View>(R.id.background)?.isImportantForAccessibility
|
container.findViewById<View>(R.id.background)?.isImportantForAccessibility
|
||||||
@@ -428,6 +430,27 @@ class AuthContainerViewTest : SysuiTestCase() {
|
|||||||
verify(callback).onTryAgainPressed(authContainer?.requestId ?: 0L)
|
verify(callback).onTryAgainPressed(authContainer?.requestId ?: 0L)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun initializeCredentialPasswordContainer(
|
||||||
|
addToView: Boolean = true,
|
||||||
|
): TestAuthContainerView {
|
||||||
|
whenever(userManager.getCredentialOwnerProfile(anyInt())).thenReturn(20)
|
||||||
|
whenever(lockPatternUtils.getKeyguardStoredPasswordQuality(eq(20))).thenReturn(
|
||||||
|
DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
|
||||||
|
)
|
||||||
|
|
||||||
|
// In the credential view, clicking on the background (to cancel authentication) is not
|
||||||
|
// valid. Thus, the listener should be null, and it should not be in the accessibility
|
||||||
|
// hierarchy.
|
||||||
|
val container = initializeFingerprintContainer(
|
||||||
|
authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL,
|
||||||
|
addToView = addToView,
|
||||||
|
)
|
||||||
|
waitForIdleSync()
|
||||||
|
|
||||||
|
assertThat(container.hasCredentialPasswordView()).isTrue()
|
||||||
|
return container
|
||||||
|
}
|
||||||
|
|
||||||
private fun initializeFingerprintContainer(
|
private fun initializeFingerprintContainer(
|
||||||
authenticators: Int = BiometricManager.Authenticators.BIOMETRIC_WEAK,
|
authenticators: Int = BiometricManager.Authenticators.BIOMETRIC_WEAK,
|
||||||
addToView: Boolean = true
|
addToView: Boolean = true
|
||||||
|
|||||||
Reference in New Issue
Block a user