blob: b4d0d479ff3929b66c82f68b4a368ce238e29a36 [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
Selim Cinek2c890ee2019-05-20 19:16:43 -070022import android.provider.Settings
Lucas Dupin64171fe2019-10-30 14:28:29 -070023import com.android.systemui.DumpController
24import com.android.systemui.Dumpable
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
Lucas Dupinc8f16e82019-09-17 18:24:50 -040028import com.android.systemui.statusbar.policy.KeyguardStateController
Selim Cinek2c890ee2019-05-20 19:16:43 -070029import com.android.systemui.tuner.TunerService
Lucas Dupin64171fe2019-10-30 14:28:29 -070030import java.io.FileDescriptor
Lucas Dupin5a5e0bd2019-07-11 14:19:11 +090031import java.io.PrintWriter
Selim Cinek2c890ee2019-05-20 19:16:43 -070032import javax.inject.Inject
33import javax.inject.Singleton
34
35@Singleton
Lucas Dupin960b7e7f2020-01-24 15:47:28 -080036open class KeyguardBypassController : Dumpable {
Selim Cinek2c890ee2019-05-20 19:16:43 -070037
Lucas Dupinc8f16e82019-09-17 18:24:50 -040038 private val mKeyguardStateController: KeyguardStateController
Selim Cinekbd84c162019-06-11 16:23:23 -070039 private val statusBarStateController: StatusBarStateController
Lucas Dupin0f6d5d82019-07-30 15:47:04 -070040 private var hasFaceFeature: Boolean
Selim Cinekbd84c162019-06-11 16:23:23 -070041
Selim Cinekb8cc6ef2019-06-14 16:37:53 -070042 /**
43 * The pending unlock type which is set if the bypass was blocked when it happened.
44 */
45 private var pendingUnlockType: BiometricSourceType? = null
Lucas Dupin206fe562019-05-31 14:36:42 -070046
Selim Cinekf89a5dc2019-06-18 15:10:25 -070047 lateinit var unlockController: BiometricUnlockController
48 var isPulseExpanding = false
49
50 /**
51 * If face unlock dismisses the lock screen or keeps user on keyguard for the current user.
52 */
53 var bypassEnabled: Boolean = false
Lucas Dupinc8f16e82019-09-17 18:24:50 -040054 get() = field && mKeyguardStateController.isFaceAuthEnabled
Selim Cinekf89a5dc2019-06-18 15:10:25 -070055 private set
56
57 var bouncerShowing: Boolean = false
Selim Cinekec177752019-06-19 18:13:51 -070058 var launchingAffordance: Boolean = false
Selim Cinekae2702d2019-06-19 18:04:05 -070059 var qSExpanded = false
60 set(value) {
61 val changed = field != value
62 field = value
63 if (changed && !value) {
64 maybePerformPendingUnlock()
65 }
66 }
Selim Cinekf89a5dc2019-06-18 15:10:25 -070067
Selim Cinek2c890ee2019-05-20 19:16:43 -070068 @Inject
Lucas Dupin5a5e0bd2019-07-11 14:19:11 +090069 constructor(
70 context: Context,
71 tunerService: TunerService,
72 statusBarStateController: StatusBarStateController,
Lucas Dupinc8f16e82019-09-17 18:24:50 -040073 lockscreenUserManager: NotificationLockscreenUserManager,
Lucas Dupin64171fe2019-10-30 14:28:29 -070074 keyguardStateController: KeyguardStateController,
75 dumpController: DumpController
Lucas Dupin5a5e0bd2019-07-11 14:19:11 +090076 ) {
Lucas Dupinc8f16e82019-09-17 18:24:50 -040077 this.mKeyguardStateController = keyguardStateController
Selim Cinekbd84c162019-06-11 16:23:23 -070078 this.statusBarStateController = statusBarStateController
Lucas Dupin5a5e0bd2019-07-11 14:19:11 +090079
Lucas Dupin0f6d5d82019-07-30 15:47:04 -070080 hasFaceFeature = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)
81 if (!hasFaceFeature) {
Lucas Dupin1b883b42019-05-28 17:43:59 -070082 return
83 }
84
Lucas Dupin64171fe2019-10-30 14:28:29 -070085 dumpController.registerDumpable("KeyguardBypassController", this)
Lucas Dupin5a5e0bd2019-07-11 14:19:11 +090086 statusBarStateController.addCallback(object : StatusBarStateController.StateListener {
87 override fun onStateChanged(newState: Int) {
88 if (newState != StatusBarState.KEYGUARD) {
89 pendingUnlockType = null
90 }
91 }
92 })
93
Lucas Dupin1b883b42019-05-28 17:43:59 -070094 val dismissByDefault = if (context.resources.getBoolean(
Lucas Dupin5a5e0bd2019-07-11 14:19:11 +090095 com.android.internal.R.bool.config_faceAuthDismissesKeyguard)) 1 else 0
96 tunerService.addTunable(object : TunerService.Tunable {
97 override fun onTuningChanged(key: String?, newValue: String?) {
98 bypassEnabled = tunerService.getValue(key, dismissByDefault) != 0
Selim Cinek2c890ee2019-05-20 19:16:43 -070099 }
100 }, Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD)
Steve Elliottb47f1c72019-12-19 12:39:26 -0500101 lockscreenUserManager.addUserChangedListener(
102 object : NotificationLockscreenUserManager.UserChangedListener {
103 override fun onUserChanged(userId: Int) {
104 pendingUnlockType = null
105 }
106 })
Selim Cinek2c890ee2019-05-20 19:16:43 -0700107 }
Selim Cinekbd84c162019-06-11 16:23:23 -0700108
109 /**
110 * Notify that the biometric unlock has happened.
111 *
112 * @return false if we can not wake and unlock right now
113 */
114 fun onBiometricAuthenticated(biometricSourceType: BiometricSourceType): Boolean {
Selim Cinekb8cc6ef2019-06-14 16:37:53 -0700115 if (bypassEnabled) {
Lucas Dupin4befb742019-07-01 11:31:31 -0700116 val can = canBypass()
117 if (!can && (isPulseExpanding || qSExpanded)) {
Selim Cinekb8cc6ef2019-06-14 16:37:53 -0700118 pendingUnlockType = biometricSourceType
Selim Cinekb8cc6ef2019-06-14 16:37:53 -0700119 }
Lucas Dupin4befb742019-07-01 11:31:31 -0700120 return can
Selim Cinekbd84c162019-06-11 16:23:23 -0700121 }
122 return true
123 }
Selim Cinekb8cc6ef2019-06-14 16:37:53 -0700124
125 fun maybePerformPendingUnlock() {
126 if (pendingUnlockType != null) {
127 if (onBiometricAuthenticated(pendingUnlockType!!)) {
128 unlockController.startWakeAndUnlock(pendingUnlockType)
129 pendingUnlockType = null
130 }
131 }
132 }
133
Lucas Dupin4befb742019-07-01 11:31:31 -0700134 /**
135 * If keyguard can be dismissed because of bypass.
136 */
137 fun canBypass(): Boolean {
138 if (bypassEnabled) {
139 return when {
140 bouncerShowing -> true
141 statusBarStateController.state != StatusBarState.KEYGUARD -> false
142 launchingAffordance -> false
143 isPulseExpanding || qSExpanded -> false
144 else -> true
145 }
146 }
147 return false
148 }
149
Lucas Dupinfa817a02019-07-02 15:22:54 -0700150 /**
151 * If shorter animations should be played when unlocking.
152 */
153 fun canPlaySubtleWindowAnimations(): Boolean {
154 if (bypassEnabled) {
155 return when {
156 statusBarStateController.state != StatusBarState.KEYGUARD -> false
157 qSExpanded -> false
158 else -> true
159 }
160 }
161 return false
162 }
163
Selim Cinekb8cc6ef2019-06-14 16:37:53 -0700164 fun onStartedGoingToSleep() {
165 pendingUnlockType = null
166 }
Lucas Dupin5a5e0bd2019-07-11 14:19:11 +0900167
Lucas Dupin64171fe2019-10-30 14:28:29 -0700168 override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
Lucas Dupin5a5e0bd2019-07-11 14:19:11 +0900169 pw.println("KeyguardBypassController:")
Lucas Dupin64171fe2019-10-30 14:28:29 -0700170 pw.println(" pendingUnlockType: $pendingUnlockType")
171 pw.println(" bypassEnabled: $bypassEnabled")
172 pw.println(" canBypass: ${canBypass()}")
173 pw.println(" bouncerShowing: $bouncerShowing")
174 pw.println(" isPulseExpanding: $isPulseExpanding")
175 pw.println(" launchingAffordance: $launchingAffordance")
176 pw.println(" qSExpanded: $qSExpanded")
177 pw.println(" hasFaceFeature: $hasFaceFeature")
Lucas Dupin5a5e0bd2019-07-11 14:19:11 +0900178 }
Selim Cinek84b2acc2019-07-07 00:40:38 -0700179
180 companion object {
181 const val BYPASS_PANEL_FADE_DURATION = 67
182 }
Selim Cinek2c890ee2019-05-20 19:16:43 -0700183}