blob: 2337ffc35fa63a35d306d3b188045c4258fd80e7 [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.systemui.keyguard.ui.binder
import android.view.KeyEvent
import android.view.View
import android.view.ViewGroup
import android.window.OnBackAnimationCallback
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.keyguard.KeyguardSecurityContainerController
import com.android.keyguard.KeyguardSecurityModel
import com.android.keyguard.KeyguardSecurityView
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.dagger.KeyguardBouncerComponent
import com.android.settingslib.Utils
import com.android.systemui.keyguard.data.BouncerViewDelegate
import com.android.systemui.keyguard.shared.constants.KeyguardBouncerConstants.EXPANSION_VISIBLE
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBouncerViewModel
import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToGoneTransitionViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.plugins.ActivityStarter
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.launch
/** Binds the bouncer container to its view model. */
object KeyguardBouncerViewBinder {
@JvmStatic
fun bind(
view: ViewGroup,
viewModel: KeyguardBouncerViewModel,
primaryBouncerToGoneTransitionViewModel: PrimaryBouncerToGoneTransitionViewModel,
componentFactory: KeyguardBouncerComponent.Factory
) {
// Builds the KeyguardSecurityContainerController from bouncer view group.
val securityContainerController: KeyguardSecurityContainerController =
componentFactory.create(view).securityContainerController
securityContainerController.init()
val delegate =
object : BouncerViewDelegate {
override fun isFullScreenBouncer(): Boolean {
val mode = securityContainerController.currentSecurityMode
return mode == KeyguardSecurityModel.SecurityMode.SimPin ||
mode == KeyguardSecurityModel.SecurityMode.SimPuk
}
override fun getBackCallback(): OnBackAnimationCallback {
return securityContainerController.backCallback
}
override fun shouldDismissOnMenuPressed(): Boolean {
return securityContainerController.shouldEnableMenuKey()
}
override fun interceptMediaKey(event: KeyEvent?): Boolean {
return securityContainerController.interceptMediaKey(event)
}
override fun dispatchBackKeyEventPreIme(): Boolean {
return securityContainerController.dispatchBackKeyEventPreIme()
}
override fun showNextSecurityScreenOrFinish(): Boolean {
return securityContainerController.dismiss(
KeyguardUpdateMonitor.getCurrentUser()
)
}
override fun resume() {
securityContainerController.showPrimarySecurityScreen(/* isTurningOff= */ false)
securityContainerController.onResume(KeyguardSecurityView.SCREEN_ON)
}
override fun setDismissAction(
onDismissAction: ActivityStarter.OnDismissAction?,
cancelAction: Runnable?
) {
securityContainerController.setOnDismissAction(onDismissAction, cancelAction)
}
override fun willDismissWithActions(): Boolean {
return securityContainerController.hasDismissActions()
}
}
view.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.CREATED) {
try {
viewModel.setBouncerViewDelegate(delegate)
launch {
viewModel.show.collect {
// Reset Security Container entirely.
securityContainerController.reinflateViewFlipper()
securityContainerController.showPromptReason(it.promptReason)
it.errorMessage?.let { errorMessage ->
securityContainerController.showMessage(
errorMessage,
Utils.getColorError(view.context)
)
}
securityContainerController.showPrimarySecurityScreen(
/* turningOff= */ false
)
securityContainerController.appear()
securityContainerController.onResume(KeyguardSecurityView.SCREEN_ON)
}
}
launch {
viewModel.hide.collect {
securityContainerController.cancelDismissAction()
securityContainerController.reset()
}
}
launch {
viewModel.startingToHide.collect {
securityContainerController.onStartingToHide()
}
}
launch {
viewModel.startDisappearAnimation.collect {
securityContainerController.startDisappearAnimation(it)
}
}
launch {
viewModel.bouncerExpansionAmount.collect { expansion ->
securityContainerController.setExpansion(expansion)
}
}
launch {
primaryBouncerToGoneTransitionViewModel.bouncerAlpha.collect { alpha ->
securityContainerController.setAlpha(alpha)
}
}
launch {
viewModel.bouncerExpansionAmount
.filter { it == EXPANSION_VISIBLE }
.collect {
securityContainerController.onResume(KeyguardSecurityView.SCREEN_ON)
view.announceForAccessibility(securityContainerController.title)
}
}
launch {
viewModel.isBouncerVisible.collect { isVisible ->
view.visibility = if (isVisible) View.VISIBLE else View.INVISIBLE
securityContainerController.onBouncerVisibilityChanged(isVisible)
}
}
launch {
viewModel.isBouncerVisible
.filter { !it }
.collect { securityContainerController.onPause() }
}
launch {
viewModel.isInteractable.collect { isInteractable ->
securityContainerController.setInteractable(isInteractable)
}
}
launch {
viewModel.keyguardPosition.collect { position ->
securityContainerController.updateKeyguardPosition(position)
}
}
launch {
viewModel.updateResources.collect {
securityContainerController.updateResources()
viewModel.notifyUpdateResources()
}
}
launch {
viewModel.bouncerShowMessage.collect {
securityContainerController.showMessage(it.message, it.colorStateList)
viewModel.onMessageShown()
}
}
launch {
viewModel.keyguardAuthenticated.collect {
securityContainerController.finish(
it,
KeyguardUpdateMonitor.getCurrentUser()
)
viewModel.notifyKeyguardAuthenticated()
}
}
launch {
viewModel
.observeOnIsBackButtonEnabled { view.systemUiVisibility }
.collect { view.systemUiVisibility = it }
}
launch {
viewModel.shouldUpdateSideFps.collect {
viewModel.updateSideFpsVisibility()
}
}
launch {
viewModel.sideFpsShowing.collect {
securityContainerController.updateSideFpsVisibility(it)
}
}
awaitCancellation()
} finally {
viewModel.setBouncerViewDelegate(null)
}
}
}
}
}