• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.annotation.IntDef
20 import android.content.Context
21 import android.content.pm.PackageManager
22 import android.hardware.biometrics.BiometricSourceType
23 import android.provider.Settings
24 import com.android.systemui.Dumpable
25 import com.android.systemui.R
26 import com.android.systemui.dagger.SysUISingleton
27 import com.android.systemui.dump.DumpManager
28 import com.android.systemui.plugins.statusbar.StatusBarStateController
29 import com.android.systemui.statusbar.NotificationLockscreenUserManager
30 import com.android.systemui.statusbar.StatusBarState
31 import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm
32 import com.android.systemui.statusbar.policy.KeyguardStateController
33 import com.android.systemui.tuner.TunerService
34 import java.io.FileDescriptor
35 import java.io.PrintWriter
36 import javax.inject.Inject
37 
38 @SysUISingleton
39 open class KeyguardBypassController : Dumpable, StackScrollAlgorithm.BypassController {
40 
41     private val mKeyguardStateController: KeyguardStateController
42     private val statusBarStateController: StatusBarStateController
43     @BypassOverride private val bypassOverride: Int
44     private var hasFaceFeature: Boolean
45     private var pendingUnlock: PendingUnlock? = null
46     var userHasDeviceEntryIntent: Boolean = false // ie: attempted udfps auth
47 
48     @IntDef(
49         FACE_UNLOCK_BYPASS_NO_OVERRIDE,
50         FACE_UNLOCK_BYPASS_ALWAYS,
51         FACE_UNLOCK_BYPASS_NEVER
52     )
53     @Retention(AnnotationRetention.SOURCE)
54     private annotation class BypassOverride
55 
56     /**
57      * Pending unlock info:
58      *
59      * The pending unlock type which is set if the bypass was blocked when it happened.
60      *
61      * Whether the pending unlock type is strong biometric or non-strong biometric
62      * (i.e. weak or convenience).
63      */
64     private data class PendingUnlock(
65         val pendingUnlockType: BiometricSourceType,
66         val isStrongBiometric: Boolean
67     )
68 
69     lateinit var unlockController: BiometricUnlockController
70     var isPulseExpanding = false
71 
72     /** delegates to [bypassEnabled] but conforms to [StackScrollAlgorithm.BypassController] */
isBypassEnablednull73     override fun isBypassEnabled() = bypassEnabled
74 
75     /**
76      * If face unlock dismisses the lock screen or keeps user on keyguard for the current user.
77      */
78     var bypassEnabled: Boolean = false
79         get() {
80             val enabled = when (bypassOverride) {
81                 FACE_UNLOCK_BYPASS_ALWAYS -> true
82                 FACE_UNLOCK_BYPASS_NEVER -> false
83                 else -> field
84             }
85             return enabled && mKeyguardStateController.isFaceAuthEnabled
86         }
87         private set
88 
89     var bouncerShowing: Boolean = false
90     var altBouncerShowing: Boolean = false
91     var launchingAffordance: Boolean = false
92     var qSExpanded = false
93         set(value) {
94             val changed = field != value
95             field = value
96             if (changed && !value) {
97                 maybePerformPendingUnlock()
98             }
99         }
100 
101     @Inject
102     constructor(
103         context: Context,
104         tunerService: TunerService,
105         statusBarStateController: StatusBarStateController,
106         lockscreenUserManager: NotificationLockscreenUserManager,
107         keyguardStateController: KeyguardStateController,
108         dumpManager: DumpManager
109     ) {
110         this.mKeyguardStateController = keyguardStateController
111         this.statusBarStateController = statusBarStateController
112 
113         bypassOverride = context.resources.getInteger(R.integer.config_face_unlock_bypass_override)
114 
115         hasFaceFeature = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)
116         if (!hasFaceFeature) {
117             return
118         }
119 
120         dumpManager.registerDumpable("KeyguardBypassController", this)
121         statusBarStateController.addCallback(object : StatusBarStateController.StateListener {
onStateChangednull122             override fun onStateChanged(newState: Int) {
123                 if (newState != StatusBarState.KEYGUARD) {
124                     pendingUnlock = null
125                 }
126             }
127         })
128 
129         val dismissByDefault = if (context.resources.getBoolean(
130                         com.android.internal.R.bool.config_faceAuthDismissesKeyguard)) 1 else 0
131         tunerService.addTunable(object : TunerService.Tunable {
onTuningChangednull132             override fun onTuningChanged(key: String?, newValue: String?) {
133                 bypassEnabled = tunerService.getValue(key, dismissByDefault) != 0
134             }
135         }, Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD)
136         lockscreenUserManager.addUserChangedListener(
137                 object : NotificationLockscreenUserManager.UserChangedListener {
onUserChangednull138                     override fun onUserChanged(userId: Int) {
139                         pendingUnlock = null
140                     }
141                 })
142     }
143 
144     /**
145      * Notify that the biometric unlock has happened.
146      *
147      * @return false if we can not wake and unlock right now
148      */
onBiometricAuthenticatednull149     fun onBiometricAuthenticated(
150         biometricSourceType: BiometricSourceType,
151         isStrongBiometric: Boolean
152     ): Boolean {
153         if (biometricSourceType == BiometricSourceType.FACE && bypassEnabled) {
154             val can = canBypass()
155             if (!can && (isPulseExpanding || qSExpanded)) {
156                 pendingUnlock = PendingUnlock(biometricSourceType, isStrongBiometric)
157             }
158             return can
159         }
160         return true
161     }
162 
maybePerformPendingUnlocknull163     fun maybePerformPendingUnlock() {
164         if (pendingUnlock != null) {
165             if (onBiometricAuthenticated(pendingUnlock!!.pendingUnlockType,
166                             pendingUnlock!!.isStrongBiometric)) {
167                 unlockController.startWakeAndUnlock(pendingUnlock!!.pendingUnlockType,
168                         pendingUnlock!!.isStrongBiometric)
169                 pendingUnlock = null
170             }
171         }
172     }
173 
174     /**
175      * If keyguard can be dismissed because of bypass.
176      */
canBypassnull177     fun canBypass(): Boolean {
178         if (bypassEnabled) {
179             return when {
180                 bouncerShowing -> true
181                 altBouncerShowing -> true
182                 statusBarStateController.state != StatusBarState.KEYGUARD -> false
183                 launchingAffordance -> false
184                 isPulseExpanding || qSExpanded -> false
185                 else -> true
186             }
187         }
188         return false
189     }
190 
191     /**
192      * If shorter animations should be played when unlocking.
193      */
canPlaySubtleWindowAnimationsnull194     fun canPlaySubtleWindowAnimations(): Boolean {
195         if (bypassEnabled) {
196             return when {
197                 statusBarStateController.state != StatusBarState.KEYGUARD -> false
198                 qSExpanded -> false
199                 else -> true
200             }
201         }
202         return false
203     }
204 
onStartedGoingToSleepnull205     fun onStartedGoingToSleep() {
206         pendingUnlock = null
207     }
208 
dumpnull209     override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
210         pw.println("KeyguardBypassController:")
211         if (pendingUnlock != null) {
212             pw.println("  mPendingUnlock.pendingUnlockType: ${pendingUnlock!!.pendingUnlockType}")
213             pw.println("  mPendingUnlock.isStrongBiometric: ${pendingUnlock!!.isStrongBiometric}")
214         } else {
215             pw.println("  mPendingUnlock: $pendingUnlock")
216         }
217         pw.println("  bypassEnabled: $bypassEnabled")
218         pw.println("  canBypass: ${canBypass()}")
219         pw.println("  bouncerShowing: $bouncerShowing")
220         pw.println("  altBouncerShowing: $altBouncerShowing")
221         pw.println("  isPulseExpanding: $isPulseExpanding")
222         pw.println("  launchingAffordance: $launchingAffordance")
223         pw.println("  qSExpanded: $qSExpanded")
224         pw.println("  hasFaceFeature: $hasFaceFeature")
225         pw.println("  userHasDeviceEntryIntent: $userHasDeviceEntryIntent")
226     }
227 
228     companion object {
229         const val BYPASS_FADE_DURATION = 67
230 
231         private const val FACE_UNLOCK_BYPASS_NO_OVERRIDE = 0
232         private const val FACE_UNLOCK_BYPASS_ALWAYS = 1
233         private const val FACE_UNLOCK_BYPASS_NEVER = 2
234     }
235 }
236