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

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

Merge "Add support for Predictive Back in CredentialPasswordViewBinder"

parents 41752009 1417609a
Loading
Loading
Loading
Loading
+25 −6
Original line number Diff line number Diff line
@@ -6,6 +6,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 androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.systemui.R
@@ -13,7 +15,7 @@ import com.android.systemui.biometrics.ui.CredentialPasswordView
import com.android.systemui.biometrics.ui.CredentialView
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.launch

/** Sub-binder for the [CredentialPasswordView]. */
@@ -29,6 +31,8 @@ object CredentialPasswordViewBinder {

        val passwordField: ImeAwareEditText = view.requireViewById(R.id.lockPassword)

        val onBackInvokedCallback = OnBackInvokedCallback { host.onCredentialAborted() }

        view.repeatWhenAttached {
            passwordField.requestFocus()
            passwordField.scheduleShowSoftInput()
@@ -43,9 +47,7 @@ object CredentialPasswordViewBinder {
                                launch { viewModel.checkCredential(text, header) }
                            }
                        )
                        passwordField.setOnKeyListener(
                            OnBackButtonListener { host.onCredentialAborted() }
                        )
                        passwordField.setOnKeyListener(OnBackButtonListener(onBackInvokedCallback))
                    }
                }

@@ -66,18 +68,35 @@ object CredentialPasswordViewBinder {
                        }
                    }
                }

                val onBackInvokedDispatcher = view.findOnBackInvokedDispatcher()
                if (onBackInvokedDispatcher != null) {
                    launch {
                            onBackInvokedDispatcher.registerOnBackInvokedCallback(
                                OnBackInvokedDispatcher.PRIORITY_DEFAULT,
                                onBackInvokedCallback
                            )
                            awaitCancellation()
                        }
                        .invokeOnCompletion {
                            onBackInvokedDispatcher.unregisterOnBackInvokedCallback(
                                onBackInvokedCallback
                            )
                        }
                }
            }
        }
    }
}

private class OnBackButtonListener(private val onBack: () -> Unit) : View.OnKeyListener {
private class OnBackButtonListener(private val onBackInvokedCallback: OnBackInvokedCallback) :
    View.OnKeyListener {
    override fun onKey(v: View, keyCode: Int, event: KeyEvent): Boolean {
        if (keyCode != KeyEvent.KEYCODE_BACK) {
            return false
        }
        if (event.action == KeyEvent.ACTION_UP) {
            onBack()
            onBackInvokedCallback.onBackInvoked()
        }
        return true
    }
+37 −14
Original line number Diff line number Diff line
@@ -124,6 +124,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)
@@ -369,20 +384,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
@@ -442,6 +444,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