1 /*
2  * Copyright (C) 2022 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 
17 package com.android.systemui.bouncer.ui.binder
18 
19 import android.view.KeyEvent
20 import android.view.View
21 import android.view.ViewGroup
22 import android.window.OnBackAnimationCallback
23 import androidx.lifecycle.Lifecycle
24 import androidx.lifecycle.repeatOnLifecycle
25 import com.android.keyguard.KeyguardMessageAreaController
26 import com.android.keyguard.KeyguardSecurityContainerController
27 import com.android.keyguard.KeyguardSecurityModel
28 import com.android.keyguard.KeyguardSecurityView
29 import com.android.keyguard.KeyguardUpdateMonitor
30 import com.android.keyguard.dagger.KeyguardBouncerComponent
31 import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor
32 import com.android.systemui.bouncer.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE
33 import com.android.systemui.bouncer.ui.BouncerViewDelegate
34 import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel
35 import com.android.systemui.flags.FeatureFlags
36 import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel
37 import com.android.systemui.lifecycle.repeatWhenAttached
38 import com.android.systemui.log.BouncerLogger
39 import com.android.systemui.plugins.ActivityStarter
40 import kotlinx.coroutines.awaitCancellation
41 import kotlinx.coroutines.flow.filter
42 import kotlinx.coroutines.launch
43 
44 /** Binds the bouncer container to its view model. */
45 object KeyguardBouncerViewBinder {
46     @JvmStatic
47     fun bind(
48         view: ViewGroup,
49         viewModel: KeyguardBouncerViewModel,
50         primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel,
51         componentFactory: KeyguardBouncerComponent.Factory,
52         messageAreaControllerFactory: KeyguardMessageAreaController.Factory,
53         bouncerMessageInteractor: BouncerMessageInteractor,
54         bouncerLogger: BouncerLogger,
55         featureFlags: FeatureFlags,
56     ) {
57         // Builds the KeyguardSecurityContainerController from bouncer view group.
58         val securityContainerController: KeyguardSecurityContainerController =
59             componentFactory.create(view).securityContainerController
60         securityContainerController.init()
61         val delegate =
62             object : BouncerViewDelegate {
63                 override fun isFullScreenBouncer(): Boolean {
64                     val mode = securityContainerController.currentSecurityMode
65                     return mode == KeyguardSecurityModel.SecurityMode.SimPin ||
66                         mode == KeyguardSecurityModel.SecurityMode.SimPuk
67                 }
68 
69                 override fun getBackCallback(): OnBackAnimationCallback {
70                     return securityContainerController.backCallback
71                 }
72 
73                 override fun shouldDismissOnMenuPressed(): Boolean {
74                     return securityContainerController.shouldEnableMenuKey()
75                 }
76 
77                 override fun interceptMediaKey(event: KeyEvent?): Boolean {
78                     return securityContainerController.interceptMediaKey(event)
79                 }
80 
81                 override fun dispatchBackKeyEventPreIme(): Boolean {
82                     return securityContainerController.dispatchBackKeyEventPreIme()
83                 }
84 
85                 override fun showNextSecurityScreenOrFinish(): Boolean {
86                     return securityContainerController.dismiss(
87                         KeyguardUpdateMonitor.getCurrentUser()
88                     )
89                 }
90 
91                 override fun resume() {
92                     securityContainerController.showPrimarySecurityScreen(/* isTurningOff= */ false)
93                     securityContainerController.onResume(KeyguardSecurityView.SCREEN_ON)
94                 }
95 
96                 override fun setDismissAction(
97                     onDismissAction: ActivityStarter.OnDismissAction?,
98                     cancelAction: Runnable?
99                 ) {
100                     securityContainerController.setOnDismissAction(onDismissAction, cancelAction)
101                 }
102 
103                 override fun willDismissWithActions(): Boolean {
104                     return securityContainerController.hasDismissActions()
105                 }
106 
107                 override fun willRunDismissFromKeyguard(): Boolean {
108                     return securityContainerController.willRunDismissFromKeyguard()
109                 }
110 
111                 override fun showPromptReason(reason: Int) {
112                     securityContainerController.showPromptReason(reason)
113                 }
114             }
115         view.repeatWhenAttached {
116             repeatOnLifecycle(Lifecycle.State.CREATED) {
117                 try {
118                     viewModel.setBouncerViewDelegate(delegate)
119                     launch {
120                         viewModel.isShowing.collect { isShowing ->
121                             view.visibility = if (isShowing) View.VISIBLE else View.INVISIBLE
122                             if (isShowing) {
123                                 // Reset security container because these views are not reinflated.
124                                 securityContainerController.prepareToShow()
125                                 securityContainerController.reinflateViewFlipper {
126                                     // Reset Security Container entirely.
127                                     securityContainerController.onBouncerVisibilityChanged(
128                                         /* isVisible= */ true
129                                     )
130                                     securityContainerController.showPrimarySecurityScreen(
131                                         /* turningOff= */ false
132                                     )
133                                     securityContainerController.setInitialMessage()
134                                     securityContainerController.appear()
135                                     securityContainerController.onResume(
136                                         KeyguardSecurityView.SCREEN_ON
137                                     )
138                                     bouncerLogger.bindingBouncerMessageView()
139                                     it.bindMessageView(
140                                         bouncerMessageInteractor,
141                                         messageAreaControllerFactory,
142                                         bouncerLogger,
143                                         featureFlags
144                                     )
145                                 }
146                             } else {
147                                 bouncerMessageInteractor.onBouncerBeingHidden()
148                                 securityContainerController.onBouncerVisibilityChanged(
149                                     /* isVisible= */ false
150                                 )
151                                 securityContainerController.cancelDismissAction()
152                                 securityContainerController.reset()
153                                 securityContainerController.onPause()
154                             }
155                         }
156                     }
157 
158                     launch {
159                         viewModel.startingToHide.collect {
160                             securityContainerController.onStartingToHide()
161                         }
162                     }
163 
164                     launch {
165                         viewModel.startDisappearAnimation.collect {
166                             securityContainerController.startDisappearAnimation(it)
167                         }
168                     }
169 
170                     launch {
171                         viewModel.bouncerExpansionAmount.collect { expansion ->
172                             securityContainerController.setExpansion(expansion)
173                         }
174                     }
175 
176                     launch {
177                         primaryBouncerToGoneTransitionViewModel.bouncerAlpha.collect { alpha ->
178                             securityContainerController.setAlpha(alpha)
179                         }
180                     }
181 
182                     launch {
183                         viewModel.bouncerExpansionAmount
184                             .filter { it == EXPANSION_VISIBLE }
185                             .collect {
186                                 securityContainerController.onResume(KeyguardSecurityView.SCREEN_ON)
187                                 view.announceForAccessibility(securityContainerController.title)
188                             }
189                     }
190 
191                     launch {
192                         viewModel.isInteractable.collect { isInteractable ->
193                             securityContainerController.setInteractable(isInteractable)
194                         }
195                     }
196 
197                     launch {
198                         viewModel.keyguardPosition.collect { position ->
199                             securityContainerController.updateKeyguardPosition(position)
200                         }
201                     }
202 
203                     launch {
204                         viewModel.updateResources.collect {
205                             securityContainerController.updateResources()
206                             viewModel.notifyUpdateResources()
207                         }
208                     }
209 
210                     launch {
211                         viewModel.bouncerShowMessage.collect {
212                             securityContainerController.showMessage(
213                                 it.message,
214                                 it.colorStateList,
215                                 /* animated= */ true
216                             )
217                             viewModel.onMessageShown()
218                         }
219                     }
220 
221                     launch {
222                         viewModel.keyguardAuthenticated.collect {
223                             securityContainerController.finish(
224                                 it,
225                                 KeyguardUpdateMonitor.getCurrentUser()
226                             )
227                             viewModel.notifyKeyguardAuthenticated()
228                         }
229                     }
230 
231                     launch {
232                         viewModel
233                             .observeOnIsBackButtonEnabled { view.systemUiVisibility }
234                             .collect { view.systemUiVisibility = it }
235                     }
236 
237                     launch {
238                         viewModel.shouldUpdateSideFps.collect {
239                             viewModel.updateSideFpsVisibility()
240                         }
241                     }
242 
243                     launch {
244                         viewModel.sideFpsShowing.collect {
245                             securityContainerController.updateSideFpsVisibility(it)
246                         }
247                     }
248                     awaitCancellation()
249                 } finally {
250                     viewModel.setBouncerViewDelegate(null)
251                 }
252             }
253         }
254     }
255 }
256