1 package com.android.systemui.biometrics.ui
2 
3 import android.content.Context
4 import android.content.res.Configuration.ORIENTATION_LANDSCAPE
5 import android.graphics.Insets
6 import android.text.TextUtils
7 import android.util.AttributeSet
8 import android.view.View
9 import android.view.WindowInsets
10 import android.view.accessibility.AccessibilityManager
11 import android.widget.LinearLayout
12 import android.widget.TextView
13 import com.android.systemui.biometrics.AuthPanelController
14 import com.android.systemui.biometrics.plugins.AuthContextPlugins
15 import com.android.systemui.biometrics.ui.binder.CredentialViewBinder
16 import com.android.systemui.biometrics.ui.binder.Spaghetti
17 import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel
18 import com.android.systemui.res.R
19 
20 /** PIN or password credential view for BiometricPrompt. */
21 class CredentialPasswordView(context: Context, attrs: AttributeSet?) :
22     LinearLayout(context, attrs), CredentialView, View.OnApplyWindowInsetsListener {
23 
24     private var bottomInset: Int = 0
25 
<lambda>null26     private val accessibilityManager by lazy {
27         context.getSystemService(AccessibilityManager::class.java)
28     }
29 
30     /** Initializes the view. */
initnull31     override fun init(
32         viewModel: CredentialViewModel,
33         host: CredentialView.Host,
34         panelViewController: AuthPanelController,
35         animatePanel: Boolean,
36         legacyCallback: Spaghetti.Callback,
37         plugins: AuthContextPlugins?,
38     ) {
39         CredentialViewBinder.bind(
40             this,
41             host,
42             viewModel,
43             panelViewController,
44             animatePanel,
45             legacyCallback,
46             plugins,
47         )
48     }
49 
onFinishInflatenull50     override fun onFinishInflate() {
51         super.onFinishInflate()
52         setOnApplyWindowInsetsListener(this)
53     }
54 
onApplyWindowInsetsnull55     override fun onApplyWindowInsets(v: View, insets: WindowInsets): WindowInsets {
56         val statusBarInsets: Insets = insets.getInsets(WindowInsets.Type.statusBars())
57         val keyboardInsets: Insets = insets.getInsets(WindowInsets.Type.ime())
58         val navigationInsets: Insets = insets.getInsets(WindowInsets.Type.navigationBars())
59         val imeBottomInset = keyboardInsets.bottom
60         if (bottomInset != imeBottomInset) {
61             val titleView: TextView? = findViewById(R.id.title)
62             if (titleView != null) {
63                 if (
64                     bottomInset > 0 && resources.configuration.orientation == ORIENTATION_LANDSCAPE
65                 ) {
66                     titleView.isSingleLine = true
67                     titleView.ellipsize = TextUtils.TruncateAt.MARQUEE
68                     titleView.marqueeRepeatLimit = -1
69                     // select to enable marquee unless a screen reader is enabled
70                     titleView.isSelected = accessibilityManager?.shouldMarquee() ?: false
71                 } else {
72                     titleView.isSingleLine = false
73                     titleView.ellipsize = null
74                     // select to enable marquee unless a screen reader is enabled
75                     titleView.isSelected = false
76                 }
77             }
78         }
79 
80         setPadding(
81             0,
82             statusBarInsets.top,
83             0,
84             if (keyboardInsets.bottom == 0) navigationInsets.bottom else keyboardInsets.bottom,
85         )
86         return WindowInsets.CONSUMED
87     }
88 }
89 
AccessibilityManagernull90 private fun AccessibilityManager.shouldMarquee(): Boolean = !isEnabled || !isTouchExplorationEnabled
91