1 /* 2 * Copyright (C) 2019 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.statusbar.phone 18 19 import android.content.Context 20 import android.content.pm.PackageManager 21 import android.hardware.Sensor 22 import android.hardware.TriggerEvent 23 import android.hardware.TriggerEventListener 24 import com.android.keyguard.ActiveUnlockConfig 25 import com.android.keyguard.FaceAuthApiRequestReason 26 import com.android.keyguard.KeyguardUpdateMonitor 27 import com.android.keyguard.KeyguardUpdateMonitorCallback 28 import com.android.systemui.CoreStartable 29 import com.android.systemui.Dumpable 30 import com.android.systemui.dagger.SysUISingleton 31 import com.android.systemui.dump.DumpManager 32 import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor 33 import com.android.systemui.plugins.statusbar.StatusBarStateController 34 import com.android.systemui.util.Assert 35 import com.android.systemui.util.sensors.AsyncSensorManager 36 import java.io.PrintWriter 37 import javax.inject.Inject 38 39 /** 40 * Triggers face auth on lift when the device is showing the lock screen. Only initialized 41 * if face auth is supported on the device. Not to be confused with the lift to wake gesture 42 * which is handled by {@link com.android.server.policy.PhoneWindowManager}. 43 */ 44 @SysUISingleton 45 class KeyguardLiftController @Inject constructor( 46 private val context: Context, 47 private val statusBarStateController: StatusBarStateController, 48 private val asyncSensorManager: AsyncSensorManager, 49 private val keyguardUpdateMonitor: KeyguardUpdateMonitor, 50 private val keyguardFaceAuthInteractor: KeyguardFaceAuthInteractor, 51 private val dumpManager: DumpManager 52 ) : Dumpable, CoreStartable { 53 54 private val pickupSensor = asyncSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE) 55 private var isListening = false 56 private var bouncerVisible = false 57 58 override fun start() { 59 if (context.packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)) { 60 init() 61 } 62 } 63 64 private fun init() { 65 dumpManager.registerDumpable(javaClass.name, this) 66 statusBarStateController.addCallback(statusBarStateListener) 67 keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback) 68 updateListeningState() 69 } 70 71 private val listener: TriggerEventListener = object : TriggerEventListener() { 72 override fun onTrigger(event: TriggerEvent?) { 73 Assert.isMainThread() 74 // Not listening anymore since trigger events unregister themselves 75 isListening = false 76 updateListeningState() 77 keyguardFaceAuthInteractor.onDeviceLifted() 78 keyguardUpdateMonitor.requestFaceAuth( 79 FaceAuthApiRequestReason.PICK_UP_GESTURE_TRIGGERED 80 ) 81 keyguardUpdateMonitor.requestActiveUnlock( 82 ActiveUnlockConfig.ActiveUnlockRequestOrigin.WAKE, 83 "KeyguardLiftController") 84 } 85 } 86 87 private val keyguardUpdateMonitorCallback = object : KeyguardUpdateMonitorCallback() { 88 override fun onKeyguardBouncerFullyShowingChanged(bouncer: Boolean) { 89 bouncerVisible = bouncer 90 updateListeningState() 91 } 92 93 override fun onKeyguardVisibilityChanged(visible: Boolean) { 94 updateListeningState() 95 } 96 } 97 98 private val statusBarStateListener = object : StatusBarStateController.StateListener { 99 override fun onDozingChanged(isDozing: Boolean) { 100 updateListeningState() 101 } 102 } 103 104 override fun dump(pw: PrintWriter, args: Array<out String>) { 105 pw.println("KeyguardLiftController:") 106 pw.println(" pickupSensor: $pickupSensor") 107 pw.println(" isListening: $isListening") 108 pw.println(" bouncerVisible: $bouncerVisible") 109 } 110 111 private fun updateListeningState() { 112 if (pickupSensor == null) { 113 return 114 } 115 val onKeyguard = keyguardUpdateMonitor.isKeyguardVisible && 116 !statusBarStateController.isDozing 117 118 val userId = KeyguardUpdateMonitor.getCurrentUser() 119 val isFaceEnabled = keyguardUpdateMonitor.isFaceAuthEnabledForUser(userId) 120 val shouldListen = (onKeyguard || bouncerVisible) && isFaceEnabled 121 if (shouldListen != isListening) { 122 isListening = shouldListen 123 124 if (shouldListen) { 125 asyncSensorManager.requestTriggerSensor(listener, pickupSensor) 126 } else { 127 asyncSensorManager.cancelTriggerSensor(listener, pickupSensor) 128 } 129 } 130 } 131 } 132