blob: 70d3bff9b82283f5e4cd4cee8a3e325c1946dc78 [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 Cinekbd84c162019-06-11 16:23:23 -070024import com.android.systemui.plugins.statusbar.StatusBarStateController
Selim Cineka6a3ebc2019-06-19 18:33:17 -070025import com.android.systemui.statusbar.NotificationLockscreenUserManager
Selim Cinekbd84c162019-06-11 16:23:23 -070026import com.android.systemui.statusbar.StatusBarState
Selim Cinek2c890ee2019-05-20 19:16:43 -070027import com.android.systemui.tuner.TunerService
Lucas Dupin5a5e0bd2019-07-11 14:19:11 +090028import java.io.PrintWriter
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
Lucas Dupin4c507042019-07-22 16:47:34 -070050 get() = field && unlockMethodCache.isFaceAuthEnabled
Selim Cinekf89a5dc2019-06-18 15:10:25 -070051 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
Lucas Dupin5a5e0bd2019-07-11 14:19:11 +090065 constructor(
66 context: Context,
67 tunerService: TunerService,
68 statusBarStateController: StatusBarStateController,
69 lockscreenUserManager: NotificationLockscreenUserManager
70 ) {
Lucas Dupin206fe562019-05-31 14:36:42 -070071 unlockMethodCache = UnlockMethodCache.getInstance(context)
Selim Cinekbd84c162019-06-11 16:23:23 -070072 this.statusBarStateController = statusBarStateController
Lucas Dupin5a5e0bd2019-07-11 14:19:11 +090073
Mady Mellordce1bf32019-06-25 14:31:19 -070074 if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) {
75 return
76 }
Lucas Dupin1b883b42019-05-28 17:43:59 -070077 val faceManager = context.getSystemService(FaceManager::class.java)
78 if (faceManager?.isHardwareDetected != true) {
79 return
80 }
81
Lucas Dupin5a5e0bd2019-07-11 14:19:11 +090082 statusBarStateController.addCallback(object : StatusBarStateController.StateListener {
83 override fun onStateChanged(newState: Int) {
84 if (newState != StatusBarState.KEYGUARD) {
85 pendingUnlockType = null
86 }
87 }
88 })
89
Lucas Dupin1b883b42019-05-28 17:43:59 -070090 val dismissByDefault = if (context.resources.getBoolean(
Lucas Dupin5a5e0bd2019-07-11 14:19:11 +090091 com.android.internal.R.bool.config_faceAuthDismissesKeyguard)) 1 else 0
92 tunerService.addTunable(object : TunerService.Tunable {
93 override fun onTuningChanged(key: String?, newValue: String?) {
94 bypassEnabled = tunerService.getValue(key, dismissByDefault) != 0
Selim Cinek2c890ee2019-05-20 19:16:43 -070095 }
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) {
Lucas Dupin4befb742019-07-01 11:31:31 -0700107 val can = canBypass()
108 if (!can && (isPulseExpanding || qSExpanded)) {
Selim Cinekb8cc6ef2019-06-14 16:37:53 -0700109 pendingUnlockType = biometricSourceType
Selim Cinekb8cc6ef2019-06-14 16:37:53 -0700110 }
Lucas Dupin4befb742019-07-01 11:31:31 -0700111 return can
Selim Cinekbd84c162019-06-11 16:23:23 -0700112 }
113 return true
114 }
Selim Cinekb8cc6ef2019-06-14 16:37:53 -0700115
116 fun maybePerformPendingUnlock() {
117 if (pendingUnlockType != null) {
118 if (onBiometricAuthenticated(pendingUnlockType!!)) {
119 unlockController.startWakeAndUnlock(pendingUnlockType)
120 pendingUnlockType = null
121 }
122 }
123 }
124
Lucas Dupin4befb742019-07-01 11:31:31 -0700125 /**
126 * If keyguard can be dismissed because of bypass.
127 */
128 fun canBypass(): Boolean {
129 if (bypassEnabled) {
130 return when {
131 bouncerShowing -> true
132 statusBarStateController.state != StatusBarState.KEYGUARD -> false
133 launchingAffordance -> false
134 isPulseExpanding || qSExpanded -> false
135 else -> true
136 }
137 }
138 return false
139 }
140
Lucas Dupinfa817a02019-07-02 15:22:54 -0700141 /**
142 * If shorter animations should be played when unlocking.
143 */
144 fun canPlaySubtleWindowAnimations(): Boolean {
145 if (bypassEnabled) {
146 return when {
147 statusBarStateController.state != StatusBarState.KEYGUARD -> false
148 qSExpanded -> false
149 else -> true
150 }
151 }
152 return false
153 }
154
Selim Cinekb8cc6ef2019-06-14 16:37:53 -0700155 fun onStartedGoingToSleep() {
156 pendingUnlockType = null
157 }
Lucas Dupin5a5e0bd2019-07-11 14:19:11 +0900158
159 fun dump(pw: PrintWriter) {
160 pw.println("KeyguardBypassController:")
161 pw.print(" pendingUnlockType: "); pw.println(pendingUnlockType)
162 pw.print(" bypassEnabled: "); pw.println(bypassEnabled)
163 pw.print(" canBypass: "); pw.println(canBypass())
164 pw.print(" bouncerShowing: "); pw.println(bouncerShowing)
165 pw.print(" isPulseExpanding: "); pw.println(isPulseExpanding)
166 pw.print(" launchingAffordance: "); pw.println(launchingAffordance)
167 pw.print(" qSExpanded: "); pw.println(qSExpanded)
168 pw.print(" bouncerShowing: "); pw.println(bouncerShowing)
169 }
Selim Cinek84b2acc2019-07-07 00:40:38 -0700170
171 companion object {
172 const val BYPASS_PANEL_FADE_DURATION = 67
173 }
Selim Cinek2c890ee2019-05-20 19:16:43 -0700174}