Merge "Move BiometricUnlockController logs to LogBuffer" into tm-qpr-dev am: a6a69b9e8e
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20519957 Change-Id: I2f8150d0281c9577b857cc965669d280340c460e Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -29,5 +29,4 @@ public class KeyguardConstants {
|
|||||||
*/
|
*/
|
||||||
public static final boolean DEBUG = Log.isLoggable("Keyguard", Log.DEBUG);
|
public static final boolean DEBUG = Log.isLoggable("Keyguard", Log.DEBUG);
|
||||||
public static final boolean DEBUG_SIM_STATES = true;
|
public static final boolean DEBUG_SIM_STATES = true;
|
||||||
public static final boolean DEBUG_BIOMETRIC_WAKELOCK = true;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -845,6 +845,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
|
|||||||
+ " triggered while waiting for cancellation, removing watchdog");
|
+ " triggered while waiting for cancellation, removing watchdog");
|
||||||
mHandler.removeCallbacks(mFpCancelNotReceived);
|
mHandler.removeCallbacks(mFpCancelNotReceived);
|
||||||
}
|
}
|
||||||
|
mLogger.d("handleFingerprintAuthFailed");
|
||||||
for (int i = 0; i < mCallbacks.size(); i++) {
|
for (int i = 0; i < mCallbacks.size(); i++) {
|
||||||
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
|
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
|
||||||
if (cb != null) {
|
if (cb != null) {
|
||||||
@@ -974,6 +975,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
|
|||||||
stopListeningForFace(FACE_AUTH_STOPPED_FP_LOCKED_OUT);
|
stopListeningForFace(FACE_AUTH_STOPPED_FP_LOCKED_OUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mLogger.logFingerprintError(msgId, errString);
|
||||||
for (int i = 0; i < mCallbacks.size(); i++) {
|
for (int i = 0; i < mCallbacks.size(); i++) {
|
||||||
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
|
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
|
||||||
if (cb != null) {
|
if (cb != null) {
|
||||||
@@ -3900,6 +3902,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
|
|||||||
pw.println(" listening: actual=" + mFaceRunningState
|
pw.println(" listening: actual=" + mFaceRunningState
|
||||||
+ " expected=(" + (shouldListenForFace() ? 1 : 0));
|
+ " expected=(" + (shouldListenForFace() ? 1 : 0));
|
||||||
pw.println(" strongAuthFlags=" + Integer.toHexString(strongAuthFlags));
|
pw.println(" strongAuthFlags=" + Integer.toHexString(strongAuthFlags));
|
||||||
|
pw.println(" isNonStrongBiometricAllowedAfterIdleTimeout="
|
||||||
|
+ mStrongAuthTracker.isNonStrongBiometricAllowedAfterIdleTimeout(userId));
|
||||||
pw.println(" trustManaged=" + getUserTrustIsManaged(userId));
|
pw.println(" trustManaged=" + getUserTrustIsManaged(userId));
|
||||||
pw.println(" mFaceLockedOutPermanent=" + mFaceLockedOutPermanent);
|
pw.println(" mFaceLockedOutPermanent=" + mFaceLockedOutPermanent);
|
||||||
pw.println(" enabledByUser=" + mBiometricEnabledForUser.get(userId));
|
pw.println(" enabledByUser=" + mBiometricEnabledForUser.get(userId));
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
package com.android.keyguard.logging
|
package com.android.keyguard.logging
|
||||||
|
|
||||||
import com.android.systemui.dagger.SysUISingleton
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
import com.android.systemui.log.dagger.BiometricMessagesLog
|
import com.android.systemui.log.dagger.BiometricLog
|
||||||
import com.android.systemui.plugins.log.LogBuffer
|
import com.android.systemui.plugins.log.LogBuffer
|
||||||
import com.android.systemui.plugins.log.LogLevel.DEBUG
|
import com.android.systemui.plugins.log.LogLevel.DEBUG
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@@ -26,7 +26,7 @@ import javax.inject.Inject
|
|||||||
@SysUISingleton
|
@SysUISingleton
|
||||||
class FaceMessageDeferralLogger
|
class FaceMessageDeferralLogger
|
||||||
@Inject
|
@Inject
|
||||||
constructor(@BiometricMessagesLog private val logBuffer: LogBuffer) :
|
constructor(@BiometricLog private val logBuffer: LogBuffer) :
|
||||||
BiometricMessageDeferralLogger(logBuffer, "FaceMessageDeferralLogger")
|
BiometricMessageDeferralLogger(logBuffer, "FaceMessageDeferralLogger")
|
||||||
|
|
||||||
open class BiometricMessageDeferralLogger(
|
open class BiometricMessageDeferralLogger(
|
||||||
|
|||||||
@@ -0,0 +1,174 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.keyguard.logging
|
||||||
|
|
||||||
|
import com.android.systemui.dagger.SysUISingleton
|
||||||
|
import com.android.systemui.log.dagger.BiometricLog
|
||||||
|
import com.android.systemui.plugins.log.LogBuffer
|
||||||
|
import com.android.systemui.plugins.log.LogLevel
|
||||||
|
import com.android.systemui.plugins.log.LogLevel.DEBUG
|
||||||
|
import com.android.systemui.plugins.log.LogLevel.INFO
|
||||||
|
import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_DISMISS_BOUNCER
|
||||||
|
import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_NONE
|
||||||
|
import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_ONLY_WAKE
|
||||||
|
import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_SHOW_BOUNCER
|
||||||
|
import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_UNLOCK_COLLAPSING
|
||||||
|
import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK
|
||||||
|
import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK_FROM_DREAM
|
||||||
|
import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
|
||||||
|
import com.google.errorprone.annotations.CompileTimeConstant
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
private const val TAG = "BiometricUnlockLogger"
|
||||||
|
|
||||||
|
/** Helper class for logging for [com.android.systemui.statusbar.phone.BiometricUnlockController] */
|
||||||
|
@SysUISingleton
|
||||||
|
class BiometricUnlockLogger @Inject constructor(@BiometricLog private val logBuffer: LogBuffer) {
|
||||||
|
fun i(@CompileTimeConstant msg: String) = log(msg, INFO)
|
||||||
|
fun d(@CompileTimeConstant msg: String) = log(msg, DEBUG)
|
||||||
|
fun log(@CompileTimeConstant msg: String, level: LogLevel) = logBuffer.log(TAG, level, msg)
|
||||||
|
|
||||||
|
fun logStartWakeAndUnlock(mode: Int) {
|
||||||
|
logBuffer.log(
|
||||||
|
TAG,
|
||||||
|
DEBUG,
|
||||||
|
{ int1 = mode },
|
||||||
|
{ "startWakeAndUnlock(${wakeAndUnlockModeToString(int1)})" }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun logUdfpsAttemptThresholdMet(consecutiveFailedAttempts: Int) {
|
||||||
|
logBuffer.log(
|
||||||
|
TAG,
|
||||||
|
DEBUG,
|
||||||
|
{ int1 = consecutiveFailedAttempts },
|
||||||
|
{ "udfpsAttemptThresholdMet consecutiveFailedAttempts=$int1" }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun logCalculateModeForFingerprintUnlockingAllowed(
|
||||||
|
deviceInteractive: Boolean,
|
||||||
|
keyguardShowing: Boolean,
|
||||||
|
deviceDreaming: Boolean
|
||||||
|
) {
|
||||||
|
logBuffer.log(
|
||||||
|
TAG,
|
||||||
|
DEBUG,
|
||||||
|
{
|
||||||
|
bool1 = deviceInteractive
|
||||||
|
bool2 = keyguardShowing
|
||||||
|
bool3 = deviceDreaming
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"calculateModeForFingerprint unlockingAllowed=true" +
|
||||||
|
" deviceInteractive=$bool1 isKeyguardShowing=$bool2" +
|
||||||
|
" deviceDreaming=$bool3"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun logCalculateModeForFingerprintUnlockingNotAllowed(
|
||||||
|
strongBiometric: Boolean,
|
||||||
|
strongAuthFlags: Int,
|
||||||
|
nonStrongBiometricAllowed: Boolean,
|
||||||
|
deviceInteractive: Boolean,
|
||||||
|
keyguardShowing: Boolean
|
||||||
|
) {
|
||||||
|
logBuffer.log(
|
||||||
|
TAG,
|
||||||
|
DEBUG,
|
||||||
|
{
|
||||||
|
int1 = strongAuthFlags
|
||||||
|
bool1 = strongBiometric
|
||||||
|
bool2 = nonStrongBiometricAllowed
|
||||||
|
bool3 = deviceInteractive
|
||||||
|
bool4 = keyguardShowing
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"calculateModeForFingerprint unlockingAllowed=false" +
|
||||||
|
" strongBiometric=$bool1 strongAuthFlags=$int1" +
|
||||||
|
" nonStrongBiometricAllowed=$bool2" +
|
||||||
|
" deviceInteractive=$bool3 isKeyguardShowing=$bool4"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun logCalculateModeForPassiveAuthUnlockingAllowed(
|
||||||
|
deviceInteractive: Boolean,
|
||||||
|
keyguardShowing: Boolean,
|
||||||
|
deviceDreaming: Boolean,
|
||||||
|
bypass: Boolean
|
||||||
|
) {
|
||||||
|
logBuffer.log(
|
||||||
|
TAG,
|
||||||
|
DEBUG,
|
||||||
|
{
|
||||||
|
bool1 = deviceInteractive
|
||||||
|
bool2 = keyguardShowing
|
||||||
|
bool3 = deviceDreaming
|
||||||
|
bool4 = bypass
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"calculateModeForPassiveAuth unlockingAllowed=true" +
|
||||||
|
" deviceInteractive=$bool1 isKeyguardShowing=$bool2" +
|
||||||
|
" deviceDreaming=$bool3 bypass=$bool4"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun logCalculateModeForPassiveAuthUnlockingNotAllowed(
|
||||||
|
strongBiometric: Boolean,
|
||||||
|
strongAuthFlags: Int,
|
||||||
|
nonStrongBiometricAllowed: Boolean,
|
||||||
|
deviceInteractive: Boolean,
|
||||||
|
keyguardShowing: Boolean,
|
||||||
|
bypass: Boolean
|
||||||
|
) {
|
||||||
|
logBuffer.log(
|
||||||
|
TAG,
|
||||||
|
DEBUG,
|
||||||
|
{
|
||||||
|
int1 = if (strongBiometric) 1 else 0
|
||||||
|
int2 = strongAuthFlags
|
||||||
|
bool1 = nonStrongBiometricAllowed
|
||||||
|
bool2 = deviceInteractive
|
||||||
|
bool3 = keyguardShowing
|
||||||
|
bool4 = bypass
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"calculateModeForPassiveAuth unlockingAllowed=false" +
|
||||||
|
" strongBiometric=${int1 == 1}" +
|
||||||
|
" strongAuthFlags=$int2 nonStrongBiometricAllowed=$bool1" +
|
||||||
|
" deviceInteractive=$bool2 isKeyguardShowing=$bool3 bypass=$bool4"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun wakeAndUnlockModeToString(mode: Int): String {
|
||||||
|
return when (mode) {
|
||||||
|
MODE_NONE -> "MODE_NONE"
|
||||||
|
MODE_WAKE_AND_UNLOCK -> "MODE_WAKE_AND_UNLOCK"
|
||||||
|
MODE_WAKE_AND_UNLOCK_PULSING -> "MODE_WAKE_AND_UNLOCK_PULSING"
|
||||||
|
MODE_SHOW_BOUNCER -> "MODE_SHOW_BOUNCER"
|
||||||
|
MODE_ONLY_WAKE -> "MODE_ONLY_WAKE"
|
||||||
|
MODE_UNLOCK_COLLAPSING -> "MODE_UNLOCK_COLLAPSING"
|
||||||
|
MODE_WAKE_AND_UNLOCK_FROM_DREAM -> "MODE_WAKE_AND_UNLOCK_FROM_DREAM"
|
||||||
|
MODE_DISMISS_BOUNCER -> "MODE_DISMISS_BOUNCER"
|
||||||
|
else -> "UNKNOWN{$mode}"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -161,6 +161,13 @@ class KeyguardUpdateMonitorLogger @Inject constructor(
|
|||||||
}, {"Fingerprint auth successful: userId: $int1, isStrongBiometric: $bool1"})
|
}, {"Fingerprint auth successful: userId: $int1, isStrongBiometric: $bool1"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun logFingerprintError(msgId: Int, originalErrMsg: String) {
|
||||||
|
logBuffer.log(TAG, DEBUG, {
|
||||||
|
str1 = originalErrMsg
|
||||||
|
int1 = msgId
|
||||||
|
}, { "Fingerprint error received: $str1 msgId= $int1" })
|
||||||
|
}
|
||||||
|
|
||||||
fun logInvalidSubId(subId: Int) {
|
fun logInvalidSubId(subId: Int) {
|
||||||
logBuffer.log(TAG, INFO,
|
logBuffer.log(TAG, INFO,
|
||||||
{ int1 = subId },
|
{ int1 = subId },
|
||||||
|
|||||||
@@ -29,5 +29,5 @@ import javax.inject.Qualifier;
|
|||||||
@Qualifier
|
@Qualifier
|
||||||
@Documented
|
@Documented
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
public @interface BiometricMessagesLog {
|
public @interface BiometricLog {
|
||||||
}
|
}
|
||||||
@@ -300,9 +300,9 @@ public class LogModule {
|
|||||||
*/
|
*/
|
||||||
@Provides
|
@Provides
|
||||||
@SysUISingleton
|
@SysUISingleton
|
||||||
@BiometricMessagesLog
|
@BiometricLog
|
||||||
public static LogBuffer provideBiometricMessagesLogBuffer(LogBufferFactory factory) {
|
public static LogBuffer provideBiometricLogBuffer(LogBufferFactory factory) {
|
||||||
return factory.create("BiometricMessagesLog", 150);
|
return factory.create("BiometricLog", 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import android.os.Handler;
|
|||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.os.Trace;
|
import android.os.Trace;
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
@@ -41,10 +40,10 @@ import com.android.internal.logging.UiEventLogger;
|
|||||||
import com.android.internal.logging.UiEventLoggerImpl;
|
import com.android.internal.logging.UiEventLoggerImpl;
|
||||||
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||||
import com.android.internal.util.LatencyTracker;
|
import com.android.internal.util.LatencyTracker;
|
||||||
import com.android.keyguard.KeyguardConstants;
|
|
||||||
import com.android.keyguard.KeyguardUpdateMonitor;
|
import com.android.keyguard.KeyguardUpdateMonitor;
|
||||||
import com.android.keyguard.KeyguardUpdateMonitorCallback;
|
import com.android.keyguard.KeyguardUpdateMonitorCallback;
|
||||||
import com.android.keyguard.KeyguardViewController;
|
import com.android.keyguard.KeyguardViewController;
|
||||||
|
import com.android.keyguard.logging.BiometricUnlockLogger;
|
||||||
import com.android.systemui.Dumpable;
|
import com.android.systemui.Dumpable;
|
||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
import com.android.systemui.biometrics.AuthController;
|
import com.android.systemui.biometrics.AuthController;
|
||||||
@@ -79,9 +78,6 @@ import javax.inject.Inject;
|
|||||||
*/
|
*/
|
||||||
@SysUISingleton
|
@SysUISingleton
|
||||||
public class BiometricUnlockController extends KeyguardUpdateMonitorCallback implements Dumpable {
|
public class BiometricUnlockController extends KeyguardUpdateMonitorCallback implements Dumpable {
|
||||||
|
|
||||||
private static final String TAG = "BiometricUnlockCtrl";
|
|
||||||
private static final boolean DEBUG_BIO_WAKELOCK = KeyguardConstants.DEBUG_BIOMETRIC_WAKELOCK;
|
|
||||||
private static final long BIOMETRIC_WAKELOCK_TIMEOUT_MS = 15 * 1000;
|
private static final long BIOMETRIC_WAKELOCK_TIMEOUT_MS = 15 * 1000;
|
||||||
private static final String BIOMETRIC_WAKE_LOCK_NAME = "wake-and-unlock:wakelock";
|
private static final String BIOMETRIC_WAKE_LOCK_NAME = "wake-and-unlock:wakelock";
|
||||||
private static final UiEventLogger UI_EVENT_LOGGER = new UiEventLoggerImpl();
|
private static final UiEventLogger UI_EVENT_LOGGER = new UiEventLoggerImpl();
|
||||||
@@ -176,6 +172,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
|
|||||||
private final StatusBarStateController mStatusBarStateController;
|
private final StatusBarStateController mStatusBarStateController;
|
||||||
private final LatencyTracker mLatencyTracker;
|
private final LatencyTracker mLatencyTracker;
|
||||||
private final VibratorHelper mVibratorHelper;
|
private final VibratorHelper mVibratorHelper;
|
||||||
|
private final BiometricUnlockLogger mLogger;
|
||||||
|
|
||||||
private long mLastFpFailureUptimeMillis;
|
private long mLastFpFailureUptimeMillis;
|
||||||
private int mNumConsecutiveFpFailures;
|
private int mNumConsecutiveFpFailures;
|
||||||
@@ -262,7 +259,8 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
|
|||||||
private final ScreenOffAnimationController mScreenOffAnimationController;
|
private final ScreenOffAnimationController mScreenOffAnimationController;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public BiometricUnlockController(DozeScrimController dozeScrimController,
|
public BiometricUnlockController(
|
||||||
|
DozeScrimController dozeScrimController,
|
||||||
KeyguardViewMediator keyguardViewMediator, ScrimController scrimController,
|
KeyguardViewMediator keyguardViewMediator, ScrimController scrimController,
|
||||||
ShadeController shadeController,
|
ShadeController shadeController,
|
||||||
NotificationShadeWindowController notificationShadeWindowController,
|
NotificationShadeWindowController notificationShadeWindowController,
|
||||||
@@ -272,6 +270,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
|
|||||||
KeyguardBypassController keyguardBypassController,
|
KeyguardBypassController keyguardBypassController,
|
||||||
MetricsLogger metricsLogger, DumpManager dumpManager,
|
MetricsLogger metricsLogger, DumpManager dumpManager,
|
||||||
PowerManager powerManager,
|
PowerManager powerManager,
|
||||||
|
BiometricUnlockLogger biometricUnlockLogger,
|
||||||
NotificationMediaManager notificationMediaManager,
|
NotificationMediaManager notificationMediaManager,
|
||||||
WakefulnessLifecycle wakefulnessLifecycle,
|
WakefulnessLifecycle wakefulnessLifecycle,
|
||||||
ScreenLifecycle screenLifecycle,
|
ScreenLifecycle screenLifecycle,
|
||||||
@@ -308,6 +307,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
|
|||||||
mSessionTracker = sessionTracker;
|
mSessionTracker = sessionTracker;
|
||||||
mScreenOffAnimationController = screenOffAnimationController;
|
mScreenOffAnimationController = screenOffAnimationController;
|
||||||
mVibratorHelper = vibrator;
|
mVibratorHelper = vibrator;
|
||||||
|
mLogger = biometricUnlockLogger;
|
||||||
|
|
||||||
dumpManager.registerDumpable(getClass().getName(), this);
|
dumpManager.registerDumpable(getClass().getName(), this);
|
||||||
}
|
}
|
||||||
@@ -329,9 +329,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
|
|||||||
private final Runnable mReleaseBiometricWakeLockRunnable = new Runnable() {
|
private final Runnable mReleaseBiometricWakeLockRunnable = new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (DEBUG_BIO_WAKELOCK) {
|
mLogger.i("biometric wakelock: TIMEOUT!!");
|
||||||
Log.i(TAG, "biometric wakelock: TIMEOUT!!");
|
|
||||||
}
|
|
||||||
releaseBiometricWakeLock();
|
releaseBiometricWakeLock();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -339,9 +337,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
|
|||||||
private void releaseBiometricWakeLock() {
|
private void releaseBiometricWakeLock() {
|
||||||
if (mWakeLock != null) {
|
if (mWakeLock != null) {
|
||||||
mHandler.removeCallbacks(mReleaseBiometricWakeLockRunnable);
|
mHandler.removeCallbacks(mReleaseBiometricWakeLockRunnable);
|
||||||
if (DEBUG_BIO_WAKELOCK) {
|
mLogger.i("releasing biometric wakelock");
|
||||||
Log.i(TAG, "releasing biometric wakelock");
|
|
||||||
}
|
|
||||||
mWakeLock.release();
|
mWakeLock.release();
|
||||||
mWakeLock = null;
|
mWakeLock = null;
|
||||||
}
|
}
|
||||||
@@ -372,9 +368,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
|
|||||||
Trace.beginSection("acquiring wake-and-unlock");
|
Trace.beginSection("acquiring wake-and-unlock");
|
||||||
mWakeLock.acquire();
|
mWakeLock.acquire();
|
||||||
Trace.endSection();
|
Trace.endSection();
|
||||||
if (DEBUG_BIO_WAKELOCK) {
|
mLogger.i("biometric acquired, grabbing biometric wakelock");
|
||||||
Log.i(TAG, "biometric acquired, grabbing biometric wakelock");
|
|
||||||
}
|
|
||||||
mHandler.postDelayed(mReleaseBiometricWakeLockRunnable,
|
mHandler.postDelayed(mReleaseBiometricWakeLockRunnable,
|
||||||
BIOMETRIC_WAKELOCK_TIMEOUT_MS);
|
BIOMETRIC_WAKELOCK_TIMEOUT_MS);
|
||||||
}
|
}
|
||||||
@@ -411,7 +405,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
|
|||||||
mKeyguardViewMediator.userActivity();
|
mKeyguardViewMediator.userActivity();
|
||||||
startWakeAndUnlock(biometricSourceType, isStrongBiometric);
|
startWakeAndUnlock(biometricSourceType, isStrongBiometric);
|
||||||
} else {
|
} else {
|
||||||
Log.d(TAG, "onBiometricAuthenticated aborted by bypass controller");
|
mLogger.d("onBiometricAuthenticated aborted by bypass controller");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -427,7 +421,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void startWakeAndUnlock(@WakeAndUnlockMode int mode) {
|
public void startWakeAndUnlock(@WakeAndUnlockMode int mode) {
|
||||||
Log.v(TAG, "startWakeAndUnlock(" + mode + ")");
|
mLogger.logStartWakeAndUnlock(mode);
|
||||||
boolean wasDeviceInteractive = mUpdateMonitor.isDeviceInteractive();
|
boolean wasDeviceInteractive = mUpdateMonitor.isDeviceInteractive();
|
||||||
mMode = mode;
|
mMode = mode;
|
||||||
mHasScreenTurnedOnSinceAuthenticating = false;
|
mHasScreenTurnedOnSinceAuthenticating = false;
|
||||||
@@ -442,9 +436,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
|
|||||||
// brightness changes due to display state transitions.
|
// brightness changes due to display state transitions.
|
||||||
Runnable wakeUp = ()-> {
|
Runnable wakeUp = ()-> {
|
||||||
if (!wasDeviceInteractive || mUpdateMonitor.isDreaming()) {
|
if (!wasDeviceInteractive || mUpdateMonitor.isDreaming()) {
|
||||||
if (DEBUG_BIO_WAKELOCK) {
|
mLogger.i("bio wakelock: Authenticated, waking up...");
|
||||||
Log.i(TAG, "bio wakelock: Authenticated, waking up...");
|
|
||||||
}
|
|
||||||
mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
|
mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
|
||||||
"android.policy:BIOMETRIC");
|
"android.policy:BIOMETRIC");
|
||||||
}
|
}
|
||||||
@@ -537,13 +529,16 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
|
|||||||
}
|
}
|
||||||
|
|
||||||
private @WakeAndUnlockMode int calculateModeForFingerprint(boolean isStrongBiometric) {
|
private @WakeAndUnlockMode int calculateModeForFingerprint(boolean isStrongBiometric) {
|
||||||
boolean unlockingAllowed =
|
final boolean unlockingAllowed =
|
||||||
mUpdateMonitor.isUnlockingWithBiometricAllowed(isStrongBiometric);
|
mUpdateMonitor.isUnlockingWithBiometricAllowed(isStrongBiometric);
|
||||||
boolean deviceDreaming = mUpdateMonitor.isDreaming();
|
final boolean deviceInteractive = mUpdateMonitor.isDeviceInteractive();
|
||||||
|
final boolean keyguardShowing = mKeyguardStateController.isShowing();
|
||||||
|
final boolean deviceDreaming = mUpdateMonitor.isDreaming();
|
||||||
|
|
||||||
if (!mUpdateMonitor.isDeviceInteractive()) {
|
logCalculateModeForFingerprint(unlockingAllowed, deviceInteractive,
|
||||||
if (!mKeyguardStateController.isShowing()
|
keyguardShowing, deviceDreaming, isStrongBiometric);
|
||||||
&& !mScreenOffAnimationController.isKeyguardShowDelayed()) {
|
if (!deviceInteractive) {
|
||||||
|
if (!keyguardShowing && !mScreenOffAnimationController.isKeyguardShowDelayed()) {
|
||||||
if (mKeyguardStateController.isUnlocked()) {
|
if (mKeyguardStateController.isUnlocked()) {
|
||||||
return MODE_WAKE_AND_UNLOCK;
|
return MODE_WAKE_AND_UNLOCK;
|
||||||
}
|
}
|
||||||
@@ -559,7 +554,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
|
|||||||
if (unlockingAllowed && deviceDreaming) {
|
if (unlockingAllowed && deviceDreaming) {
|
||||||
return MODE_WAKE_AND_UNLOCK_FROM_DREAM;
|
return MODE_WAKE_AND_UNLOCK_FROM_DREAM;
|
||||||
}
|
}
|
||||||
if (mKeyguardStateController.isShowing()) {
|
if (keyguardShowing) {
|
||||||
if (mKeyguardViewController.primaryBouncerIsOrWillBeShowing() && unlockingAllowed) {
|
if (mKeyguardViewController.primaryBouncerIsOrWillBeShowing() && unlockingAllowed) {
|
||||||
return MODE_DISMISS_BOUNCER;
|
return MODE_DISMISS_BOUNCER;
|
||||||
} else if (unlockingAllowed) {
|
} else if (unlockingAllowed) {
|
||||||
@@ -571,14 +566,39 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
|
|||||||
return MODE_NONE;
|
return MODE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void logCalculateModeForFingerprint(boolean unlockingAllowed, boolean deviceInteractive,
|
||||||
|
boolean keyguardShowing, boolean deviceDreaming, boolean strongBiometric) {
|
||||||
|
if (unlockingAllowed) {
|
||||||
|
mLogger.logCalculateModeForFingerprintUnlockingAllowed(deviceInteractive,
|
||||||
|
keyguardShowing, deviceDreaming);
|
||||||
|
} else {
|
||||||
|
// if unlocking isn't allowed, log more information about why unlocking may not
|
||||||
|
// have been allowed
|
||||||
|
final int strongAuthFlags = mUpdateMonitor.getStrongAuthTracker().getStrongAuthForUser(
|
||||||
|
KeyguardUpdateMonitor.getCurrentUser());
|
||||||
|
final boolean nonStrongBiometricAllowed =
|
||||||
|
mUpdateMonitor.getStrongAuthTracker()
|
||||||
|
.isNonStrongBiometricAllowedAfterIdleTimeout(
|
||||||
|
KeyguardUpdateMonitor.getCurrentUser());
|
||||||
|
|
||||||
|
mLogger.logCalculateModeForFingerprintUnlockingNotAllowed(strongBiometric,
|
||||||
|
strongAuthFlags, nonStrongBiometricAllowed, deviceInteractive, keyguardShowing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private @WakeAndUnlockMode int calculateModeForPassiveAuth(boolean isStrongBiometric) {
|
private @WakeAndUnlockMode int calculateModeForPassiveAuth(boolean isStrongBiometric) {
|
||||||
boolean unlockingAllowed =
|
final boolean deviceInteractive = mUpdateMonitor.isDeviceInteractive();
|
||||||
|
final boolean isKeyguardShowing = mKeyguardStateController.isShowing();
|
||||||
|
final boolean unlockingAllowed =
|
||||||
mUpdateMonitor.isUnlockingWithBiometricAllowed(isStrongBiometric);
|
mUpdateMonitor.isUnlockingWithBiometricAllowed(isStrongBiometric);
|
||||||
boolean deviceDreaming = mUpdateMonitor.isDreaming();
|
final boolean deviceDreaming = mUpdateMonitor.isDreaming();
|
||||||
boolean bypass = mKeyguardBypassController.getBypassEnabled()
|
final boolean bypass = mKeyguardBypassController.getBypassEnabled()
|
||||||
|| mAuthController.isUdfpsFingerDown();
|
|| mAuthController.isUdfpsFingerDown();
|
||||||
if (!mUpdateMonitor.isDeviceInteractive()) {
|
|
||||||
if (!mKeyguardStateController.isShowing()) {
|
logCalculateModeForPassiveAuth(unlockingAllowed, deviceInteractive, isKeyguardShowing,
|
||||||
|
deviceDreaming, bypass, isStrongBiometric);
|
||||||
|
if (!deviceInteractive) {
|
||||||
|
if (!isKeyguardShowing) {
|
||||||
return bypass ? MODE_WAKE_AND_UNLOCK : MODE_ONLY_WAKE;
|
return bypass ? MODE_WAKE_AND_UNLOCK : MODE_ONLY_WAKE;
|
||||||
} else if (!unlockingAllowed) {
|
} else if (!unlockingAllowed) {
|
||||||
return bypass ? MODE_SHOW_BOUNCER : MODE_NONE;
|
return bypass ? MODE_SHOW_BOUNCER : MODE_NONE;
|
||||||
@@ -602,11 +622,11 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
|
|||||||
if (unlockingAllowed && mKeyguardStateController.isOccluded()) {
|
if (unlockingAllowed && mKeyguardStateController.isOccluded()) {
|
||||||
return MODE_UNLOCK_COLLAPSING;
|
return MODE_UNLOCK_COLLAPSING;
|
||||||
}
|
}
|
||||||
if (mKeyguardStateController.isShowing()) {
|
if (isKeyguardShowing) {
|
||||||
if ((mKeyguardViewController.primaryBouncerIsOrWillBeShowing()
|
if ((mKeyguardViewController.primaryBouncerIsOrWillBeShowing()
|
||||||
|| mKeyguardBypassController.getAltBouncerShowing()) && unlockingAllowed) {
|
|| mKeyguardBypassController.getAltBouncerShowing()) && unlockingAllowed) {
|
||||||
return MODE_DISMISS_BOUNCER;
|
return MODE_DISMISS_BOUNCER;
|
||||||
} else if (unlockingAllowed && (bypass || mAuthController.isUdfpsFingerDown())) {
|
} else if (unlockingAllowed && bypass) {
|
||||||
return MODE_UNLOCK_COLLAPSING;
|
return MODE_UNLOCK_COLLAPSING;
|
||||||
} else {
|
} else {
|
||||||
return bypass ? MODE_SHOW_BOUNCER : MODE_NONE;
|
return bypass ? MODE_SHOW_BOUNCER : MODE_NONE;
|
||||||
@@ -615,6 +635,28 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
|
|||||||
return MODE_NONE;
|
return MODE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void logCalculateModeForPassiveAuth(boolean unlockingAllowed,
|
||||||
|
boolean deviceInteractive, boolean keyguardShowing, boolean deviceDreaming,
|
||||||
|
boolean bypass, boolean strongBiometric) {
|
||||||
|
if (unlockingAllowed) {
|
||||||
|
mLogger.logCalculateModeForPassiveAuthUnlockingAllowed(
|
||||||
|
deviceInteractive, keyguardShowing, deviceDreaming, bypass);
|
||||||
|
} else {
|
||||||
|
// if unlocking isn't allowed, log more information about why unlocking may not
|
||||||
|
// have been allowed
|
||||||
|
final int strongAuthFlags = mUpdateMonitor.getStrongAuthTracker().getStrongAuthForUser(
|
||||||
|
KeyguardUpdateMonitor.getCurrentUser());
|
||||||
|
final boolean nonStrongBiometricAllowed =
|
||||||
|
mUpdateMonitor.getStrongAuthTracker()
|
||||||
|
.isNonStrongBiometricAllowedAfterIdleTimeout(
|
||||||
|
KeyguardUpdateMonitor.getCurrentUser());
|
||||||
|
|
||||||
|
mLogger.logCalculateModeForPassiveAuthUnlockingNotAllowed(
|
||||||
|
strongBiometric, strongAuthFlags, nonStrongBiometricAllowed,
|
||||||
|
deviceInteractive, keyguardShowing, bypass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBiometricAuthFailed(BiometricSourceType biometricSourceType) {
|
public void onBiometricAuthFailed(BiometricSourceType biometricSourceType) {
|
||||||
mMetricsLogger.write(new LogMaker(MetricsEvent.BIOMETRIC_AUTH)
|
mMetricsLogger.write(new LogMaker(MetricsEvent.BIOMETRIC_AUTH)
|
||||||
@@ -632,6 +674,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
|
|||||||
|
|
||||||
if (!mVibratorHelper.hasVibrator()
|
if (!mVibratorHelper.hasVibrator()
|
||||||
&& (!mUpdateMonitor.isDeviceInteractive() || mUpdateMonitor.isDreaming())) {
|
&& (!mUpdateMonitor.isDeviceInteractive() || mUpdateMonitor.isDreaming())) {
|
||||||
|
mLogger.d("wakeup device on authentication failure (device doesn't have a vibrator)");
|
||||||
startWakeAndUnlock(MODE_ONLY_WAKE);
|
startWakeAndUnlock(MODE_ONLY_WAKE);
|
||||||
} else if (biometricSourceType == BiometricSourceType.FINGERPRINT
|
} else if (biometricSourceType == BiometricSourceType.FINGERPRINT
|
||||||
&& mUpdateMonitor.isUdfpsSupported()) {
|
&& mUpdateMonitor.isUdfpsSupported()) {
|
||||||
@@ -644,6 +687,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
|
|||||||
mLastFpFailureUptimeMillis = currUptimeMillis;
|
mLastFpFailureUptimeMillis = currUptimeMillis;
|
||||||
|
|
||||||
if (mNumConsecutiveFpFailures >= UDFPS_ATTEMPTS_BEFORE_SHOW_BOUNCER) {
|
if (mNumConsecutiveFpFailures >= UDFPS_ATTEMPTS_BEFORE_SHOW_BOUNCER) {
|
||||||
|
mLogger.logUdfpsAttemptThresholdMet(mNumConsecutiveFpFailures);
|
||||||
startWakeAndUnlock(MODE_SHOW_BOUNCER);
|
startWakeAndUnlock(MODE_SHOW_BOUNCER);
|
||||||
UI_EVENT_LOGGER.log(BiometricUiEvent.BIOMETRIC_BOUNCER_SHOWN, getSessionId());
|
UI_EVENT_LOGGER.log(BiometricUiEvent.BIOMETRIC_BOUNCER_SHOWN, getSessionId());
|
||||||
mNumConsecutiveFpFailures = 0;
|
mNumConsecutiveFpFailures = 0;
|
||||||
@@ -674,6 +718,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp
|
|||||||
&& (msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT
|
&& (msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT
|
||||||
|| msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT);
|
|| msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT);
|
||||||
if (fingerprintLockout) {
|
if (fingerprintLockout) {
|
||||||
|
mLogger.d("fingerprint locked out");
|
||||||
startWakeAndUnlock(MODE_SHOW_BOUNCER);
|
startWakeAndUnlock(MODE_SHOW_BOUNCER);
|
||||||
UI_EVENT_LOGGER.log(BiometricUiEvent.BIOMETRIC_BOUNCER_SHOWN, getSessionId());
|
UI_EVENT_LOGGER.log(BiometricUiEvent.BIOMETRIC_BOUNCER_SHOWN, getSessionId());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ import android.testing.TestableResources;
|
|||||||
import com.android.internal.logging.MetricsLogger;
|
import com.android.internal.logging.MetricsLogger;
|
||||||
import com.android.internal.util.LatencyTracker;
|
import com.android.internal.util.LatencyTracker;
|
||||||
import com.android.keyguard.KeyguardUpdateMonitor;
|
import com.android.keyguard.KeyguardUpdateMonitor;
|
||||||
|
import com.android.keyguard.logging.BiometricUnlockLogger;
|
||||||
import com.android.systemui.SysuiTestCase;
|
import com.android.systemui.SysuiTestCase;
|
||||||
import com.android.systemui.biometrics.AuthController;
|
import com.android.systemui.biometrics.AuthController;
|
||||||
import com.android.systemui.dump.DumpManager;
|
import com.android.systemui.dump.DumpManager;
|
||||||
@@ -78,6 +79,8 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
|
|||||||
@Mock
|
@Mock
|
||||||
private KeyguardUpdateMonitor mUpdateMonitor;
|
private KeyguardUpdateMonitor mUpdateMonitor;
|
||||||
@Mock
|
@Mock
|
||||||
|
private KeyguardUpdateMonitor.StrongAuthTracker mStrongAuthTracker;
|
||||||
|
@Mock
|
||||||
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
|
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
|
||||||
@Mock
|
@Mock
|
||||||
private NotificationShadeWindowController mNotificationShadeWindowController;
|
private NotificationShadeWindowController mNotificationShadeWindowController;
|
||||||
@@ -119,6 +122,8 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
|
|||||||
private ScreenOffAnimationController mScreenOffAnimationController;
|
private ScreenOffAnimationController mScreenOffAnimationController;
|
||||||
@Mock
|
@Mock
|
||||||
private VibratorHelper mVibratorHelper;
|
private VibratorHelper mVibratorHelper;
|
||||||
|
@Mock
|
||||||
|
private BiometricUnlockLogger mLogger;
|
||||||
private BiometricUnlockController mBiometricUnlockController;
|
private BiometricUnlockController mBiometricUnlockController;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@@ -138,12 +143,13 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
|
|||||||
mKeyguardViewMediator, mScrimController, mShadeController,
|
mKeyguardViewMediator, mScrimController, mShadeController,
|
||||||
mNotificationShadeWindowController, mKeyguardStateController, mHandler,
|
mNotificationShadeWindowController, mKeyguardStateController, mHandler,
|
||||||
mUpdateMonitor, res.getResources(), mKeyguardBypassController,
|
mUpdateMonitor, res.getResources(), mKeyguardBypassController,
|
||||||
mMetricsLogger, mDumpManager, mPowerManager,
|
mMetricsLogger, mDumpManager, mPowerManager, mLogger,
|
||||||
mNotificationMediaManager, mWakefulnessLifecycle, mScreenLifecycle,
|
mNotificationMediaManager, mWakefulnessLifecycle, mScreenLifecycle,
|
||||||
mAuthController, mStatusBarStateController, mKeyguardUnlockAnimationController,
|
mAuthController, mStatusBarStateController, mKeyguardUnlockAnimationController,
|
||||||
mSessionTracker, mLatencyTracker, mScreenOffAnimationController, mVibratorHelper);
|
mSessionTracker, mLatencyTracker, mScreenOffAnimationController, mVibratorHelper);
|
||||||
mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager);
|
mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager);
|
||||||
mBiometricUnlockController.addBiometricModeListener(mBiometricModeListener);
|
mBiometricUnlockController.addBiometricModeListener(mBiometricModeListener);
|
||||||
|
when(mUpdateMonitor.getStrongAuthTracker()).thenReturn(mStrongAuthTracker);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -285,6 +291,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void onBiometricAuthenticated_whenFace_andBypass_encrypted_showPrimaryBouncer() {
|
public void onBiometricAuthenticated_whenFace_andBypass_encrypted_showPrimaryBouncer() {
|
||||||
reset(mUpdateMonitor);
|
reset(mUpdateMonitor);
|
||||||
|
when(mUpdateMonitor.getStrongAuthTracker()).thenReturn(mStrongAuthTracker);
|
||||||
when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
|
when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
|
||||||
mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager);
|
mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager);
|
||||||
|
|
||||||
@@ -322,6 +329,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void onBiometricAuthenticated_whenFace_noBypass_encrypted_doNothing() {
|
public void onBiometricAuthenticated_whenFace_noBypass_encrypted_doNothing() {
|
||||||
reset(mUpdateMonitor);
|
reset(mUpdateMonitor);
|
||||||
|
when(mUpdateMonitor.getStrongAuthTracker()).thenReturn(mStrongAuthTracker);
|
||||||
mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager);
|
mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager);
|
||||||
|
|
||||||
when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
|
when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
|
||||||
|
|||||||
Reference in New Issue
Block a user