1 /*
2  * 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.ActivityStarter
33 import com.android.systemui.plugins.FalsingManager
34 import com.android.systemui.statusbar.VibratorHelper
35 import com.android.systemui.util.animation.requiresRemeasuring
36 
37 /**
38  * Renders the bottom area of the lock-screen. Concerned primarily with the quick affordance UI
39  * elements. A secondary concern is the interaction of the quick affordance elements with the
40  * indication area between them, though the indication area is primarily controlled elsewhere.
41  */
42 @Deprecated("Deprecated as part of b/278057014")
43 class KeyguardBottomAreaView
44 @JvmOverloads
45 constructor(
46     context: Context,
47     attrs: AttributeSet? = null,
48     defStyleAttr: Int = 0,
49     defStyleRes: Int = 0,
50 ) :
51     FrameLayout(
52         context,
53         attrs,
54         defStyleAttr,
55         defStyleRes,
56     ) {
57 
58     @Deprecated("Deprecated as part of b/278057014")
59     interface MessageDisplayer {
60         fun display(@StringRes stringResourceId: Int)
61     }
62 
63     private var ambientIndicationArea: View? = null
64     private var binding: KeyguardBottomAreaViewBinder.Binding? = null
65     private var lockIconViewController: LockIconViewController? = null
66 
67     /** Initializes the view. */
68     @Deprecated("Deprecated as part of b/278057014")
69     fun init(
70         viewModel: KeyguardBottomAreaViewModel,
71         falsingManager: FalsingManager? = null,
72         lockIconViewController: LockIconViewController? = null,
73         messageDisplayer: MessageDisplayer? = null,
74         vibratorHelper: VibratorHelper? = null,
75         activityStarter: ActivityStarter? = null,
76     ) {
77         binding?.destroy()
78         binding =
79             bind(
80                 this,
81                 viewModel,
82                 falsingManager,
83                 vibratorHelper,
84                 activityStarter,
85             ) {
86                 messageDisplayer?.display(it)
87             }
88         this.lockIconViewController = lockIconViewController
89     }
90 
91     /**
92      * Initializes this instance of [KeyguardBottomAreaView] based on the given instance of another
93      * [KeyguardBottomAreaView]
94      */
95     @Deprecated("Deprecated as part of b/278057014")
96     fun initFrom(oldBottomArea: KeyguardBottomAreaView) {
97         // if it exists, continue to use the original ambient indication container
98         // instead of the newly inflated one
99         ambientIndicationArea?.let { nonNullAmbientIndicationArea ->
100             // remove old ambient indication from its parent
101             val originalAmbientIndicationView =
102                 oldBottomArea.requireViewById<View>(R.id.ambient_indication_container)
103             (originalAmbientIndicationView.parent as ViewGroup).removeView(
104                 originalAmbientIndicationView
105             )
106 
107             // remove current ambient indication from its parent (discard)
108             val ambientIndicationParent = nonNullAmbientIndicationArea.parent as ViewGroup
109             val ambientIndicationIndex =
110                 ambientIndicationParent.indexOfChild(nonNullAmbientIndicationArea)
111             ambientIndicationParent.removeView(nonNullAmbientIndicationArea)
112 
113             // add the old ambient indication to this view
114             ambientIndicationParent.addView(originalAmbientIndicationView, ambientIndicationIndex)
115             ambientIndicationArea = originalAmbientIndicationView
116         }
117     }
118 
119     override fun onFinishInflate() {
120         super.onFinishInflate()
121         ambientIndicationArea = findViewById(R.id.ambient_indication_container)
122     }
123 
124     override fun onConfigurationChanged(newConfig: Configuration) {
125         super.onConfigurationChanged(newConfig)
126         binding?.onConfigurationChanged()
127     }
128 
129     /** Returns a list of animators to use to animate the indication areas. */
130     @Deprecated("Deprecated as part of b/278057014")
131     val indicationAreaAnimators: List<ViewPropertyAnimator>
132         get() = checkNotNull(binding).getIndicationAreaAnimators()
133 
134 
135     override fun hasOverlappingRendering(): Boolean {
136         return false
137     }
138 
139     override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets {
140         val bottom = insets.displayCutout?.safeInsetBottom ?: 0
141         if (isPaddingRelative) {
142             setPaddingRelative(paddingStart, paddingTop, paddingEnd, bottom)
143         } else {
144             setPadding(paddingLeft, paddingTop, paddingRight, bottom)
145         }
146         return insets
147     }
148 
149     override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
150         super.onLayout(changed, left, top, right, bottom)
151         findViewById<View>(R.id.ambient_indication_container)?.let {
152             val (ambientLeft, ambientTop) = it.locationOnScreen
153             if (binding?.shouldConstrainToTopOfLockIcon() == true) {
154                 // make top of ambient indication view the bottom of the lock icon
155                 it.layout(
156                     ambientLeft,
157                     lockIconViewController?.bottom?.toInt() ?: 0,
158                     right - ambientLeft,
159                     ambientTop + it.measuredHeight
160                 )
161             } else {
162                 // make bottom of ambient indication view the top of the lock icon
163                 val lockLocationTop = lockIconViewController?.top ?: 0
164                 it.layout(
165                     ambientLeft,
166                     lockLocationTop.toInt() - it.measuredHeight,
167                     right - ambientLeft,
168                     lockLocationTop.toInt()
169                 )
170             }
171         }
172     }
173 }
174