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