Loading packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +79 −56 Original line number Diff line number Diff line Loading @@ -49,7 +49,6 @@ import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback import android.hardware.fingerprint.IUdfpsHbmListener; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.RemoteException; import android.util.Log; import android.util.SparseBooleanArray; Loading @@ -65,6 +64,7 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.doze.DozeReceiver; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.util.concurrency.Execution; import java.util.ArrayList; import java.util.Arrays; Loading Loading @@ -92,15 +92,20 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, private static final boolean DEBUG = true; private static final int SENSOR_PRIVACY_DELAY = 500; private final Handler mHandler = new Handler(Looper.getMainLooper()); private final Handler mHandler; private final Execution mExecution; private final CommandQueue mCommandQueue; private final ActivityTaskManager mActivityTaskManager; @Nullable private final FingerprintManager mFingerprintManager; @Nullable private final FaceManager mFaceManager; @Nullable private final FingerprintManager mFingerprintManager; @Nullable private final FaceManager mFaceManager; private final Provider<UdfpsController> mUdfpsControllerFactory; private final Provider<SidefpsController> mSidefpsControllerFactory; @Nullable private final PointF mFaceAuthSensorLocation; @Nullable private PointF mFingerprintLocation; @Nullable private final PointF mFaceAuthSensorLocation; @Nullable private PointF mFingerprintLocation; private final Set<Callback> mCallbacks = new HashSet<>(); // TODO: These should just be saved from onSaveState Loading Loading @@ -133,62 +138,27 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, } } private final FingerprintStateListener mFingerprintStateListener = new FingerprintStateListener() { @Override public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) { Log.d(TAG, "onEnrollmentsChanged, userId: " + userId + ", sensorId: " + sensorId + ", hasEnrollments: " + hasEnrollments); for (FingerprintSensorPropertiesInternal prop : mUdfpsProps) { if (prop.sensorId == sensorId) { mUdfpsEnrolledForUser.put(userId, hasEnrollments); } } for (Callback cb : mCallbacks) { cb.onEnrollmentsChanged(); } } }; @NonNull private final IFingerprintAuthenticatorsRegisteredCallback mFingerprintAuthenticatorsRegisteredCallback = new IFingerprintAuthenticatorsRegisteredCallback.Stub() { @Override public void onAllAuthenticatorsRegistered( @Override public void onAllAuthenticatorsRegistered( List<FingerprintSensorPropertiesInternal> sensors) { if (DEBUG) { Log.d(TAG, "onFingerprintProvidersAvailable | sensors: " + Arrays.toString( sensors.toArray())); } mFpProps = sensors; List<FingerprintSensorPropertiesInternal> udfpsProps = new ArrayList<>(); List<FingerprintSensorPropertiesInternal> sidefpsProps = new ArrayList<>(); for (FingerprintSensorPropertiesInternal props : mFpProps) { if (props.isAnyUdfpsType()) { udfpsProps.add(props); } if (props.isAnySidefpsType()) { sidefpsProps.add(props); } } mUdfpsProps = !udfpsProps.isEmpty() ? udfpsProps : null; if (mUdfpsProps != null) { mUdfpsController = mUdfpsControllerFactory.get(); } mSidefpsProps = !sidefpsProps.isEmpty() ? sidefpsProps : null; if (mSidefpsProps != null) { mSidefpsController = mSidefpsControllerFactory.get(); mHandler.post(() -> handleAllAuthenticatorsRegistered(sensors)); } }; for (Callback cb : mCallbacks) { cb.onAllAuthenticatorsRegistered(); } private final FingerprintStateListener mFingerprintStateListener = new FingerprintStateListener() { @Override public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) { mHandler.post( () -> handleEnrollmentsChanged(userId, sensorId, hasEnrollments)); } }; @VisibleForTesting final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @VisibleForTesting final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (mCurrentDialog != null Loading @@ -212,6 +182,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, }; private void handleTaskStackChanged() { mExecution.assertIsMainThread(); if (mCurrentDialog != null) { try { final String clientPackage = mCurrentDialog.getOpPackageName(); Loading Loading @@ -241,6 +212,56 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, } } private void handleAllAuthenticatorsRegistered( List<FingerprintSensorPropertiesInternal> sensors) { mExecution.assertIsMainThread(); if (DEBUG) { Log.d(TAG, "handleAllAuthenticatorsRegistered | sensors: " + Arrays.toString( sensors.toArray())); } mFpProps = sensors; List<FingerprintSensorPropertiesInternal> udfpsProps = new ArrayList<>(); List<FingerprintSensorPropertiesInternal> sidefpsProps = new ArrayList<>(); for (FingerprintSensorPropertiesInternal props : mFpProps) { if (props.isAnyUdfpsType()) { udfpsProps.add(props); } if (props.isAnySidefpsType()) { sidefpsProps.add(props); } } mUdfpsProps = !udfpsProps.isEmpty() ? udfpsProps : null; if (mUdfpsProps != null) { mUdfpsController = mUdfpsControllerFactory.get(); } mSidefpsProps = !sidefpsProps.isEmpty() ? sidefpsProps : null; if (mSidefpsProps != null) { mSidefpsController = mSidefpsControllerFactory.get(); } for (Callback cb : mCallbacks) { cb.onAllAuthenticatorsRegistered(); } mFingerprintManager.registerFingerprintStateListener(mFingerprintStateListener); } private void handleEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) { mExecution.assertIsMainThread(); Log.d(TAG, "handleEnrollmentsChanged, userId: " + userId + ", sensorId: " + sensorId + ", hasEnrollments: " + hasEnrollments); if (mUdfpsProps == null) { Log.d(TAG, "handleEnrollmentsChanged, mUdfpsProps is null"); } else { for (FingerprintSensorPropertiesInternal prop : mUdfpsProps) { if (prop.sensorId == sensorId) { mUdfpsEnrolledForUser.put(userId, hasEnrollments); } } } for (Callback cb : mCallbacks) { cb.onEnrollmentsChanged(); } } /** * Adds a callback. See {@link Callback}. */ Loading Loading @@ -449,6 +470,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, @Inject public AuthController(Context context, Execution execution, CommandQueue commandQueue, ActivityTaskManager activityTaskManager, @NonNull WindowManager windowManager, Loading @@ -459,6 +481,8 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, @NonNull DisplayManager displayManager, @Main Handler handler) { super(context); mExecution = execution; mHandler = handler; mCommandQueue = commandQueue; mActivityTaskManager = activityTaskManager; mFingerprintManager = fingerprintManager; Loading @@ -470,7 +494,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, mOrientationListener = new BiometricDisplayListener( context, displayManager, handler, mHandler, BiometricDisplayListener.SensorType.Generic.INSTANCE, () -> { onOrientationChanged(); Loading Loading @@ -521,7 +545,6 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, if (mFingerprintManager != null) { mFingerprintManager.addAuthenticatorsRegisteredCallback( mFingerprintAuthenticatorsRegisteredCallback); mFingerprintManager.registerFingerprintStateListener(mFingerprintStateListener); } mTaskStackListener = new BiometricTaskStackListener(); Loading packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java +79 −9 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; Loading @@ -53,12 +54,14 @@ import android.hardware.face.FaceManager; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorProperties; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.FingerprintStateListener; import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; import android.os.Bundle; import android.os.Handler; import android.os.RemoteException; import android.testing.AndroidTestingRunner; import android.testing.TestableContext; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import android.view.WindowManager; Loading @@ -67,6 +70,8 @@ import androidx.test.filters.SmallTest; import com.android.internal.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.util.concurrency.Execution; import com.android.systemui.util.concurrency.FakeExecution; import org.junit.Before; import org.junit.Test; Loading Loading @@ -112,20 +117,27 @@ public class AuthControllerTest extends SysuiTestCase { private SidefpsController mSidefpsController; @Mock private DisplayManager mDisplayManager; @Mock private Handler mHandler; @Captor ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback> mAuthenticatorsRegisteredCaptor; @Captor ArgumentCaptor<FingerprintStateListener> mFingerprintStateCaptor; private TestableContext mContextSpy; private Execution mExecution; private TestableLooper mTestableLooper; private Handler mHandler; private TestableAuthController mAuthController; @Before public void setup() throws RemoteException { MockitoAnnotations.initMocks(this); TestableContext context = spy(mContext); mContextSpy = spy(mContext); mExecution = new FakeExecution(); mTestableLooper = TestableLooper.get(this); mHandler = new Handler(mTestableLooper.getLooper()); when(context.getPackageManager()).thenReturn(mPackageManager); when(mContextSpy.getPackageManager()).thenReturn(mPackageManager); when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)) .thenReturn(true); when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) Loading Loading @@ -158,18 +170,75 @@ public class AuthControllerTest extends SysuiTestCase { props.add(prop); when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(props); mAuthController = new TestableAuthController(context, mCommandQueue, mAuthController = new TestableAuthController(mContextSpy, mExecution, mCommandQueue, mActivityTaskManager, mWindowManager, mFingerprintManager, mFaceManager, () -> mUdfpsController, () -> mSidefpsController); mAuthController.start(); verify(mFingerprintManager).addAuthenticatorsRegisteredCallback( mAuthenticatorsRegisteredCaptor.capture()); mAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(props); // Ensures that the operations posted on the handler get executed. mTestableLooper.processAllMessages(); } // Callback tests @Test public void testRegistersFingerprintStateListener_afterAllAuthenticatorsAreRegistered() throws RemoteException { // This test is sensitive to prior FingerprintManager interactions. reset(mFingerprintManager); // This test requires an uninitialized AuthController. AuthController authController = new TestableAuthController(mContextSpy, mExecution, mCommandQueue, mActivityTaskManager, mWindowManager, mFingerprintManager, mFaceManager, () -> mUdfpsController, () -> mSidefpsController); authController.start(); verify(mFingerprintManager).addAuthenticatorsRegisteredCallback( mAuthenticatorsRegisteredCaptor.capture()); mTestableLooper.processAllMessages(); verify(mFingerprintManager, never()).registerFingerprintStateListener(any()); mAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(new ArrayList<>()); mTestableLooper.processAllMessages(); verify(mFingerprintManager).registerFingerprintStateListener(any()); } @Test public void testDoesNotCrash_afterEnrollmentsChangedForUnknownSensor() throws RemoteException { // This test is sensitive to prior FingerprintManager interactions. reset(mFingerprintManager); // This test requires an uninitialized AuthController. AuthController authController = new TestableAuthController(mContextSpy, mExecution, mCommandQueue, mActivityTaskManager, mWindowManager, mFingerprintManager, mFaceManager, () -> mUdfpsController, () -> mSidefpsController); authController.start(); verify(mFingerprintManager).addAuthenticatorsRegisteredCallback( mAuthenticatorsRegisteredCaptor.capture()); // Emulates a device with no authenticators (empty list). mAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(new ArrayList<>()); mTestableLooper.processAllMessages(); verify(mFingerprintManager).registerFingerprintStateListener( mFingerprintStateCaptor.capture()); // Enrollments changed for an unknown sensor. mFingerprintStateCaptor.getValue().onEnrollmentsChanged(0 /* userId */, 0xbeef /* sensorId */, true /* hasEnrollments */); mTestableLooper.processAllMessages(); // Nothing should crash. } @Test public void testSendsReasonUserCanceled_whenDismissedByUserCancel() throws Exception { showDialog(new int[]{1} /* sensorIds */, false /* credentialAllowed */); Loading Loading @@ -497,7 +566,7 @@ public class AuthControllerTest extends SysuiTestCase { when(mActivityTaskManager.getTasks(anyInt())).thenReturn(tasks); mAuthController.mTaskStackListener.onTaskStackChanged(); waitForIdleSync(); mTestableLooper.processAllMessages(); assertNull(mAuthController.mCurrentDialog); assertNull(mAuthController.mReceiver); Loading Loading @@ -528,7 +597,7 @@ public class AuthControllerTest extends SysuiTestCase { showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); mAuthController.mBroadcastReceiver.onReceive(mContext, intent); waitForIdleSync(); mTestableLooper.processAllMessages(); assertNull(mAuthController.mCurrentDialog); assertNull(mAuthController.mReceiver); Loading Loading @@ -598,6 +667,7 @@ public class AuthControllerTest extends SysuiTestCase { private PromptInfo mLastBiometricPromptInfo; TestableAuthController(Context context, Execution execution, CommandQueue commandQueue, ActivityTaskManager activityTaskManager, WindowManager windowManager, Loading @@ -605,7 +675,7 @@ public class AuthControllerTest extends SysuiTestCase { FaceManager faceManager, Provider<UdfpsController> udfpsControllerFactory, Provider<SidefpsController> sidefpsControllerFactory) { super(context, commandQueue, activityTaskManager, windowManager, super(context, execution, commandQueue, activityTaskManager, windowManager, fingerprintManager, faceManager, udfpsControllerFactory, sidefpsControllerFactory, mDisplayManager, mHandler); } Loading Loading
packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +79 −56 Original line number Diff line number Diff line Loading @@ -49,7 +49,6 @@ import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback import android.hardware.fingerprint.IUdfpsHbmListener; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.RemoteException; import android.util.Log; import android.util.SparseBooleanArray; Loading @@ -65,6 +64,7 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.doze.DozeReceiver; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.util.concurrency.Execution; import java.util.ArrayList; import java.util.Arrays; Loading Loading @@ -92,15 +92,20 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, private static final boolean DEBUG = true; private static final int SENSOR_PRIVACY_DELAY = 500; private final Handler mHandler = new Handler(Looper.getMainLooper()); private final Handler mHandler; private final Execution mExecution; private final CommandQueue mCommandQueue; private final ActivityTaskManager mActivityTaskManager; @Nullable private final FingerprintManager mFingerprintManager; @Nullable private final FaceManager mFaceManager; @Nullable private final FingerprintManager mFingerprintManager; @Nullable private final FaceManager mFaceManager; private final Provider<UdfpsController> mUdfpsControllerFactory; private final Provider<SidefpsController> mSidefpsControllerFactory; @Nullable private final PointF mFaceAuthSensorLocation; @Nullable private PointF mFingerprintLocation; @Nullable private final PointF mFaceAuthSensorLocation; @Nullable private PointF mFingerprintLocation; private final Set<Callback> mCallbacks = new HashSet<>(); // TODO: These should just be saved from onSaveState Loading Loading @@ -133,62 +138,27 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, } } private final FingerprintStateListener mFingerprintStateListener = new FingerprintStateListener() { @Override public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) { Log.d(TAG, "onEnrollmentsChanged, userId: " + userId + ", sensorId: " + sensorId + ", hasEnrollments: " + hasEnrollments); for (FingerprintSensorPropertiesInternal prop : mUdfpsProps) { if (prop.sensorId == sensorId) { mUdfpsEnrolledForUser.put(userId, hasEnrollments); } } for (Callback cb : mCallbacks) { cb.onEnrollmentsChanged(); } } }; @NonNull private final IFingerprintAuthenticatorsRegisteredCallback mFingerprintAuthenticatorsRegisteredCallback = new IFingerprintAuthenticatorsRegisteredCallback.Stub() { @Override public void onAllAuthenticatorsRegistered( @Override public void onAllAuthenticatorsRegistered( List<FingerprintSensorPropertiesInternal> sensors) { if (DEBUG) { Log.d(TAG, "onFingerprintProvidersAvailable | sensors: " + Arrays.toString( sensors.toArray())); } mFpProps = sensors; List<FingerprintSensorPropertiesInternal> udfpsProps = new ArrayList<>(); List<FingerprintSensorPropertiesInternal> sidefpsProps = new ArrayList<>(); for (FingerprintSensorPropertiesInternal props : mFpProps) { if (props.isAnyUdfpsType()) { udfpsProps.add(props); } if (props.isAnySidefpsType()) { sidefpsProps.add(props); } } mUdfpsProps = !udfpsProps.isEmpty() ? udfpsProps : null; if (mUdfpsProps != null) { mUdfpsController = mUdfpsControllerFactory.get(); } mSidefpsProps = !sidefpsProps.isEmpty() ? sidefpsProps : null; if (mSidefpsProps != null) { mSidefpsController = mSidefpsControllerFactory.get(); mHandler.post(() -> handleAllAuthenticatorsRegistered(sensors)); } }; for (Callback cb : mCallbacks) { cb.onAllAuthenticatorsRegistered(); } private final FingerprintStateListener mFingerprintStateListener = new FingerprintStateListener() { @Override public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) { mHandler.post( () -> handleEnrollmentsChanged(userId, sensorId, hasEnrollments)); } }; @VisibleForTesting final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @VisibleForTesting final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (mCurrentDialog != null Loading @@ -212,6 +182,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, }; private void handleTaskStackChanged() { mExecution.assertIsMainThread(); if (mCurrentDialog != null) { try { final String clientPackage = mCurrentDialog.getOpPackageName(); Loading Loading @@ -241,6 +212,56 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, } } private void handleAllAuthenticatorsRegistered( List<FingerprintSensorPropertiesInternal> sensors) { mExecution.assertIsMainThread(); if (DEBUG) { Log.d(TAG, "handleAllAuthenticatorsRegistered | sensors: " + Arrays.toString( sensors.toArray())); } mFpProps = sensors; List<FingerprintSensorPropertiesInternal> udfpsProps = new ArrayList<>(); List<FingerprintSensorPropertiesInternal> sidefpsProps = new ArrayList<>(); for (FingerprintSensorPropertiesInternal props : mFpProps) { if (props.isAnyUdfpsType()) { udfpsProps.add(props); } if (props.isAnySidefpsType()) { sidefpsProps.add(props); } } mUdfpsProps = !udfpsProps.isEmpty() ? udfpsProps : null; if (mUdfpsProps != null) { mUdfpsController = mUdfpsControllerFactory.get(); } mSidefpsProps = !sidefpsProps.isEmpty() ? sidefpsProps : null; if (mSidefpsProps != null) { mSidefpsController = mSidefpsControllerFactory.get(); } for (Callback cb : mCallbacks) { cb.onAllAuthenticatorsRegistered(); } mFingerprintManager.registerFingerprintStateListener(mFingerprintStateListener); } private void handleEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) { mExecution.assertIsMainThread(); Log.d(TAG, "handleEnrollmentsChanged, userId: " + userId + ", sensorId: " + sensorId + ", hasEnrollments: " + hasEnrollments); if (mUdfpsProps == null) { Log.d(TAG, "handleEnrollmentsChanged, mUdfpsProps is null"); } else { for (FingerprintSensorPropertiesInternal prop : mUdfpsProps) { if (prop.sensorId == sensorId) { mUdfpsEnrolledForUser.put(userId, hasEnrollments); } } } for (Callback cb : mCallbacks) { cb.onEnrollmentsChanged(); } } /** * Adds a callback. See {@link Callback}. */ Loading Loading @@ -449,6 +470,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, @Inject public AuthController(Context context, Execution execution, CommandQueue commandQueue, ActivityTaskManager activityTaskManager, @NonNull WindowManager windowManager, Loading @@ -459,6 +481,8 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, @NonNull DisplayManager displayManager, @Main Handler handler) { super(context); mExecution = execution; mHandler = handler; mCommandQueue = commandQueue; mActivityTaskManager = activityTaskManager; mFingerprintManager = fingerprintManager; Loading @@ -470,7 +494,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, mOrientationListener = new BiometricDisplayListener( context, displayManager, handler, mHandler, BiometricDisplayListener.SensorType.Generic.INSTANCE, () -> { onOrientationChanged(); Loading Loading @@ -521,7 +545,6 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, if (mFingerprintManager != null) { mFingerprintManager.addAuthenticatorsRegisteredCallback( mFingerprintAuthenticatorsRegisteredCallback); mFingerprintManager.registerFingerprintStateListener(mFingerprintStateListener); } mTaskStackListener = new BiometricTaskStackListener(); Loading
packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java +79 −9 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; Loading @@ -53,12 +54,14 @@ import android.hardware.face.FaceManager; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorProperties; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.FingerprintStateListener; import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; import android.os.Bundle; import android.os.Handler; import android.os.RemoteException; import android.testing.AndroidTestingRunner; import android.testing.TestableContext; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import android.view.WindowManager; Loading @@ -67,6 +70,8 @@ import androidx.test.filters.SmallTest; import com.android.internal.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.util.concurrency.Execution; import com.android.systemui.util.concurrency.FakeExecution; import org.junit.Before; import org.junit.Test; Loading Loading @@ -112,20 +117,27 @@ public class AuthControllerTest extends SysuiTestCase { private SidefpsController mSidefpsController; @Mock private DisplayManager mDisplayManager; @Mock private Handler mHandler; @Captor ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback> mAuthenticatorsRegisteredCaptor; @Captor ArgumentCaptor<FingerprintStateListener> mFingerprintStateCaptor; private TestableContext mContextSpy; private Execution mExecution; private TestableLooper mTestableLooper; private Handler mHandler; private TestableAuthController mAuthController; @Before public void setup() throws RemoteException { MockitoAnnotations.initMocks(this); TestableContext context = spy(mContext); mContextSpy = spy(mContext); mExecution = new FakeExecution(); mTestableLooper = TestableLooper.get(this); mHandler = new Handler(mTestableLooper.getLooper()); when(context.getPackageManager()).thenReturn(mPackageManager); when(mContextSpy.getPackageManager()).thenReturn(mPackageManager); when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)) .thenReturn(true); when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) Loading Loading @@ -158,18 +170,75 @@ public class AuthControllerTest extends SysuiTestCase { props.add(prop); when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(props); mAuthController = new TestableAuthController(context, mCommandQueue, mAuthController = new TestableAuthController(mContextSpy, mExecution, mCommandQueue, mActivityTaskManager, mWindowManager, mFingerprintManager, mFaceManager, () -> mUdfpsController, () -> mSidefpsController); mAuthController.start(); verify(mFingerprintManager).addAuthenticatorsRegisteredCallback( mAuthenticatorsRegisteredCaptor.capture()); mAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(props); // Ensures that the operations posted on the handler get executed. mTestableLooper.processAllMessages(); } // Callback tests @Test public void testRegistersFingerprintStateListener_afterAllAuthenticatorsAreRegistered() throws RemoteException { // This test is sensitive to prior FingerprintManager interactions. reset(mFingerprintManager); // This test requires an uninitialized AuthController. AuthController authController = new TestableAuthController(mContextSpy, mExecution, mCommandQueue, mActivityTaskManager, mWindowManager, mFingerprintManager, mFaceManager, () -> mUdfpsController, () -> mSidefpsController); authController.start(); verify(mFingerprintManager).addAuthenticatorsRegisteredCallback( mAuthenticatorsRegisteredCaptor.capture()); mTestableLooper.processAllMessages(); verify(mFingerprintManager, never()).registerFingerprintStateListener(any()); mAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(new ArrayList<>()); mTestableLooper.processAllMessages(); verify(mFingerprintManager).registerFingerprintStateListener(any()); } @Test public void testDoesNotCrash_afterEnrollmentsChangedForUnknownSensor() throws RemoteException { // This test is sensitive to prior FingerprintManager interactions. reset(mFingerprintManager); // This test requires an uninitialized AuthController. AuthController authController = new TestableAuthController(mContextSpy, mExecution, mCommandQueue, mActivityTaskManager, mWindowManager, mFingerprintManager, mFaceManager, () -> mUdfpsController, () -> mSidefpsController); authController.start(); verify(mFingerprintManager).addAuthenticatorsRegisteredCallback( mAuthenticatorsRegisteredCaptor.capture()); // Emulates a device with no authenticators (empty list). mAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(new ArrayList<>()); mTestableLooper.processAllMessages(); verify(mFingerprintManager).registerFingerprintStateListener( mFingerprintStateCaptor.capture()); // Enrollments changed for an unknown sensor. mFingerprintStateCaptor.getValue().onEnrollmentsChanged(0 /* userId */, 0xbeef /* sensorId */, true /* hasEnrollments */); mTestableLooper.processAllMessages(); // Nothing should crash. } @Test public void testSendsReasonUserCanceled_whenDismissedByUserCancel() throws Exception { showDialog(new int[]{1} /* sensorIds */, false /* credentialAllowed */); Loading Loading @@ -497,7 +566,7 @@ public class AuthControllerTest extends SysuiTestCase { when(mActivityTaskManager.getTasks(anyInt())).thenReturn(tasks); mAuthController.mTaskStackListener.onTaskStackChanged(); waitForIdleSync(); mTestableLooper.processAllMessages(); assertNull(mAuthController.mCurrentDialog); assertNull(mAuthController.mReceiver); Loading Loading @@ -528,7 +597,7 @@ public class AuthControllerTest extends SysuiTestCase { showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */); Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); mAuthController.mBroadcastReceiver.onReceive(mContext, intent); waitForIdleSync(); mTestableLooper.processAllMessages(); assertNull(mAuthController.mCurrentDialog); assertNull(mAuthController.mReceiver); Loading Loading @@ -598,6 +667,7 @@ public class AuthControllerTest extends SysuiTestCase { private PromptInfo mLastBiometricPromptInfo; TestableAuthController(Context context, Execution execution, CommandQueue commandQueue, ActivityTaskManager activityTaskManager, WindowManager windowManager, Loading @@ -605,7 +675,7 @@ public class AuthControllerTest extends SysuiTestCase { FaceManager faceManager, Provider<UdfpsController> udfpsControllerFactory, Provider<SidefpsController> sidefpsControllerFactory) { super(context, commandQueue, activityTaskManager, windowManager, super(context, execution, commandQueue, activityTaskManager, windowManager, fingerprintManager, faceManager, udfpsControllerFactory, sidefpsControllerFactory, mDisplayManager, mHandler); } Loading