• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16 package com.android.systemui.statusbar.phone
17 
18 import android.content.Context
19 import android.content.res.Configuration
20 import android.util.AttributeSet
21 import android.view.View
22 import android.view.ViewGroup
23 import android.view.ViewPropertyAnimator
24 import android.view.WindowInsets
25 import android.widget.FrameLayout
26 import androidx.annotation.StringRes
27 import com.android.keyguard.LockIconViewController
28 import com.android.systemui.R
29 import com.android.systemui.keyguard.ui.binder.KeyguardBottomAreaViewBinder
30 import com.android.systemui.keyguard.ui.binder.KeyguardBottomAreaViewBinder.bind
31 import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel
32 import com.android.systemui.plugins.FalsingManager
33 import com.android.systemui.statusbar.VibratorHelper
34 
35 /**
36  * Renders the bottom area of the lock-screen. Concerned primarily with the quick affordance UI
37  * elements. A secondary concern is the interaction of the quick affordance elements with the
38  * indication area between them, though the indication area is primarily controlled elsewhere.
39  */
40 class KeyguardBottomAreaView
41 @JvmOverloads
42 constructor(
43     context: Context,
44     attrs: AttributeSet? = null,
45     defStyleAttr: Int = 0,
46     defStyleRes: Int = 0,
47 ) :
48     FrameLayout(
49         context,
50         attrs,
51         defStyleAttr,
52         defStyleRes,
53     ) {
54 
55     interface MessageDisplayer {
56         fun display(@StringRes stringResourceId: Int)
57     }
58 
59     private var ambientIndicationArea: View? = null
60     private lateinit var binding: KeyguardBottomAreaViewBinder.Binding
61     private var lockIconViewController: LockIconViewController? = null
62 
63     /** Initializes the view. */
64     fun init(
65         viewModel: KeyguardBottomAreaViewModel,
66         falsingManager: FalsingManager? = null,
67         lockIconViewController: LockIconViewController? = null,
68         messageDisplayer: MessageDisplayer? = null,
69         vibratorHelper: VibratorHelper? = null,
70     ) {
71         binding =
72             bind(
73                 this,
74                 viewModel,
75                 falsingManager,
76                 vibratorHelper,
77             ) {
78                 messageDisplayer?.display(it)
79             }
80         this.lockIconViewController = lockIconViewController
81     }
82 
83     /**
84      * Initializes this instance of [KeyguardBottomAreaView] based on the given instance of another
85      * [KeyguardBottomAreaView]
86      */
87     fun initFrom(oldBottomArea: KeyguardBottomAreaView) {
88         // if it exists, continue to use the original ambient indication container
89         // instead of the newly inflated one
90         ambientIndicationArea?.let { nonNullAmbientIndicationArea ->
91             // remove old ambient indication from its parent
92             val originalAmbientIndicationView =
93                 oldBottomArea.findViewById<View>(R.id.ambient_indication_container)
94             (originalAmbientIndicationView.parent as ViewGroup).removeView(
95                 originalAmbientIndicationView
96             )
97 
98             // remove current ambient indication from its parent (discard)
99             val ambientIndicationParent = nonNullAmbientIndicationArea.parent as ViewGroup
100             val ambientIndicationIndex =
101                 ambientIndicationParent.indexOfChild(nonNullAmbientIndicationArea)
102             ambientIndicationParent.removeView(nonNullAmbientIndicationArea)
103 
104             // add the old ambient indication to this view
105             ambientIndicationParent.addView(originalAmbientIndicationView, ambientIndicationIndex)
106             ambientIndicationArea = originalAmbientIndicationView
107         }
108     }
109 
110     override fun onFinishInflate() {
111         super.onFinishInflate()
112         ambientIndicationArea = findViewById(R.id.ambient_indication_container)
113     }
114 
115     override fun onConfigurationChanged(newConfig: Configuration) {
116         super.onConfigurationChanged(newConfig)
117         binding.onConfigurationChanged()
118     }
119 
120     /** Returns a list of animators to use to animate the indication areas. */
121     val indicationAreaAnimators: List<ViewPropertyAnimator>
122         get() = binding.getIndicationAreaAnimators()
123 
124     override fun hasOverlappingRendering(): Boolean {
125         return false
126     }
127 
128     override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets {
129         val bottom = insets.displayCutout?.safeInsetBottom ?: 0
130         if (isPaddingRelative) {
131             setPaddingRelative(paddingStart, paddingTop, paddingEnd, bottom)
132         } else {
133             setPadding(paddingLeft, paddingTop, paddingRight, bottom)
134         }
135         return insets
136     }
137 
138     override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
139         super.onLayout(changed, left, top, right, bottom)
140         findViewById<View>(R.id.ambient_indication_container)?.let {
141             val (ambientLeft, ambientTop) = it.locationOnScreen
142             if (binding.shouldConstrainToTopOfLockIcon()) {
143                 // make top of ambient indication view the bottom of the lock icon
144                 it.layout(
145                     ambientLeft,
146                     lockIconViewController?.bottom?.toInt() ?: 0,
147                     right - ambientLeft,
148                     ambientTop + it.measuredHeight
149                 )
150             } else {
151                 // make bottom of ambient indication view the top of the lock icon
152                 val lockLocationTop = lockIconViewController?.top ?: 0
153                 it.layout(
154                     ambientLeft,
155                     lockLocationTop.toInt() - it.measuredHeight,
156                     right - ambientLeft,
157                     lockLocationTop.toInt()
158                 )
159             }
160         }
161     }
162 }
163