Loading core/java/android/hardware/biometrics/BiometricPrompt.java +9 −1 Original line number Diff line number Diff line Loading @@ -138,6 +138,13 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ public static final int DISMISSED_REASON_CONTENT_VIEW_MORE_OPTIONS = 8; /** * Dialog dismissal due to the system being unable to retrieve a WindowManager instance required * to show the dialog. * @hide */ public static final int DISMISSED_REASON_ERROR_NO_WM = 9; /** * @hide */ Loading @@ -148,7 +155,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan DISMISSED_REASON_ERROR, DISMISSED_REASON_SERVER_REQUESTED, DISMISSED_REASON_CREDENTIAL_CONFIRMED, DISMISSED_REASON_CONTENT_VIEW_MORE_OPTIONS}) DISMISSED_REASON_CONTENT_VIEW_MORE_OPTIONS, DISMISSED_REASON_ERROR_NO_WM}) @Retention(RetentionPolicy.SOURCE) public @interface DismissedReason {} Loading packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java +127 −5 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.systemui.biometrics; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; import static android.view.Display.INVALID_DISPLAY; import static com.google.common.truth.Truth.assertThat; Loading Loading @@ -68,10 +69,12 @@ import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; import android.os.Handler; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.testing.TestableContext; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import android.view.Display; import android.view.DisplayInfo; import android.view.Surface; import android.view.WindowManager; Loading Loading @@ -210,6 +213,7 @@ public class AuthControllerTest extends SysuiTestCase { .thenReturn(true); when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) .thenReturn(true); when(mUserManager.isVisibleBackgroundUsersSupported()).thenReturn(false); when(mDialog1.getOpPackageName()).thenReturn("Dialog1"); when(mDialog2.getOpPackageName()).thenReturn("Dialog2"); Loading Loading @@ -462,7 +466,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testShowInvoked_whenSystemRequested() { showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); verify(mDialog1).show(any()); verify(mDialog1).show(mWindowManager); } @Test Loading Loading @@ -679,7 +683,7 @@ public class AuthControllerTest extends SysuiTestCase { // 2) Client cancels authentication showDialog(new int[0] /* sensorIds */, true /* credentialAllowed */); verify(mDialog1).show(any()); verify(mDialog1).show(mWindowManager); final byte[] credentialAttestation = generateRandomHAT(); Loading @@ -695,7 +699,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testShowNewDialog_beforeOldDialogDismissed_SkipsAnimations() { showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); verify(mDialog1).show(any()); verify(mDialog1).show(mWindowManager); showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); Loading @@ -703,7 +707,7 @@ public class AuthControllerTest extends SysuiTestCase { verify(mDialog1).dismissWithoutCallback(eq(false) /* animate */); // Second dialog should be shown without animation verify(mDialog2).show(any()); verify(mDialog2).show(mWindowManager); } @Test Loading Loading @@ -990,13 +994,97 @@ public class AuthControllerTest extends SysuiTestCase { verify(mDialog1, never()).show(any()); } @Test public void testShowDialog_visibleBackgroundUser() { int backgroundUserId = 1001; int backgroundDisplayId = 1001; when(mUserManager.isVisibleBackgroundUsersSupported()).thenReturn(true); WindowManager wm = mockBackgroundUser(backgroundUserId, backgroundDisplayId, true /* isVisible */, true /* hasUserManager */, true /* hasDisplay */); showDialog(new int[]{1} /* sensorIds */, backgroundUserId /* userId */, false /* credentialAllowed */); verify(mDialog1).show(wm); } @Test public void testShowDialog_invisibleBackgroundUser_defaultWM() { int backgroundUserId = 1001; when(mUserManager.isVisibleBackgroundUsersSupported()).thenReturn(true); mockBackgroundUser(backgroundUserId, INVALID_DISPLAY, false /* isVisible */, true /* hasUserManager */, true /* hasDisplay */); showDialog(new int[]{1} /* sensorIds */, backgroundUserId /* userId */, false /* credentialAllowed */); verify(mDialog1).show(mWindowManager); } @Test public void testShowDialog_visibleBackgroundUser_noUserManager_dismissError() throws RemoteException { int backgroundUserId = 1001; int backgroundDisplayId = 1001; when(mUserManager.isVisibleBackgroundUsersSupported()).thenReturn(true); mockBackgroundUser(backgroundUserId, backgroundDisplayId, true /* isVisible */, false /* hasUserManager */, true /* hasDisplay */); showDialog(new int[]{1} /* sensorIds */, backgroundUserId /* userId */, false /* credentialAllowed */); verify(mDialog1, never()).show(any()); verify(mReceiver).onDialogDismissed( eq(BiometricPrompt.DISMISSED_REASON_ERROR_NO_WM), eq(null) /* credentialAttestation */); } @Test public void testShowDialog_visibleBackgroundUser_invalidDisplayId_dismissError() throws RemoteException { int backgroundUserId = 1001; when(mUserManager.isVisibleBackgroundUsersSupported()).thenReturn(true); mockBackgroundUser(backgroundUserId, INVALID_DISPLAY, true /* isVisible */, true /* hasUserManager */, false /* hasDisplay */); showDialog(new int[]{1} /* sensorIds */, backgroundUserId /* userId */, false /* credentialAllowed */); verify(mDialog1, never()).show(any()); verify(mReceiver).onDialogDismissed( eq(BiometricPrompt.DISMISSED_REASON_ERROR_NO_WM), eq(null) /* credentialAttestation */); } @Test public void testShowDialog_visibleBackgroundUser_invalidDisplay_dismissError() throws RemoteException { int backgroundUserId = 1001; int backgroundDisplayId = 1001; when(mUserManager.isVisibleBackgroundUsersSupported()).thenReturn(true); mockBackgroundUser(backgroundUserId, backgroundDisplayId, true /* isVisible */, true /* hasUserManager */, false /* hasDisplay */); showDialog(new int[]{1} /* sensorIds */, backgroundUserId /* userId */, false /* credentialAllowed */); verify(mDialog1, never()).show(any()); verify(mReceiver).onDialogDismissed( eq(BiometricPrompt.DISMISSED_REASON_ERROR_NO_WM), eq(null) /* credentialAttestation */); } private void showDialog(int[] sensorIds, boolean credentialAllowed) { showDialog(sensorIds, 0 /* userId */, credentialAllowed); } private void showDialog(int[] sensorIds, int userId, boolean credentialAllowed) { mAuthController.showAuthenticationDialog(createTestPromptInfo(), mReceiver /* receiver */, sensorIds, credentialAllowed, true /* requireConfirmation */, 0 /* userId */, userId /* userId */, 0 /* operationId */, "testPackage", REQUEST_ID); Loading Loading @@ -1059,6 +1147,40 @@ public class AuthControllerTest extends SysuiTestCase { assertTrue(mAuthController.isFaceAuthEnrolled(userId)); } /** * Create mocks related to visible background users. * * @param userId the user id of the background user to mock * @param displayId display id of the background user * @param isVisible whether the background user is a visible background user or not * @param hasUserManager simulate whether the background user's context will return a mock * UserManager instance or null * @param hasDisplay simulate whether the background user's context will return a mock Display * instance or null * @return mock WindowManager instance associated with the background user's display context */ private WindowManager mockBackgroundUser(int userId, int displayId, boolean isVisible, boolean hasUserManager, boolean hasDisplay) { Context mockUserContext = mock(Context.class); Context mockDisplayContext = mock(Context.class); UserManager mockUserManager = mock(UserManager.class); Display mockDisplay = mock(Display.class); WindowManager mockDisplayWM = mock(WindowManager.class); doReturn(mockUserContext).when(mContextSpy).createContextAsUser(eq(UserHandle.of(userId)), anyInt()); if (hasUserManager) { when(mockUserContext.getSystemService(UserManager.class)).thenReturn(mockUserManager); } when(mockUserManager.isUserVisible()).thenReturn(isVisible); when(mockUserManager.getMainDisplayIdAssignedToUser()).thenReturn(displayId); if (hasDisplay) { when(mDisplayManager.getDisplay(displayId)).thenReturn(mockDisplay); } doReturn(mockDisplayContext).when(mContextSpy).createDisplayContext(mockDisplay); when(mockDisplayContext.getSystemService(WindowManager.class)).thenReturn(mockDisplayWM); return mockDisplayWM; } private final class TestableAuthController extends AuthController { private int mBuildCount = 0; Loading packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +45 −24 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.systemui.biometrics; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_REAR; import static android.view.Display.INVALID_DISPLAY; import static com.android.systemui.util.ConvenienceExtensionsKt.toKotlinLazy; Loading Loading @@ -54,6 +55,7 @@ import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback; import android.os.Handler; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.util.Log; import android.util.RotationUtils; Loading Loading @@ -211,9 +213,13 @@ public class AuthController implements } }; private void closeDialog(String reason) { private void closeDialog(String reasonString) { closeDialog(BiometricPrompt.DISMISSED_REASON_USER_CANCEL, reasonString); } private void closeDialog(@DismissedReason int reason, String reasonString) { if (isShowing()) { Log.i(TAG, "Close BP, reason :" + reason); Log.i(TAG, "Close BP, reason :" + reasonString); mCurrentDialog.dismissWithoutCallback(true /* animate */); mCurrentDialog = null; Loading @@ -223,8 +229,7 @@ public class AuthController implements try { if (mReceiver != null) { mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL, null /* credentialAttestation */); mReceiver.onDialogDismissed(reason, null /* credentialAttestation */); mReceiver = null; } } catch (RemoteException e) { Loading @@ -251,25 +256,7 @@ public class AuthController implements private void cancelIfOwnerIsNotInForeground() { mExecution.assertIsMainThread(); if (mCurrentDialog != null) { try { mCurrentDialog.dismissWithoutCallback(true /* animate */); mCurrentDialog = null; for (Callback cb : mCallbacks) { cb.onBiometricPromptDismissed(); } if (mReceiver != null) { mReceiver.onDialogDismissed( BiometricPrompt.DISMISSED_REASON_USER_CANCEL, null /* credentialAttestation */); mReceiver = null; } } catch (RemoteException e) { Log.e(TAG, "Remote exception", e); } } closeDialog("owner not in foreground"); } /** Loading Loading @@ -1271,8 +1258,42 @@ public class AuthController implements if (!promptInfo.isAllowBackgroundAuthentication() && isOwnerInBackground()) { cancelIfOwnerIsNotInForeground(); } else { mCurrentDialog.show(mWindowManager); WindowManager wm = getWindowManagerForUser(userId); if (wm != null) { mCurrentDialog.show(wm); } else { closeDialog(BiometricPrompt.DISMISSED_REASON_ERROR_NO_WM, "unable to get WM instance for user"); } } } @Nullable private WindowManager getWindowManagerForUser(int userId) { if (!mUserManager.isVisibleBackgroundUsersSupported()) { return mWindowManager; } UserManager um = mContext.createContextAsUser(UserHandle.of(userId), 0 /* flags */).getSystemService(UserManager.class); if (um == null) { Log.e(TAG, "unable to get UserManager for user=" + userId); return null; } if (!um.isUserVisible()) { // not visible user - use default window manager return mWindowManager; } int displayId = um.getMainDisplayIdAssignedToUser(); if (displayId == INVALID_DISPLAY) { Log.e(TAG, "unable to get display assigned to user=" + userId); return null; } Display display = mDisplayManager.getDisplay(displayId); if (display == null) { Log.e(TAG, "unable to get Display for user=" + userId); return null; } return mContext.createDisplayContext(display).getSystemService(WindowManager.class); } private void onDialogDismissed(@DismissedReason int reason) { Loading services/core/java/com/android/server/biometrics/AuthSession.java +8 −0 Original line number Diff line number Diff line Loading @@ -879,6 +879,14 @@ public final class AuthSession implements IBinder.DeathRecipient { ); break; case BiometricPrompt.DISMISSED_REASON_ERROR_NO_WM: mClientReceiver.onError( getEligibleModalities(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */ ); break; default: Slog.w(TAG, "Unhandled reason: " + reason); break; Loading Loading
core/java/android/hardware/biometrics/BiometricPrompt.java +9 −1 Original line number Diff line number Diff line Loading @@ -138,6 +138,13 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan */ public static final int DISMISSED_REASON_CONTENT_VIEW_MORE_OPTIONS = 8; /** * Dialog dismissal due to the system being unable to retrieve a WindowManager instance required * to show the dialog. * @hide */ public static final int DISMISSED_REASON_ERROR_NO_WM = 9; /** * @hide */ Loading @@ -148,7 +155,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan DISMISSED_REASON_ERROR, DISMISSED_REASON_SERVER_REQUESTED, DISMISSED_REASON_CREDENTIAL_CONFIRMED, DISMISSED_REASON_CONTENT_VIEW_MORE_OPTIONS}) DISMISSED_REASON_CONTENT_VIEW_MORE_OPTIONS, DISMISSED_REASON_ERROR_NO_WM}) @Retention(RetentionPolicy.SOURCE) public @interface DismissedReason {} Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java +127 −5 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.systemui.biometrics; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; import static android.view.Display.INVALID_DISPLAY; import static com.google.common.truth.Truth.assertThat; Loading Loading @@ -68,10 +69,12 @@ import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; import android.os.Handler; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.testing.TestableContext; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import android.view.Display; import android.view.DisplayInfo; import android.view.Surface; import android.view.WindowManager; Loading Loading @@ -210,6 +213,7 @@ public class AuthControllerTest extends SysuiTestCase { .thenReturn(true); when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) .thenReturn(true); when(mUserManager.isVisibleBackgroundUsersSupported()).thenReturn(false); when(mDialog1.getOpPackageName()).thenReturn("Dialog1"); when(mDialog2.getOpPackageName()).thenReturn("Dialog2"); Loading Loading @@ -462,7 +466,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testShowInvoked_whenSystemRequested() { showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); verify(mDialog1).show(any()); verify(mDialog1).show(mWindowManager); } @Test Loading Loading @@ -679,7 +683,7 @@ public class AuthControllerTest extends SysuiTestCase { // 2) Client cancels authentication showDialog(new int[0] /* sensorIds */, true /* credentialAllowed */); verify(mDialog1).show(any()); verify(mDialog1).show(mWindowManager); final byte[] credentialAttestation = generateRandomHAT(); Loading @@ -695,7 +699,7 @@ public class AuthControllerTest extends SysuiTestCase { @Test public void testShowNewDialog_beforeOldDialogDismissed_SkipsAnimations() { showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); verify(mDialog1).show(any()); verify(mDialog1).show(mWindowManager); showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); Loading @@ -703,7 +707,7 @@ public class AuthControllerTest extends SysuiTestCase { verify(mDialog1).dismissWithoutCallback(eq(false) /* animate */); // Second dialog should be shown without animation verify(mDialog2).show(any()); verify(mDialog2).show(mWindowManager); } @Test Loading Loading @@ -990,13 +994,97 @@ public class AuthControllerTest extends SysuiTestCase { verify(mDialog1, never()).show(any()); } @Test public void testShowDialog_visibleBackgroundUser() { int backgroundUserId = 1001; int backgroundDisplayId = 1001; when(mUserManager.isVisibleBackgroundUsersSupported()).thenReturn(true); WindowManager wm = mockBackgroundUser(backgroundUserId, backgroundDisplayId, true /* isVisible */, true /* hasUserManager */, true /* hasDisplay */); showDialog(new int[]{1} /* sensorIds */, backgroundUserId /* userId */, false /* credentialAllowed */); verify(mDialog1).show(wm); } @Test public void testShowDialog_invisibleBackgroundUser_defaultWM() { int backgroundUserId = 1001; when(mUserManager.isVisibleBackgroundUsersSupported()).thenReturn(true); mockBackgroundUser(backgroundUserId, INVALID_DISPLAY, false /* isVisible */, true /* hasUserManager */, true /* hasDisplay */); showDialog(new int[]{1} /* sensorIds */, backgroundUserId /* userId */, false /* credentialAllowed */); verify(mDialog1).show(mWindowManager); } @Test public void testShowDialog_visibleBackgroundUser_noUserManager_dismissError() throws RemoteException { int backgroundUserId = 1001; int backgroundDisplayId = 1001; when(mUserManager.isVisibleBackgroundUsersSupported()).thenReturn(true); mockBackgroundUser(backgroundUserId, backgroundDisplayId, true /* isVisible */, false /* hasUserManager */, true /* hasDisplay */); showDialog(new int[]{1} /* sensorIds */, backgroundUserId /* userId */, false /* credentialAllowed */); verify(mDialog1, never()).show(any()); verify(mReceiver).onDialogDismissed( eq(BiometricPrompt.DISMISSED_REASON_ERROR_NO_WM), eq(null) /* credentialAttestation */); } @Test public void testShowDialog_visibleBackgroundUser_invalidDisplayId_dismissError() throws RemoteException { int backgroundUserId = 1001; when(mUserManager.isVisibleBackgroundUsersSupported()).thenReturn(true); mockBackgroundUser(backgroundUserId, INVALID_DISPLAY, true /* isVisible */, true /* hasUserManager */, false /* hasDisplay */); showDialog(new int[]{1} /* sensorIds */, backgroundUserId /* userId */, false /* credentialAllowed */); verify(mDialog1, never()).show(any()); verify(mReceiver).onDialogDismissed( eq(BiometricPrompt.DISMISSED_REASON_ERROR_NO_WM), eq(null) /* credentialAttestation */); } @Test public void testShowDialog_visibleBackgroundUser_invalidDisplay_dismissError() throws RemoteException { int backgroundUserId = 1001; int backgroundDisplayId = 1001; when(mUserManager.isVisibleBackgroundUsersSupported()).thenReturn(true); mockBackgroundUser(backgroundUserId, backgroundDisplayId, true /* isVisible */, true /* hasUserManager */, false /* hasDisplay */); showDialog(new int[]{1} /* sensorIds */, backgroundUserId /* userId */, false /* credentialAllowed */); verify(mDialog1, never()).show(any()); verify(mReceiver).onDialogDismissed( eq(BiometricPrompt.DISMISSED_REASON_ERROR_NO_WM), eq(null) /* credentialAttestation */); } private void showDialog(int[] sensorIds, boolean credentialAllowed) { showDialog(sensorIds, 0 /* userId */, credentialAllowed); } private void showDialog(int[] sensorIds, int userId, boolean credentialAllowed) { mAuthController.showAuthenticationDialog(createTestPromptInfo(), mReceiver /* receiver */, sensorIds, credentialAllowed, true /* requireConfirmation */, 0 /* userId */, userId /* userId */, 0 /* operationId */, "testPackage", REQUEST_ID); Loading Loading @@ -1059,6 +1147,40 @@ public class AuthControllerTest extends SysuiTestCase { assertTrue(mAuthController.isFaceAuthEnrolled(userId)); } /** * Create mocks related to visible background users. * * @param userId the user id of the background user to mock * @param displayId display id of the background user * @param isVisible whether the background user is a visible background user or not * @param hasUserManager simulate whether the background user's context will return a mock * UserManager instance or null * @param hasDisplay simulate whether the background user's context will return a mock Display * instance or null * @return mock WindowManager instance associated with the background user's display context */ private WindowManager mockBackgroundUser(int userId, int displayId, boolean isVisible, boolean hasUserManager, boolean hasDisplay) { Context mockUserContext = mock(Context.class); Context mockDisplayContext = mock(Context.class); UserManager mockUserManager = mock(UserManager.class); Display mockDisplay = mock(Display.class); WindowManager mockDisplayWM = mock(WindowManager.class); doReturn(mockUserContext).when(mContextSpy).createContextAsUser(eq(UserHandle.of(userId)), anyInt()); if (hasUserManager) { when(mockUserContext.getSystemService(UserManager.class)).thenReturn(mockUserManager); } when(mockUserManager.isUserVisible()).thenReturn(isVisible); when(mockUserManager.getMainDisplayIdAssignedToUser()).thenReturn(displayId); if (hasDisplay) { when(mDisplayManager.getDisplay(displayId)).thenReturn(mockDisplay); } doReturn(mockDisplayContext).when(mContextSpy).createDisplayContext(mockDisplay); when(mockDisplayContext.getSystemService(WindowManager.class)).thenReturn(mockDisplayWM); return mockDisplayWM; } private final class TestableAuthController extends AuthController { private int mBuildCount = 0; Loading
packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +45 −24 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.systemui.biometrics; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_REAR; import static android.view.Display.INVALID_DISPLAY; import static com.android.systemui.util.ConvenienceExtensionsKt.toKotlinLazy; Loading Loading @@ -54,6 +55,7 @@ import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback; import android.os.Handler; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.util.Log; import android.util.RotationUtils; Loading Loading @@ -211,9 +213,13 @@ public class AuthController implements } }; private void closeDialog(String reason) { private void closeDialog(String reasonString) { closeDialog(BiometricPrompt.DISMISSED_REASON_USER_CANCEL, reasonString); } private void closeDialog(@DismissedReason int reason, String reasonString) { if (isShowing()) { Log.i(TAG, "Close BP, reason :" + reason); Log.i(TAG, "Close BP, reason :" + reasonString); mCurrentDialog.dismissWithoutCallback(true /* animate */); mCurrentDialog = null; Loading @@ -223,8 +229,7 @@ public class AuthController implements try { if (mReceiver != null) { mReceiver.onDialogDismissed(BiometricPrompt.DISMISSED_REASON_USER_CANCEL, null /* credentialAttestation */); mReceiver.onDialogDismissed(reason, null /* credentialAttestation */); mReceiver = null; } } catch (RemoteException e) { Loading @@ -251,25 +256,7 @@ public class AuthController implements private void cancelIfOwnerIsNotInForeground() { mExecution.assertIsMainThread(); if (mCurrentDialog != null) { try { mCurrentDialog.dismissWithoutCallback(true /* animate */); mCurrentDialog = null; for (Callback cb : mCallbacks) { cb.onBiometricPromptDismissed(); } if (mReceiver != null) { mReceiver.onDialogDismissed( BiometricPrompt.DISMISSED_REASON_USER_CANCEL, null /* credentialAttestation */); mReceiver = null; } } catch (RemoteException e) { Log.e(TAG, "Remote exception", e); } } closeDialog("owner not in foreground"); } /** Loading Loading @@ -1271,8 +1258,42 @@ public class AuthController implements if (!promptInfo.isAllowBackgroundAuthentication() && isOwnerInBackground()) { cancelIfOwnerIsNotInForeground(); } else { mCurrentDialog.show(mWindowManager); WindowManager wm = getWindowManagerForUser(userId); if (wm != null) { mCurrentDialog.show(wm); } else { closeDialog(BiometricPrompt.DISMISSED_REASON_ERROR_NO_WM, "unable to get WM instance for user"); } } } @Nullable private WindowManager getWindowManagerForUser(int userId) { if (!mUserManager.isVisibleBackgroundUsersSupported()) { return mWindowManager; } UserManager um = mContext.createContextAsUser(UserHandle.of(userId), 0 /* flags */).getSystemService(UserManager.class); if (um == null) { Log.e(TAG, "unable to get UserManager for user=" + userId); return null; } if (!um.isUserVisible()) { // not visible user - use default window manager return mWindowManager; } int displayId = um.getMainDisplayIdAssignedToUser(); if (displayId == INVALID_DISPLAY) { Log.e(TAG, "unable to get display assigned to user=" + userId); return null; } Display display = mDisplayManager.getDisplay(displayId); if (display == null) { Log.e(TAG, "unable to get Display for user=" + userId); return null; } return mContext.createDisplayContext(display).getSystemService(WindowManager.class); } private void onDialogDismissed(@DismissedReason int reason) { Loading
services/core/java/com/android/server/biometrics/AuthSession.java +8 −0 Original line number Diff line number Diff line Loading @@ -879,6 +879,14 @@ public final class AuthSession implements IBinder.DeathRecipient { ); break; case BiometricPrompt.DISMISSED_REASON_ERROR_NO_WM: mClientReceiver.onError( getEligibleModalities(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */ ); break; default: Slog.w(TAG, "Unhandled reason: " + reason); break; Loading