blob: 3f1cb6c94e779767c4984ecd4569bf9e0644ea22 [file] [log] [blame]
Selim Cinek2c890ee2019-05-20 19:16:43 -07001/*
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
17package com.android.systemui.statusbar.phone
18
19import android.content.Context
Mady Mellordce1bf32019-06-25 14:31:19 -070020import android.content.pm.PackageManager
Selim Cinekbd84c162019-06-11 16:23:23 -070021import android.hardware.biometrics.BiometricSourceType
Lucas Dupin1b883b42019-05-28 17:43:59 -070022import android.hardware.face.FaceManager
Selim Cinek2c890ee2019-05-20 19:16:43 -070023import android.provider.Settings
Selim Cinek2c890ee2019-05-20 19:16:43 -070024import com.android.keyguard.KeyguardUpdateMonitor
Selim Cinekbd84c162019-06-11 16:23:23 -070025import com.android.systemui.plugins.statusbar.StatusBarStateController
Selim Cineka6a3ebc2019-06-19 18:33:17 -070026import com.android.systemui.statusbar.NotificationLockscreenUserManager
Selim Cinekbd84c162019-06-11 16:23:23 -070027import com.android.systemui.statusbar.StatusBarState
Selim Cinek2c890ee2019-05-20 19:16:43 -070028import com.android.systemui.tuner.TunerService
Selim Cinek2c890ee2019-05-20 19:16:43 -070029import javax.inject.Inject
30import javax.inject.Singleton
31
32@Singleton
33class KeyguardBypassController {
34
Selim Cinekbd84c162019-06-11 16:23:23 -070035 private val unlockMethodCache: UnlockMethodCache
36 private val statusBarStateController: StatusBarStateController
37
Selim Cinekb8cc6ef2019-06-14 16:37:53 -070038 /**
39 * The pending unlock type which is set if the bypass was blocked when it happened.
40 */
41 private var pendingUnlockType: BiometricSourceType? = null
Lucas Dupin206fe562019-05-31 14:36:42 -070042
Selim Cinekf89a5dc2019-06-18 15:10:25 -070043 lateinit var unlockController: BiometricUnlockController
44 var isPulseExpanding = false
45
46 /**
47 * If face unlock dismisses the lock screen or keeps user on keyguard for the current user.
48 */
49 var bypassEnabled: Boolean = false
50 get() = field && unlockMethodCache.isUnlockingWithFacePossible
51 private set
52
53 var bouncerShowing: Boolean = false
Selim Cinekec177752019-06-19 18:13:51 -070054 var launchingAffordance: Boolean = false
Selim Cinekae2702d2019-06-19 18:04:05 -070055 var qSExpanded = false
56 set(value) {
57 val changed = field != value
58 field = value
59 if (changed && !value) {
60 maybePerformPendingUnlock()
61 }
62 }
Selim Cinekf89a5dc2019-06-18 15:10:25 -070063
Selim Cinek2c890ee2019-05-20 19:16:43 -070064 @Inject
Selim Cinekbd84c162019-06-11 16:23:23 -070065 constructor(context: Context, tunerService: TunerService,
Selim Cineka6a3ebc2019-06-19 18:33:17 -070066 statusBarStateController: StatusBarStateController,
67 lockscreenUserManager: NotificationLockscreenUserManager) {
Lucas Dupin206fe562019-05-31 14:36:42 -070068 unlockMethodCache = UnlockMethodCache.getInstance(context)
Selim Cinekbd84c162019-06-11 16:23:23 -070069 this.statusBarStateController = statusBarStateController
Selim Cinekb8cc6ef2019-06-14 16:37:53 -070070 statusBarStateController.addCallback(object : StatusBarStateController.StateListener {
71 override fun onStateChanged(newState: Int) {
72 if (newState != StatusBarState.KEYGUARD) {
73 pendingUnlockType = null;
74 }
75 }
76 })
Mady Mellordce1bf32019-06-25 14:31:19 -070077 if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) {
78 return
79 }
Lucas Dupin1b883b42019-05-28 17:43:59 -070080 val faceManager = context.getSystemService(FaceManager::class.java)
81 if (faceManager?.isHardwareDetected != true) {
82 return
83 }
84
85 val dismissByDefault = if (context.resources.getBoolean(
86 com.android.internal.R.bool.config_faceAuthDismissesKeyguard)) 1 else 0
Selim Cinek2c890ee2019-05-20 19:16:43 -070087 tunerService.addTunable(
88 object : TunerService.Tunable {
89 override fun onTuningChanged(key: String?, newValue: String?) {
90 bypassEnabled = Settings.Secure.getIntForUser(
91 context.contentResolver,
92 Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD,
93 dismissByDefault,
94 KeyguardUpdateMonitor.getCurrentUser()) != 0
95 }
96 }, Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD)
Selim Cineka6a3ebc2019-06-19 18:33:17 -070097 lockscreenUserManager.addUserChangedListener { pendingUnlockType = null }
Selim Cinek2c890ee2019-05-20 19:16:43 -070098 }
Selim Cinekbd84c162019-06-11 16:23:23 -070099
100 /**
101 * Notify that the biometric unlock has happened.
102 *
103 * @return false if we can not wake and unlock right now
104 */
105 fun onBiometricAuthenticated(biometricSourceType: BiometricSourceType): Boolean {
Selim Cinekb8cc6ef2019-06-14 16:37:53 -0700106 if (bypassEnabled) {
Selim Cinekf89a5dc2019-06-18 15:10:25 -0700107 if (bouncerShowing) {
108 // Whenever the bouncer is showing, we want to unlock. Otherwise we can get stuck
109 // in the shade locked where the bouncer wouldn't unlock
110 return true
111 }
Selim Cinekb8cc6ef2019-06-14 16:37:53 -0700112 if (statusBarStateController.state != StatusBarState.KEYGUARD) {
113 // We're bypassing but not actually on the lockscreen, the user should decide when
114 // to unlock
115 return false
116 }
Selim Cinekec177752019-06-19 18:13:51 -0700117 if (launchingAffordance) {
118 return false
119 }
Selim Cinekae2702d2019-06-19 18:04:05 -0700120 if (isPulseExpanding || qSExpanded) {
Selim Cinekb8cc6ef2019-06-14 16:37:53 -0700121 pendingUnlockType = biometricSourceType
122 return false
123 }
Selim Cinekbd84c162019-06-11 16:23:23 -0700124 }
125 return true
126 }
Selim Cinekb8cc6ef2019-06-14 16:37:53 -0700127
128 fun maybePerformPendingUnlock() {
129 if (pendingUnlockType != null) {
130 if (onBiometricAuthenticated(pendingUnlockType!!)) {
131 unlockController.startWakeAndUnlock(pendingUnlockType)
132 pendingUnlockType = null
133 }
134 }
135 }
136
137 fun onStartedGoingToSleep() {
138 pendingUnlockType = null
139 }
Selim Cinek2c890ee2019-05-20 19:16:43 -0700140}