• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download

<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.app.tracing.coroutines.launchTraced as launch
16 import com.android.systemui.biometrics.ui.CredentialPasswordView
17 import com.android.systemui.biometrics.ui.CredentialView
18 import com.android.systemui.biometrics.ui.IPinPad
19 import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel
20 import com.android.systemui.lifecycle.repeatWhenAttached
21 import com.android.systemui.res.R
22 import kotlinx.coroutines.awaitCancellation
23 import kotlinx.coroutines.flow.first
24 import kotlinx.coroutines.flow.firstOrNull
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.inputBoxContentDescription.firstOrNull()?.let { descriptionId ->
47                 passwordField.contentDescription = view.context.getString(descriptionId)
48             }
49             viewModel.inputFlags.firstOrNull()?.let { flags -> passwordField.inputType = flags }
50             if (requestFocusForInput) {
51                 passwordField.requestFocus()
52                 passwordField.scheduleShowSoftInput()
53             }
54             passwordField.setOnEditorActionListener(
55                 OnImeSubmitListener { text ->
56                     lifecycleScope.launch { viewModel.checkCredential(text, header) }
57                 }
58             )
59             passwordField.setOnKeyListener(OnBackButtonListener(onBackInvokedCallback))
60             val pinPadView = view.findViewById(R.id.pin_pad) as? IPinPad
61             if (pinPadView != null) {
62                 PinPadViewBinder.bind(pinPadView, view)
63             }
64             repeatOnLifecycle(Lifecycle.State.STARTED) {
65                 // dismiss on a valid credential check
66                 launch {
67                     viewModel.validatedAttestation.collect { attestation ->
68                         if (attestation != null) {
69                             imeManager.hideSoftInputFromWindow(
70                                 view.windowToken,
71                                 0, // flag
72                             )
73                             host.onCredentialMatched(attestation)
74                         } else {
75                             passwordField.setText("")
76                         }
77                     }
78                 }
79 
80                 val onBackInvokedDispatcher = view.findOnBackInvokedDispatcher()
81                 if (onBackInvokedDispatcher != null) {
82                     launch {
83                             onBackInvokedDispatcher.registerOnBackInvokedCallback(
84                                 OnBackInvokedDispatcher.PRIORITY_DEFAULT,
85                                 onBackInvokedCallback,
86                             )
87                             awaitCancellation()
88                         }
89                         .invokeOnCompletion {
90                             onBackInvokedDispatcher.unregisterOnBackInvokedCallback(
91                                 onBackInvokedCallback
92                             )
93                         }
94                 }
95             }
96         }
97     }
98 }
99 
100 private class OnBackButtonListener(private val onBackInvokedCallback: OnBackInvokedCallback) :
101     View.OnKeyListener {
onKeynull102     override fun onKey(v: View, keyCode: Int, event: KeyEvent): Boolean {
103         if (keyCode != KeyEvent.KEYCODE_BACK) {
104             return false
105         }
106         if (event.action == KeyEvent.ACTION_UP) {
107             onBackInvokedCallback.onBackInvoked()
108         }
109         return true
110     }
111 }
112 
113 private class OnImeSubmitListener(private val onSubmit: (text: CharSequence) -> Unit) :
114     TextView.OnEditorActionListener {
onEditorActionnull115     override fun onEditorAction(v: TextView, actionId: Int, event: KeyEvent?): Boolean {
116         val isSoftImeEvent =
117             event == null &&
118                 (actionId == EditorInfo.IME_NULL ||
119                     actionId == EditorInfo.IME_ACTION_DONE ||
120                     actionId == EditorInfo.IME_ACTION_NEXT)
121         val isKeyboardEnterKey =
122             event != null &&
123                 KeyEvent.isConfirmKey(event.keyCode) &&
124                 event.action == KeyEvent.ACTION_DOWN
125         if (isSoftImeEvent || isKeyboardEnterKey) {
126             onSubmit(v.text)
127             return true
128         }
129         return false
130     }
131 }
132