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.shade.ShadeDisplayAware 33 import com.android.systemui.util.kotlin.pairwise 34 import javax.inject.Inject 35 import kotlin.time.Duration.Companion.milliseconds 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 @SysUISingleton 47 class OccludedToLockscreenTransitionViewModel 48 @Inject 49 constructor( 50 deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, 51 @ShadeDisplayAware configurationInteractor: ConfigurationInteractor, 52 animationFlow: KeyguardTransitionAnimationFlow, 53 keyguardInteractor: KeyguardInteractor, 54 keyguardTransitionInteractor: KeyguardTransitionInteractor, 55 ) : DeviceEntryIconTransition { 56 57 private val transitionAnimation = 58 animationFlow.setup( 59 duration = TO_LOCKSCREEN_DURATION, 60 edge = Edge.create(from = OCCLUDED, to = LOCKSCREEN), 61 ) 62 63 /** Lockscreen views y-translation */ 64 val lockscreenTranslationY: Flow<Float> = 65 configurationInteractor 66 .dimensionPixelSize(R.dimen.occluded_to_lockscreen_transition_lockscreen_translation_y) 67 .flatMapLatest { translatePx -> 68 transitionAnimation.sharedFlow( 69 duration = TO_LOCKSCREEN_DURATION, 70 onStep = { value -> -translatePx + value * translatePx }, 71 interpolator = EMPHASIZED_DECELERATE, 72 onCancel = { 0f }, 73 ) 74 } 75 76 val shortcutsAlpha: Flow<Float> = 77 transitionAnimation.sharedFlow( 78 duration = 250.milliseconds, 79 onStep = { it }, 80 onCancel = { 0f }, 81 ) 82 83 /** Lockscreen views alpha */ 84 val lockscreenAlpha: Flow<Float> = 85 merge( 86 transitionAnimation.sharedFlow( 87 startTime = 233.milliseconds, 88 duration = 250.milliseconds, 89 onStep = { it }, 90 name = "OCCLUDED->LOCKSCREEN: lockscreenAlpha", 91 ), 92 // Required to fix a bug where the shade expands while lockscreenAlpha=1f, due to a call 93 // to setOccluded(false) triggering a reset() call in KeyguardViewMediator. The 94 // permanent solution is to only expand the shade once the keyguard transition from 95 // OCCLUDED starts, but that requires more refactoring of expansion amounts. For now, 96 // emit alpha = 0f for OCCLUDED -> LOCKSCREEN whenever isOccluded flips from true to 97 // false while currentState == OCCLUDED, so that alpha = 0f when that expansion occurs. 98 // TODO(b/332946323): Remove this once it's no longer needed. 99 keyguardInteractor.isKeyguardOccluded 100 .pairwise() 101 .filter { (wasOccluded, isOccluded) -> 102 wasOccluded && 103 !isOccluded && 104 keyguardTransitionInteractor.getCurrentState() == OCCLUDED 105 } 106 .map { 0f }, 107 ) 108 109 val deviceEntryBackgroundViewAlpha: Flow<Float> = 110 transitionAnimation.immediatelyTransitionTo(1f) 111 112 override val deviceEntryParentViewAlpha: Flow<Float> = 113 transitionAnimation.sharedFlow( 114 startTime = 233.milliseconds, 115 duration = 250.milliseconds, 116 onStep = { it }, 117 onCancel = { 1f }, 118 ) 119 } 120