1 /* <lambda>null2 * Copyright (C) 2023 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.keyguard.domain.interactor 18 19 import android.animation.ValueAnimator 20 import com.android.systemui.animation.Interpolators 21 import com.android.systemui.dagger.SysUISingleton 22 import com.android.systemui.dagger.qualifiers.Application 23 import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository 24 import com.android.systemui.keyguard.shared.model.KeyguardState 25 import com.android.systemui.keyguard.shared.model.TransitionInfo 26 import com.android.systemui.keyguard.shared.model.WakefulnessState 27 import com.android.systemui.util.kotlin.sample 28 import javax.inject.Inject 29 import kotlinx.coroutines.CoroutineScope 30 import kotlinx.coroutines.delay 31 import kotlinx.coroutines.flow.combine 32 import kotlinx.coroutines.flow.onEach 33 import kotlinx.coroutines.launch 34 35 @SysUISingleton 36 class FromAlternateBouncerTransitionInteractor 37 @Inject 38 constructor( 39 @Application private val scope: CoroutineScope, 40 private val keyguardInteractor: KeyguardInteractor, 41 private val keyguardTransitionRepository: KeyguardTransitionRepository, 42 private val keyguardTransitionInteractor: KeyguardTransitionInteractor, 43 ) : TransitionInteractor(FromAlternateBouncerTransitionInteractor::class.simpleName!!) { 44 45 override fun start() { 46 listenForAlternateBouncerToGone() 47 listenForAlternateBouncerToLockscreenAodOrDozing() 48 listenForAlternateBouncerToPrimaryBouncer() 49 } 50 51 private fun listenForAlternateBouncerToLockscreenAodOrDozing() { 52 scope.launch { 53 keyguardInteractor.alternateBouncerShowing 54 // Add a slight delay, as alternateBouncer and primaryBouncer showing event changes 55 // will arrive with a small gap in time. This prevents a transition to LOCKSCREEN 56 // happening prematurely. 57 .onEach { delay(50) } 58 .sample( 59 combine( 60 keyguardInteractor.primaryBouncerShowing, 61 keyguardTransitionInteractor.startedKeyguardTransitionStep, 62 keyguardInteractor.wakefulnessModel, 63 keyguardInteractor.isAodAvailable, 64 ::toQuad 65 ), 66 ::toQuint 67 ) 68 .collect { 69 ( 70 isAlternateBouncerShowing, 71 isPrimaryBouncerShowing, 72 lastStartedTransitionStep, 73 wakefulnessState, 74 isAodAvailable) -> 75 if ( 76 !isAlternateBouncerShowing && 77 !isPrimaryBouncerShowing && 78 lastStartedTransitionStep.to == KeyguardState.ALTERNATE_BOUNCER 79 ) { 80 val to = 81 if ( 82 wakefulnessState.state == WakefulnessState.STARTING_TO_SLEEP || 83 wakefulnessState.state == WakefulnessState.ASLEEP 84 ) { 85 if (isAodAvailable) { 86 KeyguardState.AOD 87 } else { 88 KeyguardState.DOZING 89 } 90 } else { 91 KeyguardState.LOCKSCREEN 92 } 93 keyguardTransitionRepository.startTransition( 94 TransitionInfo( 95 ownerName = name, 96 from = KeyguardState.ALTERNATE_BOUNCER, 97 to = to, 98 animator = getAnimator(), 99 ) 100 ) 101 } 102 } 103 } 104 } 105 106 private fun listenForAlternateBouncerToGone() { 107 scope.launch { 108 keyguardInteractor.isKeyguardGoingAway 109 .sample(keyguardTransitionInteractor.finishedKeyguardState, ::Pair) 110 .collect { (isKeyguardGoingAway, keyguardState) -> 111 if (isKeyguardGoingAway && keyguardState == KeyguardState.ALTERNATE_BOUNCER) { 112 keyguardTransitionRepository.startTransition( 113 TransitionInfo( 114 ownerName = name, 115 from = KeyguardState.ALTERNATE_BOUNCER, 116 to = KeyguardState.GONE, 117 animator = getAnimator(), 118 ) 119 ) 120 } 121 } 122 } 123 } 124 125 private fun listenForAlternateBouncerToPrimaryBouncer() { 126 scope.launch { 127 keyguardInteractor.primaryBouncerShowing 128 .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair) 129 .collect { (isPrimaryBouncerShowing, startedKeyguardState) -> 130 if ( 131 isPrimaryBouncerShowing && 132 startedKeyguardState.to == KeyguardState.ALTERNATE_BOUNCER 133 ) { 134 keyguardTransitionRepository.startTransition( 135 TransitionInfo( 136 ownerName = name, 137 from = KeyguardState.ALTERNATE_BOUNCER, 138 to = KeyguardState.PRIMARY_BOUNCER, 139 animator = getAnimator(), 140 ) 141 ) 142 } 143 } 144 } 145 } 146 147 private fun getAnimator(): ValueAnimator { 148 return ValueAnimator().apply { 149 interpolator = Interpolators.LINEAR 150 duration = TRANSITION_DURATION_MS 151 } 152 } 153 154 companion object { 155 private const val TRANSITION_DURATION_MS = 300L 156 } 157 } 158