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.keyguard.ui.viewmodel 18 19 import com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE 20 import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor 21 import com.android.systemui.dagger.SysUISingleton 22 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor 23 import com.android.systemui.keyguard.domain.interactor.FromOccludedTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION 24 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor 25 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor 26 import com.android.systemui.keyguard.shared.model.Edge 27 import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN 28 import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED 29 import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow 30 import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition 31 import com.android.systemui.res.R 32 import com.android.systemui.util.kotlin.pairwise 33 import javax.inject.Inject 34 import kotlin.time.Duration.Companion.milliseconds 35 import kotlinx.coroutines.ExperimentalCoroutinesApi 36 import kotlinx.coroutines.flow.Flow 37 import kotlinx.coroutines.flow.filter 38 import kotlinx.coroutines.flow.flatMapLatest 39 import kotlinx.coroutines.flow.map 40 import kotlinx.coroutines.flow.merge 41 42 /** 43 * Breaks down OCCLUDED->LOCKSCREEN transition into discrete steps for corresponding views to 44 * consume. 45 */ 46 @ExperimentalCoroutinesApi 47 @SysUISingleton 48 class OccludedToLockscreenTransitionViewModel 49 @Inject 50 constructor( 51 deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, 52 configurationInteractor: ConfigurationInteractor, 53 animationFlow: KeyguardTransitionAnimationFlow, 54 keyguardInteractor: KeyguardInteractor, 55 keyguardTransitionInteractor: KeyguardTransitionInteractor, 56 ) : DeviceEntryIconTransition { 57 58 private val transitionAnimation = 59 animationFlow.setup( 60 duration = TO_LOCKSCREEN_DURATION, 61 edge = Edge.create(from = OCCLUDED, to = LOCKSCREEN), 62 ) 63 64 /** Lockscreen views y-translation */ 65 val lockscreenTranslationY: Flow<Float> = 66 configurationInteractor 67 .dimensionPixelSize(R.dimen.occluded_to_lockscreen_transition_lockscreen_translation_y) 68 .flatMapLatest { translatePx -> 69 transitionAnimation.sharedFlow( 70 duration = TO_LOCKSCREEN_DURATION, 71 onStep = { value -> -translatePx + value * translatePx }, 72 interpolator = EMPHASIZED_DECELERATE, 73 onCancel = { 0f }, 74 ) 75 } 76 77 val shortcutsAlpha: Flow<Float> = 78 transitionAnimation.sharedFlow( 79 duration = 250.milliseconds, 80 onStep = { it }, 81 onCancel = { 0f }, 82 ) 83 84 /** Lockscreen views alpha */ 85 val lockscreenAlpha: Flow<Float> = 86 merge( 87 transitionAnimation.sharedFlow( 88 startTime = 233.milliseconds, 89 duration = 250.milliseconds, 90 onStep = { it }, 91 name = "OCCLUDED->LOCKSCREEN: lockscreenAlpha", 92 ), 93 // Required to fix a bug where the shade expands while lockscreenAlpha=1f, due to a call 94 // to setOccluded(false) triggering a reset() call in KeyguardViewMediator. The 95 // permanent solution is to only expand the shade once the keyguard transition from 96 // OCCLUDED starts, but that requires more refactoring of expansion amounts. For now, 97 // emit alpha = 0f for OCCLUDED -> LOCKSCREEN whenever isOccluded flips from true to 98 // false while currentState == OCCLUDED, so that alpha = 0f when that expansion occurs. 99 // TODO(b/332946323): Remove this once it's no longer needed. 100 keyguardInteractor.isKeyguardOccluded 101 .pairwise() 102 .filter { (wasOccluded, isOccluded) -> 103 wasOccluded && 104 !isOccluded && 105 keyguardTransitionInteractor.getCurrentState() == OCCLUDED 106 } 107 .map { 0f } 108 ) 109 110 val deviceEntryBackgroundViewAlpha: Flow<Float> = 111 transitionAnimation.immediatelyTransitionTo(1f) 112 113 override val deviceEntryParentViewAlpha: Flow<Float> = lockscreenAlpha 114 } 115