• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 @file:OptIn(ExperimentalCoroutinesApi::class)
18 
19 package com.android.systemui.keyguard.data.repository
20 
21 import android.content.Context
22 import android.graphics.Point
23 import com.android.systemui.R
24 import com.android.systemui.dagger.SysUISingleton
25 import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
26 import com.android.systemui.keyguard.shared.model.BiometricUnlockSource
27 import com.android.systemui.keyguard.shared.model.WakeSleepReason
28 import com.android.systemui.statusbar.CircleReveal
29 import com.android.systemui.statusbar.LiftReveal
30 import com.android.systemui.statusbar.LightRevealEffect
31 import com.android.systemui.statusbar.PowerButtonReveal
32 import javax.inject.Inject
33 import kotlin.math.max
34 import kotlinx.coroutines.ExperimentalCoroutinesApi
35 import kotlinx.coroutines.flow.Flow
36 import kotlinx.coroutines.flow.combine
37 import kotlinx.coroutines.flow.distinctUntilChanged
38 import kotlinx.coroutines.flow.flatMapLatest
39 import kotlinx.coroutines.flow.flowOf
40 import kotlinx.coroutines.flow.map
41 
42 val DEFAULT_REVEAL_EFFECT = LiftReveal
43 
44 /**
45  * Encapsulates state relevant to the light reveal scrim, the view used to reveal/hide screen
46  * contents during transitions between AOD and lockscreen/unlocked.
47  */
48 interface LightRevealScrimRepository {
49 
50     /**
51      * The reveal effect that should be used for the next lock/unlock. We switch between either the
52      * biometric unlock effect (if wake and unlocking) or the non-biometric effect, and position it
53      * at the current screen position of the appropriate sensor.
54      */
55     val revealEffect: Flow<LightRevealEffect>
56 }
57 
58 @SysUISingleton
59 class LightRevealScrimRepositoryImpl
60 @Inject
61 constructor(
62     keyguardRepository: KeyguardRepository,
63     val context: Context,
64 ) : LightRevealScrimRepository {
65 
66     /** The reveal effect used if the device was locked/unlocked via the power button. */
67     private val powerButtonReveal =
68         PowerButtonReveal(
69             context.resources
70                 .getDimensionPixelSize(R.dimen.physical_power_button_center_screen_location_y)
71                 .toFloat()
72         )
73 
74     /**
75      * Reveal effect to use for a fingerprint unlock. This is reconstructed if the fingerprint
76      * sensor location on the screen (in pixels) changes due to configuration changes.
77      */
78     private val fingerprintRevealEffect: Flow<LightRevealEffect?> =
<lambda>null79         keyguardRepository.fingerprintSensorLocation.map {
80             it?.let { constructCircleRevealFromPoint(it) }
81         }
82 
83     /**
84      * Reveal effect to use for a face unlock. This is reconstructed if the face sensor/front camera
85      * location on the screen (in pixels) changes due to configuration changes.
86      */
87     private val faceRevealEffect: Flow<LightRevealEffect?> =
<lambda>null88         keyguardRepository.faceSensorLocation.map { it?.let { constructCircleRevealFromPoint(it) } }
89 
90     /**
91      * The reveal effect we'll use for the next biometric unlock animation. We switch between the
92      * fingerprint/face unlock effect flows depending on the biometric unlock source.
93      */
94     private val biometricRevealEffect: Flow<LightRevealEffect?> =
sourcenull95         keyguardRepository.biometricUnlockSource.flatMapLatest { source ->
96             when (source) {
97                 BiometricUnlockSource.FINGERPRINT_SENSOR -> fingerprintRevealEffect
98                 BiometricUnlockSource.FACE_SENSOR -> faceRevealEffect
99                 else -> flowOf(null)
100             }
101         }
102 
103     /** The reveal effect we'll use for the next non-biometric unlock (tap, power button, etc). */
104     private val nonBiometricRevealEffect: Flow<LightRevealEffect?> =
wakefulnessModelnull105         keyguardRepository.wakefulness.map { wakefulnessModel ->
106             val wakingUpFromPowerButton =
107                 wakefulnessModel.isWakingUpOrAwake &&
108                     wakefulnessModel.lastWakeReason == WakeSleepReason.POWER_BUTTON
109             val sleepingFromPowerButton =
110                 !wakefulnessModel.isWakingUpOrAwake &&
111                     wakefulnessModel.lastSleepReason == WakeSleepReason.POWER_BUTTON
112 
113             if (wakingUpFromPowerButton || sleepingFromPowerButton) {
114                 powerButtonReveal
115             } else {
116                 LiftReveal
117             }
118         }
119 
120     override val revealEffect =
121         combine(
122                 keyguardRepository.biometricUnlockState,
123                 biometricRevealEffect,
124                 nonBiometricRevealEffect
biometricRevealnull125             ) { biometricUnlockState, biometricReveal, nonBiometricReveal ->
126 
127                 // Use the biometric reveal for any flavor of wake and unlocking.
128                 when (biometricUnlockState) {
129                     BiometricUnlockModel.WAKE_AND_UNLOCK,
130                     BiometricUnlockModel.WAKE_AND_UNLOCK_PULSING,
131                     BiometricUnlockModel.WAKE_AND_UNLOCK_FROM_DREAM -> biometricReveal
132                     else -> nonBiometricReveal
133                 }
134                     ?: DEFAULT_REVEAL_EFFECT
135             }
136             .distinctUntilChanged()
137 
constructCircleRevealFromPointnull138     private fun constructCircleRevealFromPoint(point: Point): LightRevealEffect {
139         return with(point) {
140             CircleReveal(
141                 x,
142                 y,
143                 startRadius = 0,
144                 endRadius =
145                     max(max(x, context.display.width - x), max(y, context.display.height - y)),
146             )
147         }
148     }
149 }
150