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