<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