<lambda>null1 package com.android.systemui.biometrics.ui.binder
2
3 import android.os.UserHandle
4 import android.view.KeyEvent
5 import android.view.View
6 import android.view.inputmethod.EditorInfo
7 import android.view.inputmethod.InputMethodManager
8 import android.widget.ImeAwareEditText
9 import android.widget.TextView
10 import android.window.OnBackInvokedCallback
11 import android.window.OnBackInvokedDispatcher
12 import androidx.lifecycle.Lifecycle
13 import androidx.lifecycle.lifecycleScope
14 import androidx.lifecycle.repeatOnLifecycle
15 import com.android.systemui.biometrics.ui.CredentialPasswordView
16 import com.android.systemui.biometrics.ui.CredentialView
17 import com.android.systemui.biometrics.ui.IPinPad
18 import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel
19 import com.android.systemui.lifecycle.repeatWhenAttached
20 import com.android.systemui.res.R
21 import kotlinx.coroutines.awaitCancellation
22 import kotlinx.coroutines.flow.first
23 import kotlinx.coroutines.flow.firstOrNull
24 import kotlinx.coroutines.launch
25
26 /** Sub-binder for the [CredentialPasswordView]. */
27 object CredentialPasswordViewBinder {
28
29 /** Bind the view. */
30 fun bind(
31 view: CredentialPasswordView,
32 host: CredentialView.Host,
33 viewModel: CredentialViewModel,
34 requestFocusForInput: Boolean,
35 ) {
36 val imeManager = view.context.getSystemService(InputMethodManager::class.java)!!
37
38 val passwordField: ImeAwareEditText = view.requireViewById(R.id.lockPassword)
39
40 val onBackInvokedCallback = OnBackInvokedCallback { host.onCredentialAborted() }
41
42 view.repeatWhenAttached {
43 // the header info never changes - do it early
44 val header = viewModel.header.first()
45 passwordField.setTextOperationUser(UserHandle.of(header.user.userIdForPasswordEntry))
46 viewModel.inputFlags.firstOrNull()?.let { flags -> passwordField.inputType = flags }
47 if (requestFocusForInput) {
48 passwordField.requestFocus()
49 passwordField.scheduleShowSoftInput()
50 }
51 passwordField.setOnEditorActionListener(
52 OnImeSubmitListener { text ->
53 lifecycleScope.launch { viewModel.checkCredential(text, header) }
54 }
55 )
56 passwordField.setOnKeyListener(OnBackButtonListener(onBackInvokedCallback))
57 val pinPadView = view.findViewById(R.id.pin_pad) as? IPinPad
58 if (pinPadView != null) {
59 PinPadViewBinder.bind(pinPadView, view)
60 }
61 repeatOnLifecycle(Lifecycle.State.STARTED) {
62 // dismiss on a valid credential check
63 launch {
64 viewModel.validatedAttestation.collect { attestation ->
65 if (attestation != null) {
66 imeManager.hideSoftInputFromWindow(
67 view.windowToken,
68 0 // flag
69 )
70 host.onCredentialMatched(attestation)
71 } else {
72 passwordField.setText("")
73 }
74 }
75 }
76
77 val onBackInvokedDispatcher = view.findOnBackInvokedDispatcher()
78 if (onBackInvokedDispatcher != null) {
79 launch {
80 onBackInvokedDispatcher.registerOnBackInvokedCallback(
81 OnBackInvokedDispatcher.PRIORITY_DEFAULT,
82 onBackInvokedCallback
83 )
84 awaitCancellation()
85 }
86 .invokeOnCompletion {
87 onBackInvokedDispatcher.unregisterOnBackInvokedCallback(
88 onBackInvokedCallback
89 )
90 }
91 }
92 }
93 }
94 }
95 }
96
97 private class OnBackButtonListener(private val onBackInvokedCallback: OnBackInvokedCallback) :
98 View.OnKeyListener {
onKeynull99 override fun onKey(v: View, keyCode: Int, event: KeyEvent): Boolean {
100 if (keyCode != KeyEvent.KEYCODE_BACK) {
101 return false
102 }
103 if (event.action == KeyEvent.ACTION_UP) {
104 onBackInvokedCallback.onBackInvoked()
105 }
106 return true
107 }
108 }
109
110 private class OnImeSubmitListener(private val onSubmit: (text: CharSequence) -> Unit) :
111 TextView.OnEditorActionListener {
onEditorActionnull112 override fun onEditorAction(v: TextView, actionId: Int, event: KeyEvent?): Boolean {
113 val isSoftImeEvent =
114 event == null &&
115 (actionId == EditorInfo.IME_NULL ||
116 actionId == EditorInfo.IME_ACTION_DONE ||
117 actionId == EditorInfo.IME_ACTION_NEXT)
118 val isKeyboardEnterKey =
119 event != null &&
120 KeyEvent.isConfirmKey(event.keyCode) &&
121 event.action == KeyEvent.ACTION_DOWN
122 if (isSoftImeEvent || isKeyboardEnterKey) {
123 onSubmit(v.text)
124 return true
125 }
126 return false
127 }
128 }
129