• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2024 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.deviceentry.ui.binder
18 
19 import android.content.pm.PackageManager
20 import android.hardware.Sensor
21 import android.hardware.TriggerEvent
22 import android.hardware.TriggerEventListener
23 import com.android.keyguard.ActiveUnlockConfig
24 import com.android.keyguard.KeyguardUpdateMonitor
25 import com.android.systemui.CoreStartable
26 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
27 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
28 import com.android.systemui.dagger.SysUISingleton
29 import com.android.systemui.dagger.qualifiers.Application
30 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor
31 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
32 import com.android.systemui.power.domain.interactor.PowerInteractor
33 import com.android.systemui.util.Assert
34 import com.android.systemui.util.sensors.AsyncSensorManager
35 import java.io.PrintWriter
36 import javax.inject.Inject
37 import kotlinx.coroutines.CoroutineScope
38 import kotlinx.coroutines.flow.Flow
39 import kotlinx.coroutines.flow.MutableStateFlow
40 import kotlinx.coroutines.flow.combine
41 import kotlinx.coroutines.flow.filterNot
42 import kotlinx.coroutines.flow.map
43 import com.android.app.tracing.coroutines.launchTraced as launch
44 
45 /**
46  * Triggers face auth and active unlock on lift when the device is showing the lock screen or
47  * bouncer. Only initialized if face auth is supported on the device. Not to be confused with the
48  * lift to wake gesture which is handled by {@link com.android.server.policy.PhoneWindowManager}.
49  */
50 @SysUISingleton
51 class LiftToRunFaceAuthBinder
52 @Inject
53 constructor(
54     @Application private val scope: CoroutineScope,
55     private val packageManager: PackageManager,
56     private val asyncSensorManager: AsyncSensorManager,
57     private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
58     keyguardInteractor: KeyguardInteractor,
59     primaryBouncerInteractor: PrimaryBouncerInteractor,
60     alternateBouncerInteractor: AlternateBouncerInteractor,
61     private val deviceEntryFaceAuthInteractor: DeviceEntryFaceAuthInteractor,
62     powerInteractor: PowerInteractor,
63 ) : CoreStartable {
64 
65     private var pickupSensor: Sensor? = null
66     private val isListening: MutableStateFlow<Boolean> = MutableStateFlow(false)
67     private val stoppedListening: Flow<Unit> = isListening.filterNot { it }.map {} // map to Unit
68 
69     private val onAwakeKeyguard: Flow<Boolean> =
70         combine(
71             powerInteractor.isInteractive,
72             keyguardInteractor.isKeyguardVisible,
73         ) { isInteractive, isKeyguardVisible ->
74             isInteractive && isKeyguardVisible
75         }
76     private val bouncerShowing: Flow<Boolean> =
77         combine(
78             primaryBouncerInteractor.isShowing,
79             alternateBouncerInteractor.isVisible,
80         ) { primaryBouncerShowing, alternateBouncerShowing ->
81             primaryBouncerShowing || alternateBouncerShowing
82         }
83     private val listenForPickupSensor: Flow<Boolean> =
84         combine(
85             stoppedListening,
86             bouncerShowing,
87             onAwakeKeyguard,
88         ) { _, bouncerShowing, onAwakeKeyguard ->
89             (onAwakeKeyguard || bouncerShowing) &&
90                 deviceEntryFaceAuthInteractor.isFaceAuthEnabledAndEnrolled()
91         }
92 
93     override fun start() {
94         if (packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)) {
95             init()
96         }
97     }
98 
99     private fun init() {
100         pickupSensor = asyncSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE)
101         scope.launch {
102             listenForPickupSensor.collect { listenForPickupSensor ->
103                 updateListeningState(listenForPickupSensor)
104             }
105         }
106     }
107 
108     private val listener: TriggerEventListener =
109         object : TriggerEventListener() {
110             override fun onTrigger(event: TriggerEvent?) {
111                 Assert.isMainThread()
112                 deviceEntryFaceAuthInteractor.onDeviceLifted()
113                 keyguardUpdateMonitor.requestActiveUnlock(
114                     ActiveUnlockConfig.ActiveUnlockRequestOrigin.WAKE,
115                     "KeyguardLiftController"
116                 )
117 
118                 // Not listening anymore since trigger events unregister themselves
119                 isListening.value = false
120             }
121         }
122 
123     override fun dump(pw: PrintWriter, args: Array<out String>) {
124         pw.println("LiftToRunFaceAuthBinder:")
125         pw.println("  pickupSensor: $pickupSensor")
126         pw.println("  isListening: ${isListening.value}")
127     }
128 
129     private fun updateListeningState(shouldListen: Boolean) {
130         if (pickupSensor == null) {
131             return
132         }
133         if (shouldListen != isListening.value) {
134             isListening.value = shouldListen
135 
136             if (shouldListen) {
137                 asyncSensorManager.requestTriggerSensor(listener, pickupSensor)
138             } else {
139                 asyncSensorManager.cancelTriggerSensor(listener, pickupSensor)
140             }
141         }
142     }
143 }
144