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

Commit a491f601 authored by omarmt's avatar omarmt Committed by Omar Miatello
Browse files

Add support for Predictive Back in AuthCredentialPasswordView

Test: atest AuthContainerViewTest
Bug: 254450850
Change-Id: I3d71d3f595eba16b2e1cab01d915dd7842717a6e
Merged-In: I3d71d3f595eba16b2e1cab01d915dd7842717a6e
parent a3256d33
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