Converted Biometric tests to Robolectric tests

Added TestWithLooperRule to replace AndroidTestingRunner.
Converted some tests to run in parallel as Robolectric tests.

Bug: 267340313
Fix: 269478124
Test: atest SystemUiRoboTests
      atest SystemUITests
Change-Id: Ib2e1edfee4ecb45501f5cc42f1b63c9326d2faa4
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index ac75cc8..f8fdb95 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -258,6 +258,24 @@
         "tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDreamingTransitionViewModelTest.kt",
         "tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToOccludedTransitionViewModelTest.kt",
         "tests/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToLockscreenTransitionViewModelTest.kt",
+
+        // Biometric
+        "tests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt",
+        "tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt",
+        "tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt",
+        "tests/src/com/android/systemui/biometrics/AuthControllerTest.java",
+        "tests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java",
+        "tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt",
+        "tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt",
+        "tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt",
+        "tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java",
+        "tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java",
+        "tests/src/com/android/systemui/biometrics/UdfpsDisplayModeTest.java",
+        "tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerBaseTest.java",
+        "tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java",
+        "tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt",
+        "tests/src/com/android/systemui/biometrics/UdfpsShellTest.kt",
+        "tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt",
     ],
     path: "tests/src",
 }
@@ -402,6 +420,10 @@
     privileged: true,
     resource_dirs: [],
     kotlincflags: ["-Xjvm-default=all"],
+    optimize: {
+        shrink_resources: false,
+        proguard_flags_files: ["proguard.flags"],
+    },
 
     plugins: ["dagger2-compiler"],
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
index eb5d23a..4319f01 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
@@ -144,8 +144,7 @@
                 orientationListener.enable()
             }
         }
-    @VisibleForTesting
-    internal var overlayOffsets: SensorLocationInternal = SensorLocationInternal.DEFAULT
+    @VisibleForTesting var overlayOffsets: SensorLocationInternal = SensorLocationInternal.DEFAULT
 
     private val overlayViewParams =
         WindowManager.LayoutParams(
@@ -297,7 +296,7 @@
     }
 
     @VisibleForTesting
-    internal fun updateOverlayParams(display: Display, bounds: Rect) {
+    fun updateOverlayParams(display: Display, bounds: Rect) {
         val isNaturalOrientation = display.isNaturalOrientation()
         val isDefaultOrientation =
             if (isReverseDefaultRotation) !isNaturalOrientation else isNaturalOrientation
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
index 3e7d81a..c7f4164 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.kt
@@ -254,7 +254,7 @@
     }
 
     @VisibleForTesting
-    internal suspend fun listenForBouncerExpansion(scope: CoroutineScope): Job {
+    suspend fun listenForBouncerExpansion(scope: CoroutineScope): Job {
         return scope.launch {
             primaryBouncerInteractor.bouncerExpansion.collect { bouncerExpansion: Float ->
                 inputBouncerExpansion = bouncerExpansion
@@ -265,7 +265,7 @@
     }
 
     @VisibleForTesting
-    internal suspend fun listenForAlternateBouncerVisibility(scope: CoroutineScope): Job {
+    suspend fun listenForAlternateBouncerVisibility(scope: CoroutineScope): Job {
         return scope.launch {
             alternateBouncerInteractor.isVisible.collect { isVisible: Boolean ->
                 showUdfpsBouncer(isVisible)
diff --git a/packages/SystemUI/tests/robolectric/config/robolectric.properties b/packages/SystemUI/tests/robolectric/config/robolectric.properties
index 2a75bd9..438d54c 100644
--- a/packages/SystemUI/tests/robolectric/config/robolectric.properties
+++ b/packages/SystemUI/tests/robolectric/config/robolectric.properties
@@ -13,4 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-sdk=NEWEST_SDK
\ No newline at end of file
+sdk=NEWEST_SDK
+shadows=\
+  com.android.systemui.testutils.shadow.ShadowLockPatternUtils \
+  com.android.systemui.testutils.shadow.ShadowTestableLooper
\ No newline at end of file
diff --git a/packages/SystemUI/tests/robolectric/src/com/android/systemui/testutils/shadow/ShadowLockPatternUtils.java b/packages/SystemUI/tests/robolectric/src/com/android/systemui/testutils/shadow/ShadowLockPatternUtils.java
new file mode 100644
index 0000000..b248ce3
--- /dev/null
+++ b/packages/SystemUI/tests/robolectric/src/com/android/systemui/testutils/shadow/ShadowLockPatternUtils.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 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.systemui.testutils.shadow;
+
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
+
+import com.android.internal.widget.LockPatternUtils;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+@Implements(LockPatternUtils.class)
+public class ShadowLockPatternUtils {
+
+    @Implementation
+    protected int getCredentialTypeForUser(int userHandle) {
+        return CREDENTIAL_TYPE_NONE;
+    }
+}
diff --git a/packages/SystemUI/tests/robolectric/src/com/android/systemui/testutils/shadow/ShadowTestableLooper.java b/packages/SystemUI/tests/robolectric/src/com/android/systemui/testutils/shadow/ShadowTestableLooper.java
new file mode 100644
index 0000000..a9b8bc0
--- /dev/null
+++ b/packages/SystemUI/tests/robolectric/src/com/android/systemui/testutils/shadow/ShadowTestableLooper.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2023 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.systemui.testutils.shadow;
+
+import static org.robolectric.Shadows.shadowOf;
+
+import android.testing.TestableLooper;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.RealObject;
+
+@Implements(TestableLooper.class)
+public class ShadowTestableLooper {
+    @RealObject private TestableLooper mRealTestableLooper;
+    /**
+     * Process messages in the queue until no more are found.
+     */
+    @Implementation
+    protected void processAllMessages() {
+        shadowOf(mRealTestableLooper.getLooper()).idle();
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt
index 58d9069..dd87f6e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt
@@ -18,10 +18,10 @@
 
 import android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE
 import android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.testing.TestableLooper.RunWithLooper
 import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
@@ -36,7 +36,8 @@
 import org.mockito.Mockito.verify
 import org.mockito.junit.MockitoJUnit
 
-@RunWith(AndroidTestingRunner::class)
+
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper(setAsMainLooper = true)
 @SmallTest
 class AuthBiometricFingerprintAndFaceViewTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt
index bce98cf..9f789e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt
@@ -17,7 +17,7 @@
 
 import android.hardware.biometrics.BiometricAuthenticator
 import android.os.Bundle
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import android.testing.TestableLooper
 import android.testing.TestableLooper.RunWithLooper
 import android.view.View
@@ -37,7 +37,7 @@
 import org.mockito.Mockito.verify
 import org.mockito.junit.MockitoJUnit
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper(setAsMainLooper = true)
 @SmallTest
 class AuthBiometricFingerprintViewTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index b4696e4..fec1831 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -25,7 +25,6 @@
 import android.os.Handler
 import android.os.IBinder
 import android.os.UserManager
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.testing.TestableLooper.RunWithLooper
 import android.testing.ViewUtils
@@ -34,6 +33,7 @@
 import android.view.WindowInsets
 import android.view.WindowManager
 import android.widget.ScrollView
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.internal.widget.LockPatternUtils
@@ -62,7 +62,7 @@
 import org.mockito.Mockito.`when` as whenever
 import org.mockito.junit.MockitoJUnit
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper(setAsMainLooper = true)
 @SmallTest
 class AuthContainerViewTest : SysuiTestCase() {
@@ -489,7 +489,7 @@
     private fun AuthContainerView.addToView() {
         ViewUtils.attachView(this)
         waitForIdleSync()
-        assertThat(isAttachedToWindow).isTrue()
+        assertThat(isAttachedToWindow()).isTrue()
     }
 }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index c068efb..0f20ace 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -75,7 +75,6 @@
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.UserManager;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableContext;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
@@ -83,6 +82,7 @@
 import android.view.Surface;
 import android.view.WindowManager;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.R;
@@ -117,7 +117,7 @@
 import java.util.List;
 import java.util.Random;
 
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @RunWithLooper
 @SmallTest
 public class AuthControllerTest extends SysuiTestCase {
@@ -265,7 +265,7 @@
         mFaceAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(faceProps);
 
         // Ensures that the operations posted on the handler get executed.
-        mTestableLooper.processAllMessages();
+        waitForIdleSync();
     }
 
     // Callback tests
@@ -285,14 +285,14 @@
                 mFpAuthenticatorsRegisteredCaptor.capture());
         verify(mFaceManager).addAuthenticatorsRegisteredCallback(
                 mFaceAuthenticatorsRegisteredCaptor.capture());
-        mTestableLooper.processAllMessages();
+        waitForIdleSync();
 
         verify(mFingerprintManager, never()).registerBiometricStateListener(any());
         verify(mFaceManager, never()).registerBiometricStateListener(any());
 
         mFpAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(List.of());
         mFaceAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(List.of());
-        mTestableLooper.processAllMessages();
+        waitForIdleSync();
 
         verify(mFingerprintManager).registerBiometricStateListener(any());
         verify(mFaceManager).registerBiometricStateListener(any());
@@ -316,7 +316,7 @@
         // Emulates a device with no authenticators (empty list).
         mFpAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(List.of());
         mFaceAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(List.of());
-        mTestableLooper.processAllMessages();
+        waitForIdleSync();
 
         verify(mFingerprintManager).registerBiometricStateListener(
                 mBiometricStateCaptor.capture());
@@ -328,7 +328,7 @@
             listener.onEnrollmentsChanged(0 /* userId */,
                     0xbeef /* sensorId */, true /* hasEnrollments */);
         }
-        mTestableLooper.processAllMessages();
+        waitForIdleSync();
 
         // Nothing should crash.
     }
@@ -692,7 +692,7 @@
         switchTask("other_package");
         showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
 
-        mTestableLooper.processAllMessages();
+        waitForIdleSync();
 
         assertNull(mAuthController.mCurrentDialog);
         assertNull(mAuthController.mReceiver);
@@ -709,7 +709,7 @@
         switchTask("other_package");
 
         mAuthController.mTaskStackListener.onTaskStackChanged();
-        mTestableLooper.processAllMessages();
+        waitForIdleSync();
 
         assertNull(mAuthController.mCurrentDialog);
         assertNull(mAuthController.mReceiver);
@@ -742,7 +742,7 @@
         showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
         Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
         mAuthController.mBroadcastReceiver.onReceive(mContext, intent);
-        mTestableLooper.processAllMessages();
+        waitForIdleSync();
 
         assertNull(mAuthController.mCurrentDialog);
         assertNull(mAuthController.mReceiver);
@@ -1021,4 +1021,9 @@
             return dialog;
         }
     }
+
+    @Override
+    protected void waitForIdleSync() {
+        mTestableLooper.processAllMessages();
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java
index 69c7f36..24a13a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java
@@ -32,17 +32,20 @@
 import android.content.Context;
 import android.hardware.display.DisplayManager;
 import android.os.Handler;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 import android.view.Display;
 import android.view.Surface;
 import android.view.Surface.Rotation;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
 
+import kotlin.Unit;
+import kotlin.jvm.functions.Function0;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -51,11 +54,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-import kotlin.Unit;
-import kotlin.jvm.functions.Function0;
-
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @RunWithLooper(setAsMainLooper = true)
 public class BiometricDisplayListenerTest extends SysuiTestCase {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt
index c9ccdb3..88b6c39 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.biometrics
 
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.keyguard.logging.BiometricMessageDeferralLogger
 import com.android.systemui.SysuiTestCase
@@ -33,7 +33,7 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 class FaceHelpMessageDeferralTest : SysuiTestCase() {
     val threshold = .75f
     @Mock lateinit var logger: BiometricMessageDeferralLogger
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
index 33345b5..c554af6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
@@ -34,7 +34,6 @@
 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
 import android.hardware.fingerprint.ISidefpsController
 import android.os.Handler
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.view.Display
 import android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS
@@ -49,6 +48,7 @@
 import android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY
 import android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG
 import android.view.WindowMetrics
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.airbnb.lottie.LottieAnimationView
 import com.android.systemui.R
@@ -90,7 +90,7 @@
 private const val SENSOR_ID = 1
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class SideFpsControllerTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
index bb037642..516f459 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
@@ -24,7 +24,7 @@
 import android.hardware.biometrics.BiometricOverlayConstants.ShowReason
 import android.hardware.fingerprint.FingerprintManager
 import android.hardware.fingerprint.IUdfpsOverlayControllerCallback
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import android.testing.TestableLooper.RunWithLooper
 import android.view.LayoutInflater
 import android.view.MotionEvent
@@ -77,7 +77,7 @@
 private const val SENSOR_HEIGHT = 60
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @RunWithLooper(setAsMainLooper = true)
 class UdfpsControllerOverlayTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 445cc87..8dbb355 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -58,7 +58,6 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.VibrationAttributes;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -68,6 +67,7 @@
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.logging.InstanceIdSequence;
@@ -124,7 +124,7 @@
 import javax.inject.Provider;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @RunWithLooper(setAsMainLooper = true)
 public class UdfpsControllerTest extends SysuiTestCase {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java
index 78fb5b0..cd9189b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapterTest.java
@@ -23,8 +23,8 @@
 import android.hardware.biometrics.SensorProperties;
 import android.hardware.fingerprint.FingerprintSensorProperties;
 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
-import android.testing.AndroidTestingRunner;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -35,7 +35,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @SmallTest
 public class UdfpsDialogMeasureAdapterTest extends SysuiTestCase {
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDisplayModeTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDisplayModeTest.java
index 1bc237d..5239966 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDisplayModeTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsDisplayModeTest.java
@@ -25,9 +25,9 @@
 import android.content.Context;
 import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback;
 import android.os.RemoteException;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper.RunWithLooper;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
@@ -40,7 +40,7 @@
 import org.mockito.MockitoAnnotations;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @RunWithLooper(setAsMainLooper = true)
 public class UdfpsDisplayModeTest extends SysuiTestCase {
     private static final int DISPLAY_ID = 0;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
index f437a8f..7a6060d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
@@ -26,10 +26,10 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.MotionEvent;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.shade.ShadeExpansionListener;
@@ -39,7 +39,7 @@
 import org.junit.runner.RunWith;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 public class UdfpsKeyguardViewControllerTest extends UdfpsKeyguardViewControllerBaseTest {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
index b848413..fea9d2d5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerWithCoroutinesTest.kt
@@ -17,8 +17,8 @@
 package com.android.systemui.biometrics
 
 import android.os.Handler
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardSecurityModel
 import com.android.systemui.classifier.FalsingCollector
@@ -39,10 +39,9 @@
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.time.FakeSystemClock
 import com.android.systemui.util.time.SystemClock
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.test.TestCoroutineScope
-import kotlinx.coroutines.yield
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
 import org.junit.Assert.assertFalse
 import org.junit.Assert.assertTrue
 import org.junit.Before
@@ -54,22 +53,27 @@
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @SmallTest
 @TestableLooper.RunWithLooper
+@kotlinx.coroutines.ExperimentalCoroutinesApi
 class UdfpsKeyguardViewControllerWithCoroutinesTest : UdfpsKeyguardViewControllerBaseTest() {
     lateinit var keyguardBouncerRepository: KeyguardBouncerRepository
     @Mock private lateinit var bouncerLogger: TableLogBuffer
 
+    private lateinit var testScope: TestScope
+
     @Before
     override fun setUp() {
+        testScope = TestScope()
+
         allowTestableLooperAsMainThread() // repeatWhenAttached requires the main thread
         MockitoAnnotations.initMocks(this)
         keyguardBouncerRepository =
             KeyguardBouncerRepositoryImpl(
                 mock(com.android.keyguard.ViewMediatorCallback::class.java),
                 FakeSystemClock(),
-                TestCoroutineScope(),
+                testScope.backgroundScope,
                 bouncerLogger,
             )
         super.setUp()
@@ -107,7 +111,7 @@
 
     @Test
     fun shadeLocked_showAlternateBouncer_unpauseAuth() =
-        runBlocking(IMMEDIATE) {
+        testScope.runTest {
             // GIVEN view is attached + on the SHADE_LOCKED (udfps view not showing)
             mController.onViewAttached()
             captureStatusBarStateListeners()
@@ -116,7 +120,7 @@
             // WHEN alternate bouncer is requested
             val job = mController.listenForAlternateBouncerVisibility(this)
             keyguardBouncerRepository.setAlternateVisible(true)
-            yield()
+            runCurrent()
 
             // THEN udfps view will animate in & pause auth is updated to NOT pause
             verify(mView).animateInUdfpsBouncer(any())
@@ -128,7 +132,7 @@
     /** After migration to MODERN_BOUNCER, replaces UdfpsKeyguardViewControllerTest version */
     @Test
     fun shouldPauseAuthBouncerShowing() =
-        runBlocking(IMMEDIATE) {
+        testScope.runTest {
             // GIVEN view attached and we're on the keyguard
             mController.onViewAttached()
             captureStatusBarStateListeners()
@@ -138,15 +142,11 @@
             val job = mController.listenForBouncerExpansion(this)
             keyguardBouncerRepository.setPrimaryShow(true)
             keyguardBouncerRepository.setPanelExpansion(KeyguardBouncerConstants.EXPANSION_VISIBLE)
-            yield()
+            runCurrent()
 
             // THEN UDFPS shouldPauseAuth == true
             assertTrue(mController.shouldPauseAuth())
 
             job.cancel()
         }
-
-    companion object {
-        private val IMMEDIATE = Dispatchers.Main.immediate
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsShellTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsShellTest.kt
index c2a129b..8b374ae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsShellTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsShellTest.kt
@@ -17,9 +17,9 @@
 package com.android.systemui.biometrics
 
 import android.graphics.Rect
-import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import android.view.MotionEvent
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.biometrics.UdfpsController.UdfpsOverlayController
@@ -39,7 +39,7 @@
 import org.mockito.junit.MockitoJUnit
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class UdfpsShellTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt
index 07b4a64..f075967 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsViewTest.kt
@@ -19,7 +19,7 @@
 import android.graphics.PointF
 import android.graphics.RectF
 import android.hardware.biometrics.SensorLocationInternal
-import android.testing.AndroidTestingRunner
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import android.testing.TestableLooper
 import android.testing.ViewUtils
 import android.view.LayoutInflater
@@ -49,7 +49,7 @@
 private const val SENSOR_RADIUS = 10
 
 @SmallTest
-@RunWith(AndroidTestingRunner::class)
+@RunWith(AndroidJUnit4::class)
 @TestableLooper.RunWithLooper
 class UdfpsViewTest : SysuiTestCase() {
 
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
index 1bab997..1ec4e8c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
@@ -22,12 +22,14 @@
 import static org.mockito.Mockito.when;
 
 import android.app.Instrumentation;
+import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.MessageQueue;
 import android.os.ParcelFileDescriptor;
 import android.testing.DexmakerShareClassLoaderRule;
 import android.testing.LeakCheck;
+import android.testing.TestWithLooperRule;
 import android.testing.TestableLooper;
 import android.util.Log;
 
@@ -73,12 +75,21 @@
     @Rule
     public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
             new DexmakerShareClassLoaderRule();
+
+    // set the highest order so it's the innermost rule
+    @Rule(order = Integer.MAX_VALUE)
+    public TestWithLooperRule mlooperRule = new TestWithLooperRule();
+
     public TestableDependency mDependency;
     private Instrumentation mRealInstrumentation;
     private FakeBroadcastDispatcher mFakeBroadcastDispatcher;
 
     @Before
     public void SysuiSetup() throws Exception {
+        // Manually associate a Display to context for Robolectric test. Similar to b/214297409
+        if (isRobolectricTest()) {
+            mContext = mContext.createDefaultDisplayContext();
+        }
         SystemUIInitializer initializer =
                 SystemUIInitializerFactory.createFromConfigNoAssert(mContext);
         initializer.init(true);
@@ -215,6 +226,10 @@
         idler.waitForIdle();
     }
 
+    public static boolean isRobolectricTest() {
+        return Build.FINGERPRINT.contains("robolectric");
+    }
+
     private static final void validateThread(Looper l) {
         if (Looper.myLooper() == l) {
             throw new RuntimeException(
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java
index 0674ea8..5ff57aa 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java
@@ -18,6 +18,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.hardware.display.DisplayManager;
 import android.os.Handler;
 import android.os.UserHandle;
 import android.testing.LeakCheck;
@@ -56,6 +57,11 @@
         return context;
     }
 
+    public SysuiTestableContext createDefaultDisplayContext() {
+        Display display = getBaseContext().getSystemService(DisplayManager.class).getDisplays()[0];
+        return (SysuiTestableContext) createDisplayContext(display);
+    }
+
     public void cleanUpReceivers(String testName) {
         Set<BroadcastReceiver> copy;
         synchronized (mRegisteredReceivers) {