1 /*
2  *  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 
18 package com.android.systemui.keyguard.domain.interactor
19 
20 import android.animation.FloatEvaluator
21 import android.animation.IntEvaluator
22 import com.android.systemui.common.ui.data.repository.ConfigurationRepository
23 import com.android.systemui.dagger.SysUISingleton
24 import com.android.systemui.keyguard.shared.model.StatusBarState
25 import com.android.systemui.shade.data.repository.ShadeRepository
26 import com.android.systemui.statusbar.phone.SystemUIDialogManager
27 import com.android.systemui.statusbar.phone.hideAffordancesRequest
28 import javax.inject.Inject
29 import kotlinx.coroutines.ExperimentalCoroutinesApi
30 import kotlinx.coroutines.flow.Flow
31 import kotlinx.coroutines.flow.combine
32 import kotlinx.coroutines.flow.map
33 import kotlinx.coroutines.flow.onStart
34 
35 /** Encapsulates business logic for transitions between UDFPS states on the keyguard. */
36 @ExperimentalCoroutinesApi
37 @SysUISingleton
38 class UdfpsKeyguardInteractor
39 @Inject
40 constructor(
41     configRepo: ConfigurationRepository,
42     burnInInteractor: BurnInInteractor,
43     keyguardInteractor: KeyguardInteractor,
44     shadeRepository: ShadeRepository,
45     dialogManager: SystemUIDialogManager,
46 ) {
47     private val intEvaluator = IntEvaluator()
48     private val floatEvaluator = FloatEvaluator()
49 
50     val dozeAmount = keyguardInteractor.dozeAmount
51     val scaleForResolution = configRepo.scaleForResolution
52 
53     /** Burn-in offsets for the UDFPS view to mitigate burn-in on AOD. */
54     val burnInOffsets: Flow<BurnInOffsets> =
55         combine(
56             keyguardInteractor.dozeAmount,
57             burnInInteractor.udfpsBurnInXOffset,
58             burnInInteractor.udfpsBurnInYOffset,
59             burnInInteractor.udfpsBurnInProgress
60         ) { dozeAmount, fullyDozingBurnInX, fullyDozingBurnInY, fullyDozingBurnInProgress ->
61             BurnInOffsets(
62                 intEvaluator.evaluate(dozeAmount, 0, fullyDozingBurnInX),
63                 intEvaluator.evaluate(dozeAmount, 0, fullyDozingBurnInY),
64                 floatEvaluator.evaluate(dozeAmount, 0, fullyDozingBurnInProgress),
65             )
66         }
67 
68     val dialogHideAffordancesRequest: Flow<Boolean> = dialogManager.hideAffordancesRequest
69 
70     val qsProgress: Flow<Float> =
71         shadeRepository.qsExpansion // swipe from top of LS
72             .map { (it * 2).coerceIn(0f, 1f) }
73             .onStart { emit(0f) }
74 
75     val shadeExpansion: Flow<Float> =
76         combine(
77                 shadeRepository.udfpsTransitionToFullShadeProgress, // swipe from middle of LS
78                 keyguardInteractor.statusBarState, // quick swipe from middle of LS
79             ) { shadeProgress, statusBarState ->
80                 if (statusBarState == StatusBarState.SHADE_LOCKED) {
81                     1f
82                 } else {
83                     shadeProgress
84                 }
85             }
86             .onStart { emit(0f) }
87 }
88 
89 data class BurnInOffsets(
90     val burnInXOffset: Int, // current x burn in offset based on the aodTransitionAmount
91     val burnInYOffset: Int, // current y burn in offset based on the aodTransitionAmount
92     val burnInProgress: Float, // current progress based on the aodTransitionAmount
93 )
94