• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.android.app.tracing.coroutines.launchTraced as launch
20 import com.android.internal.policy.IKeyguardDismissCallback
21 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
22 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
23 import com.android.systemui.dagger.SysUISingleton
24 import com.android.systemui.dagger.qualifiers.Application
25 import com.android.systemui.dagger.qualifiers.Main
26 import com.android.systemui.keyguard.DismissCallbackRegistry
27 import com.android.systemui.keyguard.data.repository.KeyguardRepository
28 import com.android.systemui.keyguard.data.repository.TrustRepository
29 import com.android.systemui.keyguard.shared.model.DismissAction
30 import com.android.systemui.keyguard.shared.model.KeyguardDone
31 import com.android.systemui.power.domain.interactor.PowerInteractor
32 import com.android.systemui.user.domain.interactor.SelectedUserInteractor
33 import com.android.systemui.util.kotlin.Utils.Companion.toQuad
34 import com.android.systemui.util.kotlin.sample
35 import javax.inject.Inject
36 import kotlinx.coroutines.CoroutineDispatcher
37 import kotlinx.coroutines.CoroutineScope
38 import kotlinx.coroutines.flow.Flow
39 import kotlinx.coroutines.flow.combine
40 import kotlinx.coroutines.flow.filter
41 import kotlinx.coroutines.flow.map
42 import kotlinx.coroutines.flow.merge
43 import kotlinx.coroutines.withContext
44 
45 /** Encapsulates business logic for requesting the keyguard to dismiss/finish/done. */
46 @SysUISingleton
47 class KeyguardDismissInteractor
48 @Inject
49 constructor(
50     @Main private val mainDispatcher: CoroutineDispatcher,
51     @Application private val scope: CoroutineScope,
52     private val keyguardRepository: KeyguardRepository,
53     private val primaryBouncerInteractor: PrimaryBouncerInteractor,
54     private val selectedUserInteractor: SelectedUserInteractor,
55     private val dismissCallbackRegistry: DismissCallbackRegistry,
56     private val alternateBouncerInteractor: AlternateBouncerInteractor,
57     trustRepository: TrustRepository,
58     powerInteractor: PowerInteractor,
59 ) {
60     /*
61      * Updates when a biometric has authenticated the device and is requesting to dismiss
62      * the keyguard. When true, a class 3 biometrics has authenticated. Else, a lower class
63      * biometric strength has authenticated and is requesting to dismiss the keyguard.
64      */
65     private val biometricAuthenticatedRequestDismissKeyguard: Flow<Unit> =
66         primaryBouncerInteractor.keyguardAuthenticatedBiometrics.map {} // map to Unit
67 
68     /*
69      * Updates when a trust change is requesting to dismiss the keyguard and is able to do so
70      * in the current device state.
71      */
72     private val onTrustGrantedRequestDismissKeyguard: Flow<Unit> =
73         trustRepository.trustAgentRequestingToDismissKeyguard
74             .sample(
75                 combine(
76                     primaryBouncerInteractor.isShowing,
77                     alternateBouncerInteractor.isVisible,
78                     powerInteractor.isInteractive,
79                     ::Triple,
80                 ),
81                 ::toQuad,
82             )
83             .filter { (trustModel, primaryBouncerShowing, altBouncerShowing, interactive) ->
84                 val bouncerShowing = primaryBouncerShowing || altBouncerShowing
85                 (interactive || trustModel.flags.temporaryAndRenewable()) &&
86                     (bouncerShowing || trustModel.flags.dismissKeyguardRequested())
87             }
88             .map {} // map to Unit
89 
90     /*
91      * Updates when the current user successfully has authenticated via primary authentication
92      * (pin/pattern/password).
93      */
94     private val primaryAuthenticated: Flow<Unit> =
95         primaryBouncerInteractor.keyguardAuthenticatedPrimaryAuth
96             .filter { authedUserId -> authedUserId == selectedUserInteractor.getSelectedUserId() }
97             .map {} // map to Unit
98 
99     /*
100      * Updates when the current user requests the bouncer after they've already successfully
101      * authenticated (ie: from non-bypass face auth, from a trust agent that didn't immediately
102      * dismiss the keyguard, or if keyguard security is set to SWIPE or NONE).
103      */
104     private val userRequestedBouncerWhenAlreadyAuthenticated: Flow<Unit> =
105         primaryBouncerInteractor.userRequestedBouncerWhenAlreadyAuthenticated
106             .filter { authedUserId -> authedUserId == selectedUserInteractor.getSelectedUserId() }
107             .map {} // map to Unit
108 
109     /** Updates when keyguardDone should be requested. */
110     val keyguardDone: Flow<KeyguardDone> = keyguardRepository.keyguardDone
111 
112     /** Updates when any request to dismiss the current user's keyguard has arrived. */
113     private val dismissKeyguardRequest: Flow<DismissAction> =
114         merge(
115                 biometricAuthenticatedRequestDismissKeyguard,
116                 onTrustGrantedRequestDismissKeyguard,
117                 primaryAuthenticated,
118                 userRequestedBouncerWhenAlreadyAuthenticated,
119             )
120             .sample(keyguardRepository.dismissAction)
121 
122     /**
123      * Updates when a request to dismiss the current user's keyguard has arrived and there's a
124      * dismiss action to run immediately. It's expected that the consumer will request keyguardDone
125      * with or without a deferral.
126      */
127     val dismissKeyguardRequestWithImmediateDismissAction: Flow<Unit> =
128         dismissKeyguardRequest.filter { it is DismissAction.RunImmediately }.map {} // map to Unit
129 
130     /**
131      * Updates when a request to dismiss the current user's keyguard has arrived and there's isn't a
132      * dismiss action to run immediately. There may still be a dismiss action to run after the
133      * keyguard transitions to GONE.
134      */
135     val dismissKeyguardRequestWithoutImmediateDismissAction: Flow<Unit> =
136         dismissKeyguardRequest.filter { it !is DismissAction.RunImmediately }.map {} // map to Unit
137 
138     suspend fun setKeyguardDone(keyguardDoneTiming: KeyguardDone) {
139         keyguardRepository.setKeyguardDone(keyguardDoneTiming)
140     }
141 
142     /**
143      * Dismiss the keyguard (or show the bouncer) and invoke the provided callback once dismissed.
144      *
145      * TODO(b/358412565): Support dismiss messages.
146      */
147     fun dismissKeyguardWithCallback(callback: IKeyguardDismissCallback?) {
148         scope.launch {
149             withContext(mainDispatcher) {
150                 if (callback != null) {
151                     dismissCallbackRegistry.addCallback(callback)
152                 }
153 
154                 // This will either show the bouncer, or dismiss the keyguard if insecure. We
155                 // currently need to request showing the bouncer in order to start a transition to
156                 // *_BOUNCER. Once we refactor that so that starting the transition is what causes
157                 // the bouncer to show, we can remove this entire method, and simply call
158                 // KeyguardDismissTransitionInteractor#startDismissKeyguardTransition.
159                 if (alternateBouncerInteractor.canShowAlternateBouncer.value) {
160                     alternateBouncerInteractor.forceShow()
161                 } else {
162                     primaryBouncerInteractor.show(
163                         true,
164                         "KeyguardDismissInteractor#dismissKeyguardWithCallback",
165                     )
166                 }
167             }
168         }
169     }
170 }
171