Add support for Predictive Back in CredentialPasswordViewBinder
Test: atest AuthContainerViewTest Bug: 254450850 Change-Id: I3d71d3f595eba16b2e1cab01d915dd7842717a6e
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user