Merge "Immediately stop running face auth if the display is OFF" into udc-d1-dev

This commit is contained in:
Treehugger Robot
2023-08-09 11:34:15 +00:00
committed by Android (Google) Code Review
9 changed files with 174 additions and 14 deletions

View File

@@ -38,4 +38,6 @@
protected. -->
<bool name="flag_battery_shield_icon">false</bool>
<!-- Whether face auth will immediately stop when the display state is OFF -->
<bool name="flag_stop_face_auth_on_display_off">false</bool>
</resources>

View File

@@ -33,6 +33,7 @@ import com.android.keyguard.InternalFaceAuthReasons.AUTH_REQUEST_DURING_CANCELLA
import com.android.keyguard.InternalFaceAuthReasons.BIOMETRIC_ENABLED
import com.android.keyguard.InternalFaceAuthReasons.CAMERA_LAUNCHED
import com.android.keyguard.InternalFaceAuthReasons.DEVICE_WOKEN_UP_ON_REACH_GESTURE
import com.android.keyguard.InternalFaceAuthReasons.DISPLAY_OFF
import com.android.keyguard.InternalFaceAuthReasons.DREAM_STARTED
import com.android.keyguard.InternalFaceAuthReasons.DREAM_STOPPED
import com.android.keyguard.InternalFaceAuthReasons.ENROLLMENTS_CHANGED
@@ -131,6 +132,7 @@ private object InternalFaceAuthReasons {
const val NON_STRONG_BIOMETRIC_ALLOWED_CHANGED =
"Face auth stopped because non strong biometric allowed changed"
const val POSTURE_CHANGED = "Face auth started/stopped due to device posture changed."
const val DISPLAY_OFF = "Face auth stopped due to display state OFF."
}
/**
@@ -221,7 +223,8 @@ constructor(private val id: Int, val reason: String, var extraInfo: Int = 0) :
FACE_AUTH_UPDATED_STRONG_AUTH_CHANGED(1255, STRONG_AUTH_ALLOWED_CHANGED),
@UiEvent(doc = NON_STRONG_BIOMETRIC_ALLOWED_CHANGED)
FACE_AUTH_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED(1256, NON_STRONG_BIOMETRIC_ALLOWED_CHANGED),
@UiEvent(doc = ACCESSIBILITY_ACTION) FACE_AUTH_ACCESSIBILITY_ACTION(1454, ACCESSIBILITY_ACTION);
@UiEvent(doc = ACCESSIBILITY_ACTION) FACE_AUTH_ACCESSIBILITY_ACTION(1454, ACCESSIBILITY_ACTION),
@UiEvent(doc = DISPLAY_OFF) FACE_AUTH_DISPLAY_OFF(1461, DISPLAY_OFF);
override fun getId(): Int = this.id

View File

@@ -27,6 +27,7 @@ data class KeyguardFaceListenModel(
override var userId: Int = 0,
override var listening: Boolean = false,
// keep sorted
var allowedDisplayState: Boolean = false,
var alternateBouncerShowing: Boolean = false,
var authInterruptActive: Boolean = false,
var biometricSettingEnabledForUser: Boolean = false,
@@ -57,6 +58,8 @@ data class KeyguardFaceListenModel(
userId.toString(),
listening.toString(),
// keep sorted
allowedDisplayState.toString(),
alternateBouncerShowing.toString(),
authInterruptActive.toString(),
biometricSettingEnabledForUser.toString(),
bouncerFullyShown.toString(),
@@ -74,7 +77,6 @@ data class KeyguardFaceListenModel(
supportsDetect.toString(),
switchingUser.toString(),
systemUser.toString(),
alternateBouncerShowing.toString(),
udfpsFingerDown.toString(),
userNotTrustedOrDetectionIsNeeded.toString(),
)
@@ -96,7 +98,9 @@ data class KeyguardFaceListenModel(
userId = model.userId
listening = model.listening
// keep sorted
allowedDisplayState = model.allowedDisplayState
alternateBouncerShowing = model.alternateBouncerShowing
authInterruptActive = model.authInterruptActive
biometricSettingEnabledForUser = model.biometricSettingEnabledForUser
bouncerFullyShown = model.bouncerFullyShown
faceAndFpNotAuthenticated = model.faceAndFpNotAuthenticated
@@ -105,7 +109,6 @@ data class KeyguardFaceListenModel(
faceLockedOut = model.faceLockedOut
goingToSleep = model.goingToSleep
keyguardAwake = model.keyguardAwake
goingToSleep = model.goingToSleep
keyguardGoingAway = model.keyguardGoingAway
listeningForFaceAssistant = model.listeningForFaceAssistant
occludingAppRequestingFaceAuth = model.occludingAppRequestingFaceAuth
@@ -140,6 +143,8 @@ data class KeyguardFaceListenModel(
"userId",
"listening",
// keep sorted
"allowedDisplayState",
"alternateBouncerShowing",
"authInterruptActive",
"biometricSettingEnabledForUser",
"bouncerFullyShown",
@@ -157,7 +162,6 @@ data class KeyguardFaceListenModel(
"supportsDetect",
"switchingUser",
"systemUser",
"udfpsBouncerShowing",
"udfpsFingerDown",
"userNotTrustedOrDetectionIsNeeded",
)

View File

@@ -37,6 +37,7 @@ import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STR
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import static com.android.keyguard.FaceAuthReasonKt.apiRequestReasonToUiEvent;
import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_DISPLAY_OFF;
import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED;
import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_DREAM_STARTED;
import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_FACE_CANCEL_NOT_RECEIVED;
@@ -131,6 +132,7 @@ import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.view.Display;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -155,6 +157,8 @@ import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.dump.DumpsysTableLogger;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.domain.interactor.FaceAuthenticationListener;
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
import com.android.systemui.keyguard.shared.constants.TrustAgentUiEvent;
@@ -169,6 +173,7 @@ import com.android.systemui.keyguard.shared.model.SysUiFaceAuthenticateOptions;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.WeatherData;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.settings.DisplayTracker;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
@@ -327,6 +332,25 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
}
};
private final DisplayTracker.Callback mDisplayCallback = new DisplayTracker.Callback() {
@Override
public void onDisplayChanged(int displayId) {
if (displayId != Display.DEFAULT_DISPLAY) {
return;
}
if (mDisplayTracker.getDisplay(mDisplayTracker.getDefaultDisplayId()).getState()
== Display.STATE_OFF) {
mAllowedDisplayStateForFaceAuth = false;
updateFaceListeningState(
BIOMETRIC_ACTION_STOP,
FACE_AUTH_DISPLAY_OFF
);
} else {
mAllowedDisplayStateForFaceAuth = true;
}
}
};
private final FaceWakeUpTriggersConfig mFaceWakeUpTriggersConfig;
HashMap<Integer, SimData> mSimDatas = new HashMap<>();
@@ -347,6 +371,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private boolean mOccludingAppRequestingFp;
private boolean mOccludingAppRequestingFace;
private boolean mSecureCameraLaunched;
private boolean mAllowedDisplayStateForFaceAuth = true;
@VisibleForTesting
protected boolean mTelephonyCapable;
@@ -391,6 +416,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private final FaceManager mFaceManager;
@Nullable
private KeyguardFaceAuthInteractor mFaceAuthInteractor;
private final DisplayTracker mDisplayTracker;
private final LockPatternUtils mLockPatternUtils;
@VisibleForTesting
@DevicePostureInt
@@ -2186,6 +2212,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
Trace.beginSection("KeyguardUpdateMonitor#handleStartedWakingUp");
Assert.isMainThread();
mAllowedDisplayStateForFaceAuth = true;
updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
if (mFaceWakeUpTriggersConfig.shouldTriggerFaceAuthOnWakeUpFrom(pmWakeReason)) {
FACE_AUTH_UPDATED_STARTED_WAKING_UP.setExtraInfo(pmWakeReason);
@@ -2338,7 +2365,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
@Nullable BiometricManager biometricManager,
FaceWakeUpTriggersConfig faceWakeUpTriggersConfig,
DevicePostureController devicePostureController,
Optional<FingerprintInteractiveToAuthProvider> interactiveToAuthProvider) {
Optional<FingerprintInteractiveToAuthProvider> interactiveToAuthProvider,
FeatureFlags featureFlags,
DisplayTracker displayTracker) {
mContext = context;
mSubscriptionManager = subscriptionManager;
mUserTracker = userTracker;
@@ -2379,6 +2408,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mConfigFaceAuthSupportedPosture = mContext.getResources().getInteger(
R.integer.config_face_auth_supported_posture);
mFaceWakeUpTriggersConfig = faceWakeUpTriggersConfig;
mDisplayTracker = displayTracker;
if (featureFlags.isEnabled(Flags.STOP_FACE_AUTH_ON_DISPLAY_OFF)) {
mDisplayTracker.addDisplayChangeCallback(mDisplayCallback, mainExecutor);
}
mHandler = new Handler(mainLooper) {
@Override
@@ -3185,7 +3218,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
&& (!mSecureCameraLaunched || mAlternateBouncerShowing)
&& faceAndFpNotAuthenticated
&& !mGoingToSleep
&& isPostureAllowedForFaceAuth;
&& isPostureAllowedForFaceAuth
&& mAllowedDisplayStateForFaceAuth;
// Aggregate relevant fields for debug logging.
logListenerModelData(
@@ -3193,6 +3227,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
System.currentTimeMillis(),
user,
shouldListen,
mAllowedDisplayStateForFaceAuth,
mAlternateBouncerShowing,
mAuthInterruptActive,
biometricEnabledForUser,
@@ -4337,6 +4372,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mLockPatternUtils.unregisterStrongAuthTracker(mStrongAuthTracker);
mTrustManager.unregisterTrustListener(this);
mDisplayTracker.removeCallback(mDisplayCallback);
mHandler.removeCallbacksAndMessages(null);
}

View File

@@ -268,6 +268,11 @@ object Flags {
@JvmField
val KEYGUARD_TALKBACK_FIX = releasedFlag(238, "keyguard_talkback_fix")
/** Stop running face auth when the display state changes to OFF. */
// TODO(b/294221702): Tracking bug.
@JvmField val STOP_FACE_AUTH_ON_DISPLAY_OFF = resourceBooleanFlag(245,
R.bool.flag_stop_face_auth_on_display_off, "stop_face_auth_on_display_off")
// 300 - power menu
// TODO(b/254512600): Tracking Bug
@JvmField val POWER_MENU_LITE = releasedFlag(300, "power_menu_lite")

View File

@@ -48,6 +48,9 @@ interface DisplayTracker {
/** Remove a [Callback] previously added. */
fun removeCallback(callback: Callback)
/** Gets the Display with the given displayId */
fun getDisplay(displayId: Int): Display
/** Ćallback for notifying of changes. */
interface Callback {

View File

@@ -115,6 +115,10 @@ internal constructor(
}
}
override fun getDisplay(displayId: Int): Display {
return displayManager.getDisplay(displayId)
}
@WorkerThread
private fun onDisplayAdded(displayId: Int, list: List<DisplayTrackerDataItem>) {
Assert.isNotMainThread()

View File

@@ -38,6 +38,7 @@ import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_STATE_CANCELL
import static com.android.keyguard.KeyguardUpdateMonitor.DEFAULT_CANCEL_SIGNAL_TIMEOUT;
import static com.android.keyguard.KeyguardUpdateMonitor.HAL_POWER_PRESS_TIMEOUT;
import static com.android.keyguard.KeyguardUpdateMonitor.getCurrentUser;
import static com.android.systemui.flags.Flags.STOP_FACE_AUTH_ON_DISPLAY_OFF;
import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_CLOSED;
import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_OPENED;
import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_UNKNOWN;
@@ -84,6 +85,7 @@ import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricSourceType;
import android.hardware.biometrics.ComponentInfoInternal;
import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
import android.hardware.display.DisplayManagerGlobal;
import android.hardware.face.FaceAuthenticateOptions;
import android.hardware.face.FaceManager;
import android.hardware.face.FaceSensorProperties;
@@ -115,6 +117,9 @@ import android.telephony.TelephonyManager;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.Display;
import android.view.DisplayAdjustments;
import android.view.DisplayInfo;
import androidx.annotation.NonNull;
@@ -134,8 +139,10 @@ import com.android.systemui.biometrics.AuthController;
import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.settings.FakeDisplayTracker;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -288,10 +295,13 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mFingerprintAuthenticatorsRegisteredCallback;
private IFaceAuthenticatorsRegisteredCallback mFaceAuthenticatorsRegisteredCallback;
private final InstanceId mKeyguardInstanceId = InstanceId.fakeInstanceId(999);
private FakeFeatureFlags mFeatureFlags;
private FakeDisplayTracker mDisplayTracker;
@Before
public void setup() throws RemoteException {
MockitoAnnotations.initMocks(this);
mDisplayTracker = new FakeDisplayTracker(mContext);
when(mSessionTracker.getSessionId(SESSION_KEYGUARD)).thenReturn(mKeyguardInstanceId);
when(mUserManager.isUserUnlocked(anyInt())).thenReturn(true);
@@ -326,6 +336,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mTestableLooper = TestableLooper.get(this);
allowTestableLooperAsMainThread();
mFeatureFlags = new FakeFeatureFlags();
mFeatureFlags.set(STOP_FACE_AUTH_ON_DISPLAY_OFF, false);
when(mSecureSettings.getUriFor(anyString())).thenReturn(mURI);
@@ -336,6 +348,11 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
anyInt());
mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mContext);
setupBiometrics(mKeyguardUpdateMonitor);
}
private void setupBiometrics(KeyguardUpdateMonitor keyguardUpdateMonitor)
throws RemoteException {
captureAuthenticatorsRegisteredCallbacks();
setupFaceAuth(/* isClass3 */ false);
setupFingerprintAuth(/* isClass3 */ true);
@@ -345,9 +362,9 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mBiometricEnabledOnKeyguardCallback = mBiometricEnabledCallbackArgCaptor.getValue();
biometricsEnabledForCurrentUser();
mHandler = spy(mKeyguardUpdateMonitor.getHandler());
mHandler = spy(keyguardUpdateMonitor.getHandler());
try {
FieldSetter.setField(mKeyguardUpdateMonitor,
FieldSetter.setField(keyguardUpdateMonitor,
KeyguardUpdateMonitor.class.getDeclaredField("mHandler"), mHandler);
} catch (NoSuchFieldException e) {
@@ -2945,6 +2962,79 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
TelephonyManager.SIM_STATE_NOT_READY);
}
@Test
public void stopFaceAuthOnDisplayOffFlagNotEnabled_doNotRegisterForDisplayCallback() {
assertThat(mDisplayTracker.getDisplayCallbacks().size()).isEqualTo(0);
}
@Test
public void onDisplayOn_nothingHappens() throws RemoteException {
// GIVEN
keyguardIsVisible();
enableStopFaceAuthOnDisplayOff();
// WHEN the default display state changes to ON
triggerDefaultDisplayStateChangeToOn();
// THEN face auth is NOT started since we rely on STARTED_WAKING_UP to start face auth,
// NOT the display on event
verifyFaceAuthenticateNeverCalled();
verifyFaceDetectNeverCalled();
}
@Test
public void onDisplayOff_stopFaceAuth() throws RemoteException {
enableStopFaceAuthOnDisplayOff();
// GIVEN device is listening for face
mKeyguardUpdateMonitor.setKeyguardShowing(true, false);
mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
mTestableLooper.processAllMessages();
verifyFaceAuthenticateCall();
final CancellationSignal faceCancel = spy(mKeyguardUpdateMonitor.mFaceCancelSignal);
mKeyguardUpdateMonitor.mFaceCancelSignal = faceCancel;
KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class);
mKeyguardUpdateMonitor.registerCallback(callback);
// WHEN the default display state changes to OFF
triggerDefaultDisplayStateChangeToOff();
// THEN face listening is stopped.
verify(faceCancel).cancel();
verify(callback).onBiometricRunningStateChanged(
eq(false), eq(BiometricSourceType.FACE)); // beverlyt
}
private void triggerDefaultDisplayStateChangeToOn() {
triggerDefaultDisplayStateChangeTo(true);
}
private void triggerDefaultDisplayStateChangeToOff() {
triggerDefaultDisplayStateChangeTo(false);
}
/**
* @param on true for Display.STATE_ON, else Display.STATE_OFF
*/
private void triggerDefaultDisplayStateChangeTo(boolean on) {
DisplayManagerGlobal displayManagerGlobal = mock(DisplayManagerGlobal.class);
DisplayInfo displayInfoWithDisplayState = new DisplayInfo();
displayInfoWithDisplayState.state = on ? Display.STATE_ON : Display.STATE_OFF;
when(displayManagerGlobal.getDisplayInfo(mDisplayTracker.getDefaultDisplayId()))
.thenReturn(displayInfoWithDisplayState);
mDisplayTracker.setAllDisplays(new Display[]{
new Display(
displayManagerGlobal,
mDisplayTracker.getDefaultDisplayId(),
displayInfoWithDisplayState,
DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS
)
});
mDisplayTracker.triggerOnDisplayChanged(mDisplayTracker.getDefaultDisplayId());
}
private void verifyFingerprintAuthenticateNeverCalled() {
verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), any());
verify(mFingerprintManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
@@ -3213,6 +3303,18 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mTestableLooper.processAllMessages();
}
private void enableStopFaceAuthOnDisplayOff() throws RemoteException {
cleanupKeyguardUpdateMonitor();
clearInvocations(mFaceManager);
clearInvocations(mFingerprintManager);
clearInvocations(mBiometricManager);
clearInvocations(mStatusBarStateController);
mFeatureFlags.set(STOP_FACE_AUTH_ON_DISPLAY_OFF, true);
mKeyguardUpdateMonitor = new TestableKeyguardUpdateMonitor(mContext);
setupBiometrics(mKeyguardUpdateMonitor);
assertThat(mDisplayTracker.getDisplayCallbacks().size()).isEqualTo(1);
}
private Intent putPhoneInfo(Intent intent, Bundle data, Boolean simInited) {
int subscription = simInited
? 1/* mock subid=1 */ : SubscriptionManager.PLACEHOLDER_SUBSCRIPTION_ID_BASE;
@@ -3272,7 +3374,8 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
mDreamManager, mDevicePolicyManager, mSensorPrivacyManager, mTelephonyManager,
mPackageManager, mFaceManager, mFingerprintManager, mBiometricManager,
mFaceWakeUpTriggersConfig, mDevicePostureController,
Optional.of(mInteractiveToAuthProvider));
Optional.of(mInteractiveToAuthProvider), mFeatureFlags,
mDisplayTracker);
setStrongAuthTracker(KeyguardUpdateMonitorTest.this.mStrongAuthTracker);
}

View File

@@ -26,7 +26,7 @@ class FakeDisplayTracker constructor(val context: Context) : DisplayTracker {
override var defaultDisplayId: Int = Display.DEFAULT_DISPLAY
override var allDisplays: Array<Display> = displayManager.displays
private val displayCallbacks: MutableList<DisplayTracker.Callback> = ArrayList()
val displayCallbacks: MutableList<DisplayTracker.Callback> = ArrayList()
private val brightnessCallbacks: MutableList<DisplayTracker.Callback> = ArrayList()
override fun addDisplayChangeCallback(callback: DisplayTracker.Callback, executor: Executor) {
displayCallbacks.add(callback)
@@ -43,12 +43,12 @@ class FakeDisplayTracker constructor(val context: Context) : DisplayTracker {
brightnessCallbacks.remove(callback)
}
fun setDefaultDisplay(displayId: Int) {
defaultDisplayId = displayId
override fun getDisplay(displayId: Int): Display {
return allDisplays.filter { display -> display.displayId == displayId }[0]
}
fun setDisplays(displays: Array<Display>) {
allDisplays = displays
fun setDefaultDisplay(displayId: Int) {
defaultDisplayId = displayId
}
fun triggerOnDisplayAdded(displayId: Int) {