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.biometrics.BiometricSourceType 22 import android.provider.Settings 23 import com.android.systemui.plugins.statusbar.StatusBarStateController 24 import com.android.systemui.statusbar.NotificationLockscreenUserManager 25 import com.android.systemui.statusbar.StatusBarState 26 import com.android.systemui.tuner.TunerService 27 import java.io.PrintWriter 28 import javax.inject.Inject 29 import javax.inject.Singleton 30 31 @Singleton 32 class KeyguardBypassController { 33 34 private val unlockMethodCache: UnlockMethodCache 35 private val statusBarStateController: StatusBarStateController 36 private var hasFaceFeature: Boolean 37 38 /** 39 * The pending unlock type which is set if the bypass was blocked when it happened. 40 */ 41 private var pendingUnlockType: BiometricSourceType? = null 42 43 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.isFaceAuthEnabled 51 private set 52 53 var bouncerShowing: Boolean = false 54 var launchingAffordance: Boolean = false 55 var qSExpanded = false 56 set(value) { 57 val changed = field != value 58 field = value 59 if (changed && !value) { 60 maybePerformPendingUnlock() 61 } 62 } 63 64 @Inject 65 constructor( 66 context: Context, 67 tunerService: TunerService, 68 statusBarStateController: StatusBarStateController, 69 lockscreenUserManager: NotificationLockscreenUserManager 70 ) { 71 unlockMethodCache = UnlockMethodCache.getInstance(context) 72 this.statusBarStateController = statusBarStateController 73 74 hasFaceFeature = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE) 75 if (!hasFaceFeature) { 76 return 77 } 78 79 statusBarStateController.addCallback(object : StatusBarStateController.StateListener { onStateChangednull80 override fun onStateChanged(newState: Int) { 81 if (newState != StatusBarState.KEYGUARD) { 82 pendingUnlockType = null 83 } 84 } 85 }) 86 87 val dismissByDefault = if (context.resources.getBoolean( 88 com.android.internal.R.bool.config_faceAuthDismissesKeyguard)) 1 else 0 89 tunerService.addTunable(object : TunerService.Tunable { onTuningChangednull90 override fun onTuningChanged(key: String?, newValue: String?) { 91 bypassEnabled = tunerService.getValue(key, dismissByDefault) != 0 92 } 93 }, Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD) <lambda>null94 lockscreenUserManager.addUserChangedListener { pendingUnlockType = null } 95 } 96 97 /** 98 * Notify that the biometric unlock has happened. 99 * 100 * @return false if we can not wake and unlock right now 101 */ onBiometricAuthenticatednull102 fun onBiometricAuthenticated(biometricSourceType: BiometricSourceType): Boolean { 103 if (bypassEnabled) { 104 val can = canBypass() 105 if (!can && (isPulseExpanding || qSExpanded)) { 106 pendingUnlockType = biometricSourceType 107 } 108 return can 109 } 110 return true 111 } 112 maybePerformPendingUnlocknull113 fun maybePerformPendingUnlock() { 114 if (pendingUnlockType != null) { 115 if (onBiometricAuthenticated(pendingUnlockType!!)) { 116 unlockController.startWakeAndUnlock(pendingUnlockType) 117 pendingUnlockType = null 118 } 119 } 120 } 121 122 /** 123 * If keyguard can be dismissed because of bypass. 124 */ canBypassnull125 fun canBypass(): Boolean { 126 if (bypassEnabled) { 127 return when { 128 bouncerShowing -> true 129 statusBarStateController.state != StatusBarState.KEYGUARD -> false 130 launchingAffordance -> false 131 isPulseExpanding || qSExpanded -> false 132 else -> true 133 } 134 } 135 return false 136 } 137 138 /** 139 * If shorter animations should be played when unlocking. 140 */ canPlaySubtleWindowAnimationsnull141 fun canPlaySubtleWindowAnimations(): Boolean { 142 if (bypassEnabled) { 143 return when { 144 statusBarStateController.state != StatusBarState.KEYGUARD -> false 145 qSExpanded -> false 146 else -> true 147 } 148 } 149 return false 150 } 151 onStartedGoingToSleepnull152 fun onStartedGoingToSleep() { 153 pendingUnlockType = null 154 } 155 dumpnull156 fun dump(pw: PrintWriter) { 157 pw.println("KeyguardBypassController:") 158 pw.print(" pendingUnlockType: "); pw.println(pendingUnlockType) 159 pw.print(" bypassEnabled: "); pw.println(bypassEnabled) 160 pw.print(" canBypass: "); pw.println(canBypass()) 161 pw.print(" bouncerShowing: "); pw.println(bouncerShowing) 162 pw.print(" isPulseExpanding: "); pw.println(isPulseExpanding) 163 pw.print(" launchingAffordance: "); pw.println(launchingAffordance) 164 pw.print(" qSExpanded: "); pw.println(qSExpanded) 165 pw.print(" hasFaceFeature: "); pw.println(hasFaceFeature) 166 } 167 168 companion object { 169 const val BYPASS_PANEL_FADE_DURATION = 67 170 } 171 } 172