Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b0614930 authored by Omar Miatello's avatar Omar Miatello Committed by Android (Google) Code Review
Browse files

Merge "Add support for Predictive Back in AuthCredentialPasswordView" into tm-qpr-dev

parents 7d1f6b22 a491f601
Loading
Loading
Loading
Loading
+8 −7
Original line number Diff line number Diff line
@@ -129,6 +129,7 @@ public class AuthContainerView extends LinearLayout
    private final float mTranslationY;
    @VisibleForTesting @ContainerState int mContainerState = STATE_UNKNOWN;
    private final Set<Integer> mFailedModalities = new HashSet<Integer>();
    private OnBackInvokedDispatcher mOnBackInvokedDispatcher;
    private final OnBackInvokedCallback mBackCallback = this::onBackInvoked;

    private final @Background DelayableExecutor mBackgroundExecutor;
@@ -497,9 +498,9 @@ public class AuthContainerView extends LinearLayout
                        .start();
            });
        }
        OnBackInvokedDispatcher dispatcher = findOnBackInvokedDispatcher();
        if (dispatcher != null) {
            dispatcher.registerOnBackInvokedCallback(
        mOnBackInvokedDispatcher = findOnBackInvokedDispatcher();
        if (mOnBackInvokedDispatcher != null) {
            mOnBackInvokedDispatcher.registerOnBackInvokedCallback(
                    OnBackInvokedDispatcher.PRIORITY_DEFAULT, mBackCallback);
        }
    }
@@ -600,11 +601,11 @@ public class AuthContainerView extends LinearLayout

    @Override
    public void onDetachedFromWindow() {
        OnBackInvokedDispatcher dispatcher = findOnBackInvokedDispatcher();
        if (dispatcher != null) {
            findOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(mBackCallback);
        }
        super.onDetachedFromWindow();
        if (mOnBackInvokedDispatcher != null) {
            mOnBackInvokedDispatcher.unregisterOnBackInvokedCallback(mBackCallback);
            mOnBackInvokedDispatcher = null;
        }
        mWakefulnessLifecycle.removeObserver(this);
    }

+25 −2
Original line number Diff line number Diff line
@@ -35,6 +35,8 @@ import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.ImeAwareEditText;
import android.widget.TextView;
import android.window.OnBackInvokedCallback;
import android.window.OnBackInvokedDispatcher;

import com.android.internal.widget.LockPatternChecker;
import com.android.internal.widget.LockPatternUtils;
@@ -58,6 +60,8 @@ public class AuthCredentialPasswordView extends AuthCredentialView
    private ViewGroup mAuthCredentialHeader;
    private ViewGroup mAuthCredentialInput;
    private int mBottomInset = 0;
    private OnBackInvokedDispatcher mOnBackInvokedDispatcher;
    private final OnBackInvokedCallback mBackCallback = this::onBackInvoked;

    public AuthCredentialPasswordView(Context context,
            AttributeSet attrs) {
@@ -79,8 +83,7 @@ public class AuthCredentialPasswordView extends AuthCredentialView
                return false;
            }
            if (event.getAction() == KeyEvent.ACTION_UP) {
                mContainerView.sendEarlyUserCanceled();
                mContainerView.animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED);
                onBackInvoked();
            }
            return true;
        });
@@ -88,6 +91,11 @@ public class AuthCredentialPasswordView extends AuthCredentialView
        setOnApplyWindowInsetsListener(this);
    }

    private void onBackInvoked() {
        mContainerView.sendEarlyUserCanceled();
        mContainerView.animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
@@ -100,6 +108,12 @@ public class AuthCredentialPasswordView extends AuthCredentialView

        mPasswordField.requestFocus();
        mPasswordField.scheduleShowSoftInput();

        mOnBackInvokedDispatcher = findOnBackInvokedDispatcher();
        if (mOnBackInvokedDispatcher != null) {
            mOnBackInvokedDispatcher.registerOnBackInvokedCallback(
                    OnBackInvokedDispatcher.PRIORITY_DEFAULT, mBackCallback);
        }
    }

    @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
    protected void onCredentialVerified(@NonNull VerifyCredentialResponse response,
            int timeoutMs) {
+37 −14
Original line number Diff line number Diff line
@@ -110,6 +110,21 @@ class AuthContainerViewTest : SysuiTestCase() {
        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
    fun testIgnoresAnimatedInWhenDismissed() {
        val container = initializeFingerprintContainer(addToView = false)
@@ -355,20 +370,7 @@ class AuthContainerViewTest : SysuiTestCase() {

    @Test
    fun testCredentialUI_disablesClickingOnBackground() {
        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
        )
        waitForIdleSync()

        assertThat(container.hasCredentialPasswordView()).isTrue()
        val container = initializeCredentialPasswordContainer()
        assertThat(container.hasBiometricPrompt()).isFalse()
        assertThat(
            container.findViewById<View>(R.id.background)?.isImportantForAccessibility
@@ -428,6 +430,27 @@ class AuthContainerViewTest : SysuiTestCase() {
        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(
        authenticators: Int = BiometricManager.Authenticators.BIOMETRIC_WEAK,
        addToView: Boolean = true