diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 3e50c91cd4f20678666ce67e292a985cb7d9ae1c..0b6e4009c4f7270f910461832def6f8c9cf16060 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -47,6 +47,7 @@ import com.android.systemui.statusbar.notification.SourceType;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
+import com.android.systemui.statusbar.notification.shared.NotificationIconContainerRefactor;
 import com.android.systemui.statusbar.notification.stack.AmbientState;
 import com.android.systemui.statusbar.notification.stack.AnimationProperties;
 import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
@@ -151,7 +152,11 @@ public class NotificationShelf extends ActivatableNotificationView {
                 R.dimen.notification_corner_animation_distance);
         mEnableNotificationClipping = res.getBoolean(R.bool.notification_enable_clipping);
 
-        mShelfIcons.setInNotificationIconShelf(true);
+        if (NotificationIconContainerRefactor.isEnabled()) {
+            mShelfIcons.setOverrideIconColor(true);
+        } else {
+            mShelfIcons.setInNotificationIconShelf(true);
+        }
         if (!mShowNotificationShelf) {
             setVisibility(GONE);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 3a4ad0e79994f30a79d5d35c457adc3446b3296b..3bf8057aece2b8d817a48c5cc6df1c5ea0cd3999 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -59,7 +59,7 @@ import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.util.ContrastColorUtil;
 import com.android.systemui.res.R;
-import com.android.systemui.statusbar.notification.NotificationIconDozeHelper;
+import com.android.systemui.statusbar.notification.NotificationDozeHelper;
 import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.util.drawable.DrawableSize;
 
@@ -174,7 +174,7 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi
                 animation.getAnimatedFraction());
         setColorInternal(newColor);
     };
-    private final NotificationIconDozeHelper mDozer;
+    private final NotificationDozeHelper mDozer;
     private int mContrastedDrawableColor;
     private int mCachedContrastBackgroundColor = NO_COLOR;
     private float[] mMatrix;
@@ -192,7 +192,7 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi
     public StatusBarIconView(Context context, String slot, StatusBarNotification sbn,
             boolean blocked) {
         super(context);
-        mDozer = new NotificationIconDozeHelper(context);
+        mDozer = new NotificationDozeHelper();
         mBlocked = blocked;
         mSlot = slot;
         mNumberPain = new Paint();
@@ -712,7 +712,6 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi
         setColorInternal(color);
         updateContrastedStaticColor();
         mIconColor = color;
-        mDozer.setColor(color);
     }
 
     private void setColorInternal(int color) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java
index dc0eb7b4aab34d92741eb70af9348e9512891db4..2f9917fe33fe4c22bb6dc277bed79555407c362f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationDozeHelper.java
@@ -36,26 +36,6 @@ public class NotificationDozeHelper {
     private static final int DOZE_ANIMATOR_TAG = R.id.doze_intensity_tag;
     private final ColorMatrix mGrayscaleColorMatrix = new ColorMatrix();
 
-    public void fadeGrayscale(final ImageView target, final boolean dark, long delay) {
-        startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                updateGrayscale(target, (float) animation.getAnimatedValue());
-            }
-        }, dark, delay, new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                if (!dark) {
-                    target.setColorFilter(null);
-                }
-            }
-        });
-    }
-
-    public void updateGrayscale(ImageView target, boolean dark) {
-        updateGrayscale(target, dark ? 1 : 0);
-    }
-
     public void updateGrayscale(ImageView target, float darkAmount) {
         if (darkAmount > 0) {
             updateGrayscaleMatrix(darkAmount);
@@ -66,7 +46,7 @@ public class NotificationDozeHelper {
     }
 
     // TODO: this should be using StatusBarStateController#getDozeAmount
-    public void startIntensityAnimation(ValueAnimator.AnimatorUpdateListener updateListener,
+    private void startIntensityAnimation(ValueAnimator.AnimatorUpdateListener updateListener,
             boolean dark, long delay, Animator.AnimatorListener listener) {
         float startIntensity = dark ? 0f : 1f;
         float endIntensity = dark ? 1f : 0f;
@@ -81,11 +61,6 @@ public class NotificationDozeHelper {
         animator.start();
     }
 
-    public void setDozing(Consumer<Float> listener, boolean dozing,
-            boolean animate, long delay, View view) {
-        setDozing(listener, dozing, animate, delay, view, /* endRunnable= */ null);
-    }
-
     public void setDozing(Consumer<Float> listener, boolean dozing,
             boolean animate, long delay, View view, @Nullable Runnable endRunnable) {
         if (animate) {
@@ -118,11 +93,7 @@ public class NotificationDozeHelper {
         }
     }
 
-    public void updateGrayscaleMatrix(float intensity) {
+    private void updateGrayscaleMatrix(float intensity) {
         mGrayscaleColorMatrix.setSaturation(1 - intensity);
     }
-
-    public ColorMatrix getGrayscaleColorMatrix() {
-        return mGrayscaleColorMatrix;
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationIconDozeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationIconDozeHelper.java
deleted file mode 100644
index 552bfb288d7a9d0e17633bbb238fe8d2971761b1..0000000000000000000000000000000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationIconDozeHelper.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2017 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.statusbar.notification;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.graphics.Color;
-import android.graphics.PorterDuff.Mode;
-import android.graphics.PorterDuffColorFilter;
-import android.graphics.drawable.Drawable;
-import android.widget.ImageView;
-
-import com.android.systemui.res.R;
-
-public class NotificationIconDozeHelper extends NotificationDozeHelper {
-
-    private final int mImageDarkAlpha;
-    private final int mImageDarkColor = 0xffffffff;
-
-    @Nullable
-    private PorterDuffColorFilter mImageColorFilter = null;
-
-    private int mColor = Color.BLACK;
-
-    public NotificationIconDozeHelper(Context ctx) {
-        mImageDarkAlpha = ctx.getResources().getInteger(R.integer.doze_small_icon_alpha);
-    }
-
-    public void setColor(int color) {
-        mColor = color;
-    }
-
-    public void setImageDark(ImageView target, boolean dark, boolean fade, long delay,
-            boolean useGrayscale) {
-        if (fade) {
-            if (!useGrayscale) {
-                fadeImageColorFilter(target, dark, delay);
-                fadeImageAlpha(target, dark, delay);
-            } else {
-                fadeGrayscale(target, dark, delay);
-            }
-        } else {
-            if (!useGrayscale) {
-                updateImageColorFilter(target, dark);
-                updateImageAlpha(target, dark);
-            } else {
-                updateGrayscale(target, dark);
-            }
-        }
-    }
-
-    private void fadeImageColorFilter(final ImageView target, boolean dark, long delay) {
-        startIntensityAnimation(animation -> {
-            updateImageColorFilter(target, (Float) animation.getAnimatedValue());
-        }, dark, delay, null /* listener */);
-    }
-
-    private void fadeImageAlpha(final ImageView target, boolean dark, long delay) {
-        startIntensityAnimation(animation -> {
-            float t = (float) animation.getAnimatedValue();
-            target.setImageAlpha((int) (255 * (1f - t) + mImageDarkAlpha * t));
-        }, dark, delay, null /* listener */);
-    }
-
-    private void updateImageColorFilter(ImageView target, boolean dark) {
-        updateImageColorFilter(target, dark ? 1f : 0f);
-    }
-
-    private void updateImageColorFilter(ImageView target, float intensity) {
-        int color = NotificationUtils.interpolateColors(mColor, mImageDarkColor, intensity);
-        if (mImageColorFilter == null || mImageColorFilter.getColor() != color) {
-            mImageColorFilter = new PorterDuffColorFilter(color, Mode.SRC_ATOP);
-        }
-        Drawable imageDrawable = target.getDrawable();
-
-        // Also, the notification might have been modified during the animation, so background
-        // might be null here.
-        if (imageDrawable != null) {
-            Drawable d = imageDrawable.mutate();
-            // DrawableContainer ignores the color filter if it's already set, so clear it first to
-            // get it set and invalidated properly.
-            d.setColorFilter(null);
-            d.setColorFilter(mImageColorFilter);
-        }
-    }
-
-    private void updateImageAlpha(ImageView target, boolean dark) {
-        target.setImageAlpha(dark ? mImageDarkAlpha : 255);
-    }
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 75a697f17e6ffb70d953ea14f13b2292262a1ead..01f3b63280a259bd1c871a2f3752feb78b716d51 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -132,13 +132,16 @@ public class NotificationIconContainer extends ViewGroup {
         }
     }.setDuration(CONTENT_FADE_DURATION);
 
+    // TODO(b/278765923): Replace these with domain-agnostic state
     /* Maximum number of icons on AOD when also showing overflow dot. */
     private int mMaxIconsOnAod;
-
     /* Maximum number of icons in short shelf on lockscreen when also showing overflow dot. */
     private int mMaxIconsOnLockscreen;
     /* Maximum number of icons in the status bar when also showing overflow dot. */
     private int mMaxStaticIcons;
+    private boolean mDozing;
+    private boolean mOnLockScreen;
+    private boolean mOverrideIconColor;
 
     private boolean mIsStaticLayout = true;
     private final HashMap<View, IconState> mIconStates = new HashMap<>();
@@ -147,9 +150,6 @@ public class NotificationIconContainer extends ViewGroup {
     private int mActualLayoutWidth = NO_VALUE;
     private float mActualPaddingEnd = NO_VALUE;
     private float mActualPaddingStart = NO_VALUE;
-    private boolean mDozing;
-    private boolean mOnLockScreen;
-    private boolean mInNotificationIconShelf;
     private boolean mChangingViewPositions;
     private int mAddAnimationStartIndex = -1;
     private int mCannedAnimationStartIndex = -1;
@@ -284,7 +284,7 @@ public class NotificationIconContainer extends ViewGroup {
     public String toString() {
         return "NotificationIconContainer("
                 + "dozing=" + mDozing + " onLockScreen=" + mOnLockScreen
-                + " inNotificationIconShelf=" + mInNotificationIconShelf
+                + " overrideIconColor=" + mOverrideIconColor
                 + " speedBumpIndex=" + mSpeedBumpIndex
                 + " themedTextColorPrimary=#" + Integer.toHexString(mThemedTextColorPrimary) + ')';
     }
@@ -739,8 +739,15 @@ public class NotificationIconContainer extends ViewGroup {
         mOnLockScreen = onLockScreen;
     }
 
+    @Deprecated
     public void setInNotificationIconShelf(boolean inShelf) {
-        mInNotificationIconShelf = inShelf;
+        NotificationIconContainerRefactor.assertInLegacyMode();
+        mOverrideIconColor = inShelf;
+    }
+
+    public void setOverrideIconColor(boolean override) {
+        if (NotificationIconContainerRefactor.isUnexpectedlyInLegacyMode()) return;
+        mOverrideIconColor = override;
     }
 
     public class IconState extends ViewState {
@@ -858,7 +865,7 @@ public class NotificationIconContainer extends ViewGroup {
                     }
                 }
                 icon.setVisibleState(visibleState, animationsAllowed);
-                icon.setIconColor(mInNotificationIconShelf ? mThemedTextColorPrimary : iconColor,
+                icon.setIconColor(mOverrideIconColor ? mThemedTextColorPrimary : iconColor,
                         needsCannedAnimation && animationsAllowed);
                 if (animate) {
                     animateTo(icon, animationProperties);
diff --git a/packages/SystemUI/tests/src/com/android/SysUITestModule.kt b/packages/SystemUI/tests/src/com/android/SysUITestModule.kt
index c4b43e1cbe77238642e56686a3ea66a63f9200e6..97e43ad91f532f24744444a08fad85cdb599a1d5 100644
--- a/packages/SystemUI/tests/src/com/android/SysUITestModule.kt
+++ b/packages/SystemUI/tests/src/com/android/SysUITestModule.kt
@@ -24,11 +24,21 @@ import com.android.systemui.SysuiTestCase
 import com.android.systemui.SysuiTestableContext
 import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.broadcast.FakeBroadcastDispatcher
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.coroutines.collectValues
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Main
 import dagger.Binds
 import dagger.Module
 import dagger.Provides
+import kotlin.coroutines.CoroutineContext
+import kotlin.coroutines.EmptyCoroutineContext
+import kotlinx.coroutines.CoroutineStart
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
 
 @Module(
     includes =
@@ -64,3 +74,35 @@ interface SysUITestModule {
             test.fakeBroadcastDispatcher
     }
 }
+
+interface SysUITestComponent<out T> {
+    val testScope: TestScope
+    val underTest: T
+}
+
+@OptIn(ExperimentalCoroutinesApi::class)
+fun <T : SysUITestComponent<*>> T.runTest(block: suspend T.() -> Unit): Unit =
+    testScope.runTest {
+        // Access underTest immediately to force Dagger to instantiate it prior to the test running
+        underTest
+        runCurrent()
+        block()
+    }
+
+@OptIn(ExperimentalCoroutinesApi::class)
+fun SysUITestComponent<*>.runCurrent() = testScope.runCurrent()
+
+fun <T> SysUITestComponent<*>.collectLastValue(
+    flow: Flow<T>,
+    context: CoroutineContext = EmptyCoroutineContext,
+    start: CoroutineStart = CoroutineStart.DEFAULT,
+) = testScope.collectLastValue(flow, context, start)
+
+fun <T> SysUITestComponent<*>.collectValues(
+    flow: Flow<T>,
+    context: CoroutineContext = EmptyCoroutineContext,
+    start: CoroutineStart = CoroutineStart.DEFAULT,
+) = testScope.collectValues(flow, context, start)
+
+val SysUITestComponent<*>.backgroundScope
+    get() = testScope.backgroundScope
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt
index 8c26776a1ef8a67c29b8708272805adbc016790c..d2b81e06c0e5eab37dfc9f49861f8453bbc3fc9a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthDialogPanelInteractionDetectorTest.kt
@@ -17,7 +17,10 @@
 package com.android.systemui.biometrics
 
 import androidx.test.filters.SmallTest
+import com.android.SysUITestComponent
 import com.android.SysUITestModule
+import com.android.runCurrent
+import com.android.runTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.flags.FakeFeatureFlagsClassicModule
@@ -26,10 +29,6 @@ import com.android.systemui.shade.data.repository.FakeShadeRepository
 import com.android.systemui.user.domain.UserDomainLayerModule
 import dagger.BindsInstance
 import dagger.Component
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.runCurrent
-import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
 import org.mockito.Mock
@@ -38,9 +37,29 @@ import org.mockito.Mockito.verifyZeroInteractions
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-@OptIn(ExperimentalCoroutinesApi::class)
 class AuthDialogPanelInteractionDetectorTest : SysuiTestCase() {
 
+    @SysUISingleton
+    @Component(
+        modules =
+            [
+                SysUITestModule::class,
+                UserDomainLayerModule::class,
+            ]
+    )
+    interface TestComponent : SysUITestComponent<AuthDialogPanelInteractionDetector> {
+
+        val shadeRepository: FakeShadeRepository
+
+        @Component.Factory
+        interface Factory {
+            fun create(
+                @BindsInstance test: SysuiTestCase,
+                featureFlags: FakeFeatureFlagsClassicModule,
+            ): TestComponent
+        }
+    }
+
     private val testComponent: TestComponent =
         DaggerAuthDialogPanelInteractionDetectorTest_TestComponent.factory()
             .create(
@@ -52,11 +71,9 @@ class AuthDialogPanelInteractionDetectorTest : SysuiTestCase() {
                     },
             )
 
-    @Mock private lateinit var action: Runnable
+    private val detector: AuthDialogPanelInteractionDetector = testComponent.underTest
 
-    private val testScope = testComponent.testScope
-    private val shadeRepository = testComponent.shadeRepository
-    private val detector = testComponent.detector
+    @Mock private lateinit var action: Runnable
 
     @Before
     fun setUp() {
@@ -65,7 +82,7 @@ class AuthDialogPanelInteractionDetectorTest : SysuiTestCase() {
 
     @Test
     fun enableDetector_expand_shouldRunAction() =
-        testScope.runTest {
+        testComponent.runTest {
             // GIVEN shade is closed and detector is enabled
             shadeRepository.setLegacyShadeExpansion(0f)
             detector.enable(action)
@@ -82,7 +99,7 @@ class AuthDialogPanelInteractionDetectorTest : SysuiTestCase() {
 
     @Test
     fun enableDetector_shadeExpandImmediate_shouldNotPostRunnable() =
-        testScope.runTest {
+        testComponent.runTest {
             // GIVEN shade is closed and detector is enabled
             shadeRepository.setLegacyShadeExpansion(0f)
             detector.enable(action)
@@ -94,14 +111,11 @@ class AuthDialogPanelInteractionDetectorTest : SysuiTestCase() {
 
             // THEN action not run
             verifyZeroInteractions(action)
-
-            // Clean up job
-            detector.disable()
         }
 
     @Test
     fun disableDetector_shouldNotPostRunnable() =
-        testScope.runTest {
+        testComponent.runTest {
             // GIVEN shade is closed and detector is enabled
             shadeRepository.setLegacyShadeExpansion(0f)
             detector.enable(action)
@@ -109,6 +123,7 @@ class AuthDialogPanelInteractionDetectorTest : SysuiTestCase() {
 
             // WHEN detector is disabled and shade opens
             detector.disable()
+            runCurrent()
             shadeRepository.setLegacyShadeTracking(true)
             shadeRepository.setLegacyShadeExpansion(.5f)
             runCurrent()
@@ -119,7 +134,7 @@ class AuthDialogPanelInteractionDetectorTest : SysuiTestCase() {
 
     @Test
     fun enableDetector_beginCollapse_shouldNotPostRunnable() =
-        testScope.runTest {
+        testComponent.runTest {
             // GIVEN shade is open and detector is enabled
             shadeRepository.setLegacyShadeExpansion(1f)
             detector.enable(action)
@@ -131,31 +146,5 @@ class AuthDialogPanelInteractionDetectorTest : SysuiTestCase() {
 
             // THEN action not run
             verifyZeroInteractions(action)
-
-            // Clean up job
-            detector.disable()
         }
-
-    @SysUISingleton
-    @Component(
-        modules =
-            [
-                SysUITestModule::class,
-                UserDomainLayerModule::class,
-            ]
-    )
-    interface TestComponent {
-
-        val detector: AuthDialogPanelInteractionDetector
-        val shadeRepository: FakeShadeRepository
-        val testScope: TestScope
-
-        @Component.Factory
-        interface Factory {
-            fun create(
-                @BindsInstance test: SysuiTestCase,
-                featureFlags: FakeFeatureFlagsClassicModule,
-            ): TestComponent
-        }
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
index 4a1386e21e2aef66c58238151a37f24191039fa8..985b6fde4c63f2e1e2ffca4f7d18ab4f8136bd67 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModelTest.kt
@@ -21,8 +21,12 @@ package com.android.systemui.keyguard.ui.viewmodel
 
 import android.view.View
 import androidx.test.filters.SmallTest
+import com.android.SysUITestComponent
 import com.android.SysUITestModule
 import com.android.TestMocksModule
+import com.android.collectLastValue
+import com.android.runCurrent
+import com.android.runTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
 import com.android.systemui.coroutines.collectLastValue
@@ -319,12 +323,10 @@ class KeyguardRootViewModelTestWithFakes : SysuiTestCase() {
 
     @Component(modules = [SysUITestModule::class])
     @SysUISingleton
-    interface TestComponent {
-        val underTest: KeyguardRootViewModel
+    interface TestComponent : SysUITestComponent<KeyguardRootViewModel> {
         val deviceEntryRepository: FakeDeviceEntryRepository
         val notifsKeyguardRepository: FakeNotificationsKeyguardViewStateRepository
         val repository: FakeKeyguardRepository
-        val testScope: TestScope
         val transitionRepository: FakeKeyguardTransitionRepository
 
         @Component.Factory
@@ -356,28 +358,25 @@ class KeyguardRootViewModelTestWithFakes : SysuiTestCase() {
                     TestMocksModule(
                         dozeParameters = dozeParams,
                         screenOffAnimationController = screenOffAnimController,
-                    )
+                    ),
             )
-            .run {
+            .runTest {
                 reset(clockController)
                 underTest.clockControllerProvider = Provider { clockController }
-                testScope.runTest {
-                    runCurrent()
-                    block()
-                }
+                block()
             }
 
     @Test
     fun iconContainer_isNotVisible_notOnKeyguard_dontShowAodIconsWhenShade() = runTest {
-        val isVisible by testScope.collectLastValue(underTest.isNotifIconContainerVisible)
-        testScope.runCurrent()
+        val isVisible by collectLastValue(underTest.isNotifIconContainerVisible)
+        runCurrent()
         transitionRepository.sendTransitionSteps(
             from = KeyguardState.OFF,
             to = KeyguardState.GONE,
             testScope,
         )
         whenever(screenOffAnimController.shouldShowAodIconsWhenShade()).thenReturn(false)
-        testScope.runCurrent()
+        runCurrent()
 
         assertThat(isVisible?.value).isFalse()
         assertThat(isVisible?.isAnimating).isFalse()
@@ -385,33 +384,33 @@ class KeyguardRootViewModelTestWithFakes : SysuiTestCase() {
 
     @Test
     fun iconContainer_isVisible_bypassEnabled() = runTest {
-        val isVisible by testScope.collectLastValue(underTest.isNotifIconContainerVisible)
-        testScope.runCurrent()
+        val isVisible by collectLastValue(underTest.isNotifIconContainerVisible)
+        runCurrent()
         deviceEntryRepository.setBypassEnabled(true)
-        testScope.runCurrent()
+        runCurrent()
 
         assertThat(isVisible?.value).isTrue()
     }
 
     @Test
     fun iconContainer_isNotVisible_pulseExpanding_notBypassing() = runTest {
-        val isVisible by testScope.collectLastValue(underTest.isNotifIconContainerVisible)
-        testScope.runCurrent()
+        val isVisible by collectLastValue(underTest.isNotifIconContainerVisible)
+        runCurrent()
         notifsKeyguardRepository.setPulseExpanding(true)
         deviceEntryRepository.setBypassEnabled(false)
-        testScope.runCurrent()
+        runCurrent()
 
         assertThat(isVisible?.value).isEqualTo(false)
     }
 
     @Test
     fun iconContainer_isVisible_notifsFullyHidden_bypassEnabled() = runTest {
-        val isVisible by testScope.collectLastValue(underTest.isNotifIconContainerVisible)
-        testScope.runCurrent()
+        val isVisible by collectLastValue(underTest.isNotifIconContainerVisible)
+        runCurrent()
         notifsKeyguardRepository.setPulseExpanding(false)
         deviceEntryRepository.setBypassEnabled(true)
         notifsKeyguardRepository.setNotificationsFullyHidden(true)
-        testScope.runCurrent()
+        runCurrent()
 
         assertThat(isVisible?.value).isTrue()
         assertThat(isVisible?.isAnimating).isTrue()
@@ -419,13 +418,13 @@ class KeyguardRootViewModelTestWithFakes : SysuiTestCase() {
 
     @Test
     fun iconContainer_isVisible_notifsFullyHidden_bypassDisabled_aodDisabled() = runTest {
-        val isVisible by testScope.collectLastValue(underTest.isNotifIconContainerVisible)
-        testScope.runCurrent()
+        val isVisible by collectLastValue(underTest.isNotifIconContainerVisible)
+        runCurrent()
         notifsKeyguardRepository.setPulseExpanding(false)
         deviceEntryRepository.setBypassEnabled(false)
         whenever(dozeParams.alwaysOn).thenReturn(false)
         notifsKeyguardRepository.setNotificationsFullyHidden(true)
-        testScope.runCurrent()
+        runCurrent()
 
         assertThat(isVisible?.value).isTrue()
         assertThat(isVisible?.isAnimating).isFalse()
@@ -433,14 +432,14 @@ class KeyguardRootViewModelTestWithFakes : SysuiTestCase() {
 
     @Test
     fun iconContainer_isVisible_notifsFullyHidden_bypassDisabled_displayNeedsBlanking() = runTest {
-        val isVisible by testScope.collectLastValue(underTest.isNotifIconContainerVisible)
-        testScope.runCurrent()
+        val isVisible by collectLastValue(underTest.isNotifIconContainerVisible)
+        runCurrent()
         notifsKeyguardRepository.setPulseExpanding(false)
         deviceEntryRepository.setBypassEnabled(false)
         whenever(dozeParams.alwaysOn).thenReturn(true)
         whenever(dozeParams.displayNeedsBlanking).thenReturn(true)
         notifsKeyguardRepository.setNotificationsFullyHidden(true)
-        testScope.runCurrent()
+        runCurrent()
 
         assertThat(isVisible?.value).isTrue()
         assertThat(isVisible?.isAnimating).isFalse()
@@ -448,14 +447,14 @@ class KeyguardRootViewModelTestWithFakes : SysuiTestCase() {
 
     @Test
     fun iconContainer_isVisible_notifsFullyHidden_bypassDisabled() = runTest {
-        val isVisible by testScope.collectLastValue(underTest.isNotifIconContainerVisible)
-        testScope.runCurrent()
+        val isVisible by collectLastValue(underTest.isNotifIconContainerVisible)
+        runCurrent()
         notifsKeyguardRepository.setPulseExpanding(false)
         deviceEntryRepository.setBypassEnabled(false)
         whenever(dozeParams.alwaysOn).thenReturn(true)
         whenever(dozeParams.displayNeedsBlanking).thenReturn(false)
         notifsKeyguardRepository.setNotificationsFullyHidden(true)
-        testScope.runCurrent()
+        runCurrent()
 
         assertThat(isVisible?.value).isTrue()
         assertThat(isVisible?.isAnimating).isTrue()
@@ -463,18 +462,18 @@ class KeyguardRootViewModelTestWithFakes : SysuiTestCase() {
 
     @Test
     fun isIconContainerVisible_stopAnimation() = runTest {
-        val isVisible by testScope.collectLastValue(underTest.isNotifIconContainerVisible)
-        testScope.runCurrent()
+        val isVisible by collectLastValue(underTest.isNotifIconContainerVisible)
+        runCurrent()
         notifsKeyguardRepository.setPulseExpanding(false)
         deviceEntryRepository.setBypassEnabled(false)
         whenever(dozeParams.alwaysOn).thenReturn(true)
         whenever(dozeParams.displayNeedsBlanking).thenReturn(false)
         notifsKeyguardRepository.setNotificationsFullyHidden(true)
-        testScope.runCurrent()
+        runCurrent()
 
         assertThat(isVisible?.isAnimating).isEqualTo(true)
         isVisible?.stopAnimating()
-        testScope.runCurrent()
+        runCurrent()
 
         assertThat(isVisible?.isAnimating).isEqualTo(false)
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
index 8b8a6258589885fe7f3c903a7d0d5eb58d6232c1..ff7443f10bf3fb75e05c3cc8ad529b3dbd84f348 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
@@ -22,11 +22,14 @@ import android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS
 import android.content.pm.UserInfo
 import android.os.UserManager
 import androidx.test.filters.SmallTest
+import com.android.SysUITestComponent
 import com.android.SysUITestModule
 import com.android.TestMocksModule
+import com.android.collectLastValue
+import com.android.runCurrent
+import com.android.runTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
-import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.flags.FakeFeatureFlagsClassicModule
 import com.android.systemui.flags.Flags
@@ -54,75 +57,70 @@ import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvision
 import com.android.systemui.user.data.model.UserSwitcherSettingsModel
 import com.android.systemui.user.data.repository.FakeUserRepository
 import com.android.systemui.user.domain.UserDomainLayerModule
+import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
 import dagger.BindsInstance
 import dagger.Component
-import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.runCurrent
-import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
-import org.mockito.Mock
-import org.mockito.MockitoAnnotations
 
 @SmallTest
-@OptIn(ExperimentalCoroutinesApi::class)
 class ShadeInteractorTest : SysuiTestCase() {
 
-    @Mock private lateinit var dozeParameters: DozeParameters
-
-    private lateinit var testComponent: TestComponent
-
-    private val configurationRepository
-        get() = testComponent.configurationRepository
-    private val deviceProvisioningRepository
-        get() = testComponent.deviceProvisioningRepository
-    private val disableFlagsRepository
-        get() = testComponent.disableFlagsRepository
-    private val keyguardRepository
-        get() = testComponent.keyguardRepository
-    private val keyguardTransitionRepository
-        get() = testComponent.keygaurdTransitionRepository
-    private val powerRepository
-        get() = testComponent.powerRepository
-    private val sceneInteractor
-        get() = testComponent.sceneInteractor
-    private val shadeRepository
-        get() = testComponent.shadeRepository
-    private val testScope
-        get() = testComponent.testScope
-    private val userRepository
-        get() = testComponent.userRepository
-    private val userSetupRepository
-        get() = testComponent.userSetupRepository
-
-    private lateinit var underTest: ShadeInteractor
+    @SysUISingleton
+    @Component(
+        modules =
+            [
+                SysUITestModule::class,
+                UserDomainLayerModule::class,
+            ]
+    )
+    interface TestComponent : SysUITestComponent<ShadeInteractor> {
+
+        val configurationRepository: FakeConfigurationRepository
+        val deviceProvisioningRepository: FakeDeviceProvisioningRepository
+        val disableFlagsRepository: FakeDisableFlagsRepository
+        val keyguardRepository: FakeKeyguardRepository
+        val keyguardTransitionRepository: FakeKeyguardTransitionRepository
+        val powerRepository: FakePowerRepository
+        val sceneInteractor: SceneInteractor
+        val shadeRepository: FakeShadeRepository
+        val userRepository: FakeUserRepository
+        val userSetupRepository: FakeUserSetupRepository
+
+        @Component.Factory
+        interface Factory {
+            fun create(
+                @BindsInstance test: SysuiTestCase,
+                featureFlags: FakeFeatureFlagsClassicModule,
+                mocks: TestMocksModule,
+            ): TestComponent
+        }
+    }
+
+    private val dozeParameters: DozeParameters = mock()
+
+    private val testComponent: TestComponent =
+        DaggerShadeInteractorTest_TestComponent.factory()
+            .create(
+                test = this,
+                featureFlags =
+                    FakeFeatureFlagsClassicModule {
+                        set(Flags.FACE_AUTH_REFACTOR, false)
+                        set(Flags.FULL_SCREEN_USER_SWITCHER, true)
+                    },
+                mocks =
+                    TestMocksModule(
+                        dozeParameters = dozeParameters,
+                    ),
+            )
 
     @Before
     fun setUp() {
-        MockitoAnnotations.initMocks(this)
-
-        testComponent =
-            DaggerShadeInteractorTest_TestComponent.factory()
-                .create(
-                    test = this,
-                    featureFlags =
-                        FakeFeatureFlagsClassicModule {
-                            set(Flags.FACE_AUTH_REFACTOR, false)
-                            set(Flags.FULL_SCREEN_USER_SWITCHER, true)
-                        },
-                    mocks =
-                        TestMocksModule(
-                            dozeParameters = dozeParameters,
-                        ),
-                )
-        underTest = testComponent.underTest
-
         runBlocking {
             val userInfos =
                 listOf(
@@ -136,14 +134,16 @@ class ShadeInteractorTest : SysuiTestCase() {
                         UserManager.USER_TYPE_FULL_SYSTEM,
                     ),
                 )
-            userRepository.setUserInfos(userInfos)
-            userRepository.setSelectedUserInfo(userInfos[0])
+            testComponent.apply {
+                userRepository.setUserInfos(userInfos)
+                userRepository.setSelectedUserInfo(userInfos[0])
+            }
         }
     }
 
     @Test
     fun isShadeEnabled_matchesDisableFlagsRepo() =
-        testScope.runTest {
+        testComponent.runTest {
             val actual by collectLastValue(underTest.isShadeEnabled)
 
             disableFlagsRepository.disableFlags.value =
@@ -157,7 +157,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun isExpandToQsEnabled_deviceNotProvisioned_false() =
-        testScope.runTest {
+        testComponent.runTest {
             deviceProvisioningRepository.setDeviceProvisioned(false)
 
             val actual by collectLastValue(underTest.isExpandToQsEnabled)
@@ -167,7 +167,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun isExpandToQsEnabled_userNotSetupAndSimpleUserSwitcher_false() =
-        testScope.runTest {
+        testComponent.runTest {
             deviceProvisioningRepository.setDeviceProvisioned(true)
 
             userSetupRepository.setUserSetup(false)
@@ -180,7 +180,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun isExpandToQsEnabled_shadeNotEnabled_false() =
-        testScope.runTest {
+        testComponent.runTest {
             deviceProvisioningRepository.setDeviceProvisioned(true)
             userSetupRepository.setUserSetup(true)
 
@@ -196,7 +196,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun isExpandToQsEnabled_quickSettingsNotEnabled_false() =
-        testScope.runTest {
+        testComponent.runTest {
             deviceProvisioningRepository.setDeviceProvisioned(true)
             userSetupRepository.setUserSetup(true)
 
@@ -211,7 +211,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun isExpandToQsEnabled_dozing_false() =
-        testScope.runTest {
+        testComponent.runTest {
             deviceProvisioningRepository.setDeviceProvisioned(true)
             userSetupRepository.setUserSetup(true)
             disableFlagsRepository.disableFlags.value =
@@ -228,7 +228,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun isExpandToQsEnabled_userSetup_true() =
-        testScope.runTest {
+        testComponent.runTest {
             deviceProvisioningRepository.setDeviceProvisioned(true)
             keyguardRepository.setIsDozing(false)
             disableFlagsRepository.disableFlags.value =
@@ -245,7 +245,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun isExpandToQsEnabled_notSimpleUserSwitcher_true() =
-        testScope.runTest {
+        testComponent.runTest {
             deviceProvisioningRepository.setDeviceProvisioned(true)
             keyguardRepository.setIsDozing(false)
             disableFlagsRepository.disableFlags.value =
@@ -262,7 +262,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun isExpandToQsEnabled_respondsToDozingUpdates() =
-        testScope.runTest {
+        testComponent.runTest {
             deviceProvisioningRepository.setDeviceProvisioned(true)
             keyguardRepository.setIsDozing(false)
             disableFlagsRepository.disableFlags.value =
@@ -290,7 +290,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun isExpandToQsEnabled_respondsToDisableUpdates() =
-        testScope.runTest {
+        testComponent.runTest {
             deviceProvisioningRepository.setDeviceProvisioned(true)
             keyguardRepository.setIsDozing(false)
             disableFlagsRepository.disableFlags.value =
@@ -322,7 +322,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun isExpandToQsEnabled_respondsToUserUpdates() =
-        testScope.runTest {
+        testComponent.runTest {
             deviceProvisioningRepository.setDeviceProvisioned(true)
             keyguardRepository.setIsDozing(false)
             disableFlagsRepository.disableFlags.value =
@@ -351,7 +351,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun fullShadeExpansionWhenShadeLocked() =
-        testScope.runTest {
+        testComponent.runTest {
             val actual by collectLastValue(underTest.shadeExpansion)
 
             keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED)
@@ -362,7 +362,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun fullShadeExpansionWhenStatusBarStateIsNotShadeLocked() =
-        testScope.runTest {
+        testComponent.runTest {
             val actual by collectLastValue(underTest.shadeExpansion)
 
             keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
@@ -376,7 +376,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun shadeExpansionWhenInSplitShadeAndQsExpanded() =
-        testScope.runTest {
+        testComponent.runTest {
             val actual by collectLastValue(underTest.shadeExpansion)
 
             // WHEN split shade is enabled and QS is expanded
@@ -393,7 +393,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun shadeExpansionWhenNotInSplitShadeAndQsExpanded() =
-        testScope.runTest {
+        testComponent.runTest {
             val actual by collectLastValue(underTest.shadeExpansion)
 
             // WHEN split shade is not enabled and QS is expanded
@@ -409,7 +409,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun shadeExpansionWhenNotInSplitShadeAndQsCollapsed() =
-        testScope.runTest {
+        testComponent.runTest {
             val actual by collectLastValue(underTest.shadeExpansion)
 
             // WHEN split shade is not enabled and QS is expanded
@@ -423,7 +423,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun anyExpansion_shadeGreater() =
-        testScope.runTest() {
+        testComponent.runTest() {
             // WHEN shade is more expanded than QS
             shadeRepository.setLegacyShadeExpansion(.5f)
             shadeRepository.setQsExpansion(0f)
@@ -435,7 +435,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun anyExpansion_qsGreater() =
-        testScope.runTest() {
+        testComponent.runTest() {
             // WHEN qs is more expanded than shade
             shadeRepository.setLegacyShadeExpansion(0f)
             shadeRepository.setQsExpansion(.5f)
@@ -447,7 +447,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun lockscreenShadeExpansion_idle_onScene() =
-        testScope.runTest() {
+        testComponent.runTest() {
             // GIVEN an expansion flow based on transitions to and from a scene
             val key = SceneKey.Shade
             val expansion = underTest.sceneBasedExpansion(sceneInteractor, key)
@@ -464,7 +464,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun lockscreenShadeExpansion_idle_onDifferentScene() =
-        testScope.runTest() {
+        testComponent.runTest() {
             // GIVEN an expansion flow based on transitions to and from a scene
             val expansion = underTest.sceneBasedExpansion(sceneInteractor, SceneKey.Shade)
             val expansionAmount by collectLastValue(expansion)
@@ -482,7 +482,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun lockscreenShadeExpansion_transitioning_toScene() =
-        testScope.runTest() {
+        testComponent.runTest() {
             // GIVEN an expansion flow based on transitions to and from a scene
             val key = SceneKey.QuickSettings
             val expansion = underTest.sceneBasedExpansion(sceneInteractor, key)
@@ -520,7 +520,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun lockscreenShadeExpansion_transitioning_fromScene() =
-        testScope.runTest() {
+        testComponent.runTest() {
             // GIVEN an expansion flow based on transitions to and from a scene
             val key = SceneKey.QuickSettings
             val expansion = underTest.sceneBasedExpansion(sceneInteractor, key)
@@ -558,7 +558,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun lockscreenShadeExpansion_transitioning_toAndFromDifferentScenes() =
-        testScope.runTest() {
+        testComponent.runTest() {
             // GIVEN an expansion flow based on transitions to and from a scene
             val expansion = underTest.sceneBasedExpansion(sceneInteractor, SceneKey.QuickSettings)
             val expansionAmount by collectLastValue(expansion)
@@ -595,7 +595,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun userInteractingWithShade_shadeDraggedUpAndDown() =
-        testScope.runTest() {
+        testComponent.runTest() {
             val actual by collectLastValue(underTest.isUserInteractingWithShade)
             // GIVEN shade collapsed and not tracking input
             shadeRepository.setLegacyShadeExpansion(0f)
@@ -651,7 +651,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun userInteractingWithShade_shadeExpanded() =
-        testScope.runTest() {
+        testComponent.runTest() {
             val actual by collectLastValue(underTest.isUserInteractingWithShade)
             // GIVEN shade collapsed and not tracking input
             shadeRepository.setLegacyShadeExpansion(0f)
@@ -686,7 +686,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun userInteractingWithShade_shadePartiallyExpanded() =
-        testScope.runTest() {
+        testComponent.runTest() {
             val actual by collectLastValue(underTest.isUserInteractingWithShade)
             // GIVEN shade collapsed and not tracking input
             shadeRepository.setLegacyShadeExpansion(0f)
@@ -727,7 +727,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun userInteractingWithShade_shadeCollapsed() =
-        testScope.runTest() {
+        testComponent.runTest() {
             val actual by collectLastValue(underTest.isUserInteractingWithShade)
             // GIVEN shade expanded and not tracking input
             shadeRepository.setLegacyShadeExpansion(1f)
@@ -762,7 +762,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun userInteractingWithQs_qsDraggedUpAndDown() =
-        testScope.runTest() {
+        testComponent.runTest() {
             val actual by collectLastValue(underTest.isUserInteractingWithQs)
             // GIVEN qs collapsed and not tracking input
             shadeRepository.setQsExpansion(0f)
@@ -817,7 +817,7 @@ class ShadeInteractorTest : SysuiTestCase() {
         }
     @Test
     fun userInteracting_idle() =
-        testScope.runTest() {
+        testComponent.runTest() {
             // GIVEN an interacting flow based on transitions to and from a scene
             val key = SceneKey.Shade
             val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
@@ -834,7 +834,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun userInteracting_transitioning_toScene_programmatic() =
-        testScope.runTest() {
+        testComponent.runTest() {
             // GIVEN an interacting flow based on transitions to and from a scene
             val key = SceneKey.QuickSettings
             val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
@@ -872,7 +872,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun userInteracting_transitioning_toScene_userInputDriven() =
-        testScope.runTest() {
+        testComponent.runTest() {
             // GIVEN an interacting flow based on transitions to and from a scene
             val key = SceneKey.QuickSettings
             val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
@@ -910,7 +910,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun userInteracting_transitioning_fromScene_programmatic() =
-        testScope.runTest() {
+        testComponent.runTest() {
             // GIVEN an interacting flow based on transitions to and from a scene
             val key = SceneKey.QuickSettings
             val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
@@ -948,7 +948,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun userInteracting_transitioning_fromScene_userInputDriven() =
-        testScope.runTest() {
+        testComponent.runTest() {
             // GIVEN an interacting flow based on transitions to and from a scene
             val key = SceneKey.QuickSettings
             val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
@@ -986,7 +986,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun userInteracting_transitioning_toAndFromDifferentScenes() =
-        testScope.runTest() {
+        testComponent.runTest() {
             // GIVEN an interacting flow based on transitions to and from a scene
             val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, SceneKey.Shade)
             val interacting by collectLastValue(interactingFlow)
@@ -1011,7 +1011,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun isShadeTouchable_isFalse_whenFrpIsActive() =
-        testScope.runTest {
+        testComponent.runTest {
             deviceProvisioningRepository.setFactoryResetProtectionActive(true)
             keyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
@@ -1025,7 +1025,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun isShadeTouchable_isFalse_whenDeviceAsleepAndNotPulsing() =
-        testScope.runTest {
+        testComponent.runTest {
             powerRepository.updateWakefulness(
                 rawState = WakefulnessState.ASLEEP,
                 lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -1052,7 +1052,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun isShadeTouchable_isTrue_whenDeviceAsleepAndPulsing() =
-        testScope.runTest {
+        testComponent.runTest {
             powerRepository.updateWakefulness(
                 rawState = WakefulnessState.ASLEEP,
                 lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -1079,7 +1079,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun isShadeTouchable_isFalse_whenStartingToSleepAndNotControlScreenOff() =
-        testScope.runTest {
+        testComponent.runTest {
             powerRepository.updateWakefulness(
                 rawState = WakefulnessState.STARTING_TO_SLEEP,
                 lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -1101,7 +1101,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun isShadeTouchable_isTrue_whenStartingToSleepAndControlScreenOff() =
-        testScope.runTest {
+        testComponent.runTest {
             powerRepository.updateWakefulness(
                 rawState = WakefulnessState.STARTING_TO_SLEEP,
                 lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -1123,7 +1123,7 @@ class ShadeInteractorTest : SysuiTestCase() {
 
     @Test
     fun isShadeTouchable_isTrue_whenNotAsleep() =
-        testScope.runTest {
+        testComponent.runTest {
             powerRepository.updateWakefulness(
                 rawState = WakefulnessState.AWAKE,
                 lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -1138,38 +1138,4 @@ class ShadeInteractorTest : SysuiTestCase() {
             runCurrent()
             assertThat(isShadeTouchable).isTrue()
         }
-
-    @SysUISingleton
-    @Component(
-        modules =
-            [
-                SysUITestModule::class,
-                UserDomainLayerModule::class,
-            ]
-    )
-    interface TestComponent {
-
-        val underTest: ShadeInteractor
-
-        val configurationRepository: FakeConfigurationRepository
-        val deviceProvisioningRepository: FakeDeviceProvisioningRepository
-        val disableFlagsRepository: FakeDisableFlagsRepository
-        val keyguardRepository: FakeKeyguardRepository
-        val keygaurdTransitionRepository: FakeKeyguardTransitionRepository
-        val powerRepository: FakePowerRepository
-        val sceneInteractor: SceneInteractor
-        val shadeRepository: FakeShadeRepository
-        val testScope: TestScope
-        val userRepository: FakeUserRepository
-        val userSetupRepository: FakeUserSetupRepository
-
-        @Component.Factory
-        interface Factory {
-            fun create(
-                @BindsInstance test: SysuiTestCase,
-                featureFlags: FakeFeatureFlagsClassicModule,
-                mocks: TestMocksModule,
-            ): TestComponent
-        }
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/data/repository/NotificationsKeyguardViewStateRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/data/repository/NotificationsKeyguardViewStateRepositoryTest.kt
index 2f8f3bb14ee5fb016035560c4ce015b2a6a3d186..d47993793fc08616667b5fcaebf3db496df99cee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/data/repository/NotificationsKeyguardViewStateRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/data/repository/NotificationsKeyguardViewStateRepositoryTest.kt
@@ -13,14 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@file:OptIn(ExperimentalCoroutinesApi::class)
 
 package com.android.systemui.statusbar.notification.data.repository
 
 import androidx.test.filters.SmallTest
+import com.android.SysUITestComponent
 import com.android.SysUITestModule
+import com.android.collectLastValue
+import com.android.runCurrent
+import com.android.runTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
 import com.android.systemui.util.mockito.whenever
@@ -28,75 +30,59 @@ import com.android.systemui.util.mockito.withArgCaptor
 import com.google.common.truth.Truth.assertThat
 import dagger.BindsInstance
 import dagger.Component
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.runCurrent
-import kotlinx.coroutines.test.runTest
 import org.junit.Test
 import org.mockito.Mockito.verify
 
 @SmallTest
 class NotificationsKeyguardViewStateRepositoryTest : SysuiTestCase() {
 
+    @SysUISingleton
+    @Component(modules = [SysUITestModule::class])
+    interface TestComponent : SysUITestComponent<NotificationsKeyguardViewStateRepositoryImpl> {
+
+        val mockWakeUpCoordinator: NotificationWakeUpCoordinator
+
+        @Component.Factory
+        interface Factory {
+            fun create(
+                @BindsInstance test: SysuiTestCase,
+            ): TestComponent
+        }
+    }
+
     private val testComponent: TestComponent =
         DaggerNotificationsKeyguardViewStateRepositoryTest_TestComponent.factory()
             .create(test = this)
 
     @Test
     fun areNotifsFullyHidden_reflectsWakeUpCoordinator() =
-        with(testComponent) {
-            testScope.runTest {
-                whenever(mockWakeUpCoordinator.notificationsFullyHidden).thenReturn(false)
-                val notifsFullyHidden by collectLastValue(underTest.areNotificationsFullyHidden)
-                runCurrent()
+        testComponent.runTest {
+            whenever(mockWakeUpCoordinator.notificationsFullyHidden).thenReturn(false)
+            val notifsFullyHidden by collectLastValue(underTest.areNotificationsFullyHidden)
+            runCurrent()
 
-                assertThat(notifsFullyHidden).isFalse()
+            assertThat(notifsFullyHidden).isFalse()
 
-                withArgCaptor { verify(mockWakeUpCoordinator).addListener(capture()) }
-                    .onFullyHiddenChanged(true)
-                runCurrent()
+            withArgCaptor { verify(mockWakeUpCoordinator).addListener(capture()) }
+                .onFullyHiddenChanged(true)
+            runCurrent()
 
-                assertThat(notifsFullyHidden).isTrue()
-            }
+            assertThat(notifsFullyHidden).isTrue()
         }
 
     @Test
     fun isPulseExpanding_reflectsWakeUpCoordinator() =
-        with(testComponent) {
-            testScope.runTest {
-                whenever(mockWakeUpCoordinator.isPulseExpanding()).thenReturn(false)
-                val isPulseExpanding by collectLastValue(underTest.isPulseExpanding)
-                runCurrent()
+        testComponent.runTest {
+            whenever(mockWakeUpCoordinator.isPulseExpanding()).thenReturn(false)
+            val isPulseExpanding by collectLastValue(underTest.isPulseExpanding)
+            runCurrent()
 
-                assertThat(isPulseExpanding).isFalse()
+            assertThat(isPulseExpanding).isFalse()
 
-                withArgCaptor { verify(mockWakeUpCoordinator).addListener(capture()) }
-                    .onPulseExpansionChanged(true)
-                runCurrent()
+            withArgCaptor { verify(mockWakeUpCoordinator).addListener(capture()) }
+                .onPulseExpansionChanged(true)
+            runCurrent()
 
-                assertThat(isPulseExpanding).isTrue()
-            }
+            assertThat(isPulseExpanding).isTrue()
         }
-
-    @SysUISingleton
-    @Component(
-        modules =
-            [
-                SysUITestModule::class,
-            ]
-    )
-    interface TestComponent {
-
-        val underTest: NotificationsKeyguardViewStateRepositoryImpl
-
-        val mockWakeUpCoordinator: NotificationWakeUpCoordinator
-        val testScope: TestScope
-
-        @Component.Factory
-        interface Factory {
-            fun create(
-                @BindsInstance test: SysuiTestCase,
-            ): TestComponent
-        }
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt
index 683d0aa33d4ae7b2e08e3c709a62ac644562e944..707026e4200976d3b71a3acf12b6a1635e595085 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt
@@ -16,6 +16,7 @@ package com.android.systemui.statusbar.notification.domain.interactor
 
 import android.app.StatusBarManager
 import androidx.test.filters.SmallTest
+import com.android.SysUITestComponent
 import com.android.SysUITestModule
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dagger.SysUISingleton
@@ -31,8 +32,7 @@ class NotificationAlertsInteractorTest : SysuiTestCase() {
 
     @Component(modules = [SysUITestModule::class])
     @SysUISingleton
-    interface TestComponent {
-        val underTest: NotificationAlertsInteractor
+    interface TestComponent : SysUITestComponent<NotificationAlertsInteractor> {
         val disableFlags: FakeDisableFlagsRepository
 
         @Component.Factory
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractorTest.kt
index 705a5a3f9792fb4c9b7306739c1eeb48a898ed38..bb6f1b6a2850cf971ed973c2bf85bb6b23735f9c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationsKeyguardInteractorTest.kt
@@ -14,7 +14,11 @@
 package com.android.systemui.statusbar.notification.domain.interactor
 
 import androidx.test.filters.SmallTest
+import com.android.SysUITestComponent
 import com.android.SysUITestModule
+import com.android.collectLastValue
+import com.android.runCurrent
+import com.android.runTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.dagger.SysUISingleton
@@ -22,7 +26,6 @@ import com.android.systemui.statusbar.notification.data.repository.FakeNotificat
 import com.google.common.truth.Truth.assertThat
 import dagger.BindsInstance
 import dagger.Component
-import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Test
@@ -30,60 +33,48 @@ import org.junit.Test
 @SmallTest
 class NotificationsKeyguardInteractorTest : SysuiTestCase() {
 
+    @SysUISingleton
+    @Component(modules = [SysUITestModule::class])
+    interface TestComponent : SysUITestComponent<NotificationsKeyguardInteractor> {
+
+        val repository: FakeNotificationsKeyguardViewStateRepository
+
+        @Component.Factory
+        interface Factory {
+            fun create(@BindsInstance test: SysuiTestCase): TestComponent
+        }
+    }
+
     private val testComponent: TestComponent =
         DaggerNotificationsKeyguardInteractorTest_TestComponent.factory().create(test = this)
 
     @Test
     fun areNotifsFullyHidden_reflectsRepository() =
-        with(testComponent) {
-            testScope.runTest {
-                repository.setNotificationsFullyHidden(false)
-                val notifsFullyHidden by collectLastValue(underTest.areNotificationsFullyHidden)
-                runCurrent()
+        testComponent.runTest {
+            repository.setNotificationsFullyHidden(false)
+            val notifsFullyHidden by collectLastValue(underTest.areNotificationsFullyHidden)
+            runCurrent()
 
-                assertThat(notifsFullyHidden).isFalse()
+            assertThat(notifsFullyHidden).isFalse()
 
-                repository.setNotificationsFullyHidden(true)
-                runCurrent()
+            repository.setNotificationsFullyHidden(true)
+            runCurrent()
 
-                assertThat(notifsFullyHidden).isTrue()
-            }
+            assertThat(notifsFullyHidden).isTrue()
         }
 
     @Test
     fun isPulseExpanding_reflectsRepository() =
-        with(testComponent) {
-            testScope.runTest {
-                repository.setPulseExpanding(false)
-                val isPulseExpanding by collectLastValue(underTest.isPulseExpanding)
-                runCurrent()
+        testComponent.runTest {
+            repository.setPulseExpanding(false)
+            val isPulseExpanding by collectLastValue(underTest.isPulseExpanding)
+            runCurrent()
 
-                assertThat(isPulseExpanding).isFalse()
+            assertThat(isPulseExpanding).isFalse()
 
-                repository.setPulseExpanding(true)
-                runCurrent()
+            repository.setPulseExpanding(true)
+            runCurrent()
 
-                assertThat(isPulseExpanding).isTrue()
-            }
+            assertThat(isPulseExpanding).isTrue()
         }
-
-    @SysUISingleton
-    @Component(
-        modules =
-            [
-                SysUITestModule::class,
-            ]
-    )
-    interface TestComponent {
-
-        val underTest: NotificationsKeyguardInteractor
-
-        val repository: FakeNotificationsKeyguardViewStateRepository
-        val testScope: TestScope
-
-        @Component.Factory
-        interface Factory {
-            fun create(@BindsInstance test: SysuiTestCase): TestComponent
-        }
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt
index f8252a721b32fe463e23a856800afc3726f3b13c..05deb1cc75c799f46053391257c2dfc29afc85e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/domain/interactor/NotificationIconsInteractorTest.kt
@@ -17,10 +17,12 @@ package com.android.systemui.statusbar.notification.icon.domain.interactor
 
 import android.testing.AndroidTestingRunner
 import androidx.test.filters.SmallTest
+import com.android.SysUITestComponent
 import com.android.SysUITestModule
 import com.android.TestMocksModule
+import com.android.collectLastValue
+import com.android.runTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository
 import com.android.systemui.statusbar.data.repository.NotificationListenerSettingsRepository
@@ -43,8 +45,6 @@ import com.google.common.truth.Truth.assertThat
 import dagger.BindsInstance
 import dagger.Component
 import java.util.Optional
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -57,12 +57,10 @@ class NotificationIconsInteractorTest : SysuiTestCase() {
 
     @Component(modules = [SysUITestModule::class])
     @SysUISingleton
-    interface TestComponent {
-        val underTest: NotificationIconsInteractor
+    interface TestComponent : SysUITestComponent<NotificationIconsInteractor> {
 
         val activeNotificationListRepository: ActiveNotificationListRepository
         val keyguardViewStateRepository: FakeNotificationsKeyguardViewStateRepository
-        val testScope: TestScope
 
         @Component.Factory
         interface Factory {
@@ -75,97 +73,78 @@ class NotificationIconsInteractorTest : SysuiTestCase() {
             .create(test = this, mocks = TestMocksModule(bubbles = Optional.of(bubbles)))
 
     @Before
-    fun setup() =
-        with(testComponent) {
+    fun setup() {
+        testComponent.apply {
             activeNotificationListRepository.activeNotifications.value =
                 ActiveNotificationsStore.Builder()
                     .apply { testIcons.forEach(::addIndividualNotif) }
                     .build()
         }
+    }
 
     @Test
     fun filteredEntrySet() =
-        with(testComponent) {
-            testScope.runTest {
-                val filteredSet by collectLastValue(underTest.filteredNotifSet())
-                assertThat(filteredSet).containsExactlyElementsIn(testIcons)
-            }
+        testComponent.runTest {
+            val filteredSet by collectLastValue(underTest.filteredNotifSet())
+            assertThat(filteredSet).containsExactlyElementsIn(testIcons)
         }
 
     @Test
     fun filteredEntrySet_noExpandedBubbles() =
-        with(testComponent) {
-            testScope.runTest {
-                whenever(bubbles.isBubbleExpanded(eq("notif1"))).thenReturn(true)
-                val filteredSet by collectLastValue(underTest.filteredNotifSet())
-                assertThat(filteredSet).comparingElementsUsing(byKey).doesNotContain("notif1")
-            }
+        testComponent.runTest {
+            whenever(bubbles.isBubbleExpanded(eq("notif1"))).thenReturn(true)
+            val filteredSet by collectLastValue(underTest.filteredNotifSet())
+            assertThat(filteredSet).comparingElementsUsing(byKey).doesNotContain("notif1")
         }
 
     @Test
     fun filteredEntrySet_noAmbient() =
-        with(testComponent) {
-            testScope.runTest {
-                val filteredSet by collectLastValue(underTest.filteredNotifSet(showAmbient = false))
-                assertThat(filteredSet).comparingElementsUsing(byIsAmbient).doesNotContain(true)
-                assertThat(filteredSet)
-                    .comparingElementsUsing(byIsSuppressedFromStatusBar)
-                    .doesNotContain(true)
-            }
+        testComponent.runTest {
+            val filteredSet by collectLastValue(underTest.filteredNotifSet(showAmbient = false))
+            assertThat(filteredSet).comparingElementsUsing(byIsAmbient).doesNotContain(true)
+            assertThat(filteredSet)
+                .comparingElementsUsing(byIsSuppressedFromStatusBar)
+                .doesNotContain(true)
         }
 
     @Test
     fun filteredEntrySet_noLowPriority() =
-        with(testComponent) {
-            testScope.runTest {
-                val filteredSet by
-                    collectLastValue(underTest.filteredNotifSet(showLowPriority = false))
-                assertThat(filteredSet).comparingElementsUsing(byIsSilent).doesNotContain(true)
-            }
+        testComponent.runTest {
+            val filteredSet by collectLastValue(underTest.filteredNotifSet(showLowPriority = false))
+            assertThat(filteredSet).comparingElementsUsing(byIsSilent).doesNotContain(true)
         }
 
     @Test
     fun filteredEntrySet_noDismissed() =
-        with(testComponent) {
-            testScope.runTest {
-                val filteredSet by
-                    collectLastValue(underTest.filteredNotifSet(showDismissed = false))
-                assertThat(filteredSet)
-                    .comparingElementsUsing(byIsRowDismissed)
-                    .doesNotContain(true)
-            }
+        testComponent.runTest {
+            val filteredSet by collectLastValue(underTest.filteredNotifSet(showDismissed = false))
+            assertThat(filteredSet).comparingElementsUsing(byIsRowDismissed).doesNotContain(true)
         }
 
     @Test
     fun filteredEntrySet_noRepliedMessages() =
-        with(testComponent) {
-            testScope.runTest {
-                val filteredSet by
-                    collectLastValue(underTest.filteredNotifSet(showRepliedMessages = false))
-                assertThat(filteredSet)
-                    .comparingElementsUsing(byIsLastMessageFromReply)
-                    .doesNotContain(true)
-            }
+        testComponent.runTest {
+            val filteredSet by
+                collectLastValue(underTest.filteredNotifSet(showRepliedMessages = false))
+            assertThat(filteredSet)
+                .comparingElementsUsing(byIsLastMessageFromReply)
+                .doesNotContain(true)
         }
 
     @Test
     fun filteredEntrySet_noPulsing_notifsNotFullyHidden() =
-        with(testComponent) {
-            testScope.runTest {
-                val filteredSet by collectLastValue(underTest.filteredNotifSet(showPulsing = false))
-                keyguardViewStateRepository.setNotificationsFullyHidden(false)
-                assertThat(filteredSet).comparingElementsUsing(byIsPulsing).doesNotContain(true)
-            }
+        testComponent.runTest {
+            val filteredSet by collectLastValue(underTest.filteredNotifSet(showPulsing = false))
+            keyguardViewStateRepository.setNotificationsFullyHidden(false)
+            assertThat(filteredSet).comparingElementsUsing(byIsPulsing).doesNotContain(true)
         }
 
     @Test
     fun filteredEntrySet_noPulsing_notifsFullyHidden() =
-        with(testComponent) {
-            testScope.runTest {
-                val filteredSet by collectLastValue(underTest.filteredNotifSet(showPulsing = false))
-                keyguardViewStateRepository.setNotificationsFullyHidden(true)
-                assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true)
-            }
+        testComponent.runTest {
+            val filteredSet by collectLastValue(underTest.filteredNotifSet(showPulsing = false))
+            keyguardViewStateRepository.setNotificationsFullyHidden(true)
+            assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true)
         }
 }
 
@@ -177,13 +156,11 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() {
 
     @Component(modules = [SysUITestModule::class])
     @SysUISingleton
-    interface TestComponent {
-        val underTest: AlwaysOnDisplayNotificationIconsInteractor
+    interface TestComponent : SysUITestComponent<AlwaysOnDisplayNotificationIconsInteractor> {
 
         val activeNotificationListRepository: ActiveNotificationListRepository
         val deviceEntryRepository: FakeDeviceEntryRepository
         val keyguardViewStateRepository: FakeNotificationsKeyguardViewStateRepository
-        val testScope: TestScope
 
         @Component.Factory
         interface Factory {
@@ -191,105 +168,88 @@ class AlwaysOnDisplayNotificationIconsInteractorTest : SysuiTestCase() {
         }
     }
 
-    val testComponent: TestComponent =
+    private val testComponent: TestComponent =
         DaggerAlwaysOnDisplayNotificationIconsInteractorTest_TestComponent.factory()
             .create(test = this, mocks = TestMocksModule(bubbles = Optional.of(bubbles)))
 
     @Before
-    fun setup() =
-        with(testComponent) {
+    fun setup() {
+        testComponent.apply {
             activeNotificationListRepository.activeNotifications.value =
                 ActiveNotificationsStore.Builder()
                     .apply { testIcons.forEach(::addIndividualNotif) }
                     .build()
         }
+    }
 
     @Test
     fun filteredEntrySet_noExpandedBubbles() =
-        with(testComponent) {
-            testScope.runTest {
-                whenever(bubbles.isBubbleExpanded(eq("notif1"))).thenReturn(true)
-                val filteredSet by collectLastValue(underTest.aodNotifs)
-                assertThat(filteredSet).comparingElementsUsing(byKey).doesNotContain("notif1")
-            }
+        testComponent.runTest {
+            whenever(bubbles.isBubbleExpanded(eq("notif1"))).thenReturn(true)
+            val filteredSet by collectLastValue(underTest.aodNotifs)
+            assertThat(filteredSet).comparingElementsUsing(byKey).doesNotContain("notif1")
         }
 
     @Test
     fun filteredEntrySet_noAmbient() =
-        with(testComponent) {
-            testScope.runTest {
-                val filteredSet by collectLastValue(underTest.aodNotifs)
-                assertThat(filteredSet).comparingElementsUsing(byIsAmbient).doesNotContain(true)
-                assertThat(filteredSet)
-                    .comparingElementsUsing(byIsSuppressedFromStatusBar)
-                    .doesNotContain(true)
-            }
+        testComponent.runTest {
+            val filteredSet by collectLastValue(underTest.aodNotifs)
+            assertThat(filteredSet).comparingElementsUsing(byIsAmbient).doesNotContain(true)
+            assertThat(filteredSet)
+                .comparingElementsUsing(byIsSuppressedFromStatusBar)
+                .doesNotContain(true)
         }
 
     @Test
     fun filteredEntrySet_noDismissed() =
-        with(testComponent) {
-            testScope.runTest {
-                val filteredSet by collectLastValue(underTest.aodNotifs)
-                assertThat(filteredSet)
-                    .comparingElementsUsing(byIsRowDismissed)
-                    .doesNotContain(true)
-            }
+        testComponent.runTest {
+            val filteredSet by collectLastValue(underTest.aodNotifs)
+            assertThat(filteredSet).comparingElementsUsing(byIsRowDismissed).doesNotContain(true)
         }
 
     @Test
     fun filteredEntrySet_noRepliedMessages() =
-        with(testComponent) {
-            testScope.runTest {
-                val filteredSet by collectLastValue(underTest.aodNotifs)
-                assertThat(filteredSet)
-                    .comparingElementsUsing(byIsLastMessageFromReply)
-                    .doesNotContain(true)
-            }
+        testComponent.runTest {
+            val filteredSet by collectLastValue(underTest.aodNotifs)
+            assertThat(filteredSet)
+                .comparingElementsUsing(byIsLastMessageFromReply)
+                .doesNotContain(true)
         }
 
     @Test
     fun filteredEntrySet_showPulsing_notifsNotFullyHidden_bypassDisabled() =
-        with(testComponent) {
-            testScope.runTest {
-                val filteredSet by collectLastValue(underTest.aodNotifs)
-                deviceEntryRepository.setBypassEnabled(false)
-                keyguardViewStateRepository.setNotificationsFullyHidden(false)
-                assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true)
-            }
+        testComponent.runTest {
+            val filteredSet by collectLastValue(underTest.aodNotifs)
+            deviceEntryRepository.setBypassEnabled(false)
+            keyguardViewStateRepository.setNotificationsFullyHidden(false)
+            assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true)
         }
 
     @Test
     fun filteredEntrySet_showPulsing_notifsFullyHidden_bypassDisabled() =
-        with(testComponent) {
-            testScope.runTest {
-                val filteredSet by collectLastValue(underTest.aodNotifs)
-                deviceEntryRepository.setBypassEnabled(false)
-                keyguardViewStateRepository.setNotificationsFullyHidden(true)
-                assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true)
-            }
+        testComponent.runTest {
+            val filteredSet by collectLastValue(underTest.aodNotifs)
+            deviceEntryRepository.setBypassEnabled(false)
+            keyguardViewStateRepository.setNotificationsFullyHidden(true)
+            assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true)
         }
 
     @Test
     fun filteredEntrySet_noPulsing_notifsNotFullyHidden_bypassEnabled() =
-        with(testComponent) {
-            testScope.runTest {
-                val filteredSet by collectLastValue(underTest.aodNotifs)
-                deviceEntryRepository.setBypassEnabled(true)
-                keyguardViewStateRepository.setNotificationsFullyHidden(false)
-                assertThat(filteredSet).comparingElementsUsing(byIsPulsing).doesNotContain(true)
-            }
+        testComponent.runTest {
+            val filteredSet by collectLastValue(underTest.aodNotifs)
+            deviceEntryRepository.setBypassEnabled(true)
+            keyguardViewStateRepository.setNotificationsFullyHidden(false)
+            assertThat(filteredSet).comparingElementsUsing(byIsPulsing).doesNotContain(true)
         }
 
     @Test
     fun filteredEntrySet_showPulsing_notifsFullyHidden_bypassEnabled() =
-        with(testComponent) {
-            testScope.runTest {
-                val filteredSet by collectLastValue(underTest.aodNotifs)
-                deviceEntryRepository.setBypassEnabled(true)
-                keyguardViewStateRepository.setNotificationsFullyHidden(true)
-                assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true)
-            }
+        testComponent.runTest {
+            val filteredSet by collectLastValue(underTest.aodNotifs)
+            deviceEntryRepository.setBypassEnabled(true)
+            keyguardViewStateRepository.setNotificationsFullyHidden(true)
+            assertThat(filteredSet).comparingElementsUsing(byIsPulsing).contains(true)
         }
 }
 
@@ -301,13 +261,11 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() {
 
     @Component(modules = [SysUITestModule::class])
     @SysUISingleton
-    interface TestComponent {
-        val underTest: StatusBarNotificationIconsInteractor
+    interface TestComponent : SysUITestComponent<StatusBarNotificationIconsInteractor> {
 
         val activeNotificationListRepository: ActiveNotificationListRepository
         val keyguardViewStateRepository: FakeNotificationsKeyguardViewStateRepository
         val notificationListenerSettingsRepository: NotificationListenerSettingsRepository
-        val testScope: TestScope
 
         @Component.Factory
         interface Factory {
@@ -320,76 +278,63 @@ class StatusBarNotificationIconsInteractorTest : SysuiTestCase() {
             .create(test = this, mocks = TestMocksModule(bubbles = Optional.of(bubbles)))
 
     @Before
-    fun setup() =
-        with(testComponent) {
+    fun setup() {
+        testComponent.apply {
             activeNotificationListRepository.activeNotifications.value =
                 ActiveNotificationsStore.Builder()
                     .apply { testIcons.forEach(::addIndividualNotif) }
                     .build()
         }
+    }
 
     @Test
     fun filteredEntrySet_noExpandedBubbles() =
-        with(testComponent) {
-            testScope.runTest {
-                whenever(bubbles.isBubbleExpanded(eq("notif1"))).thenReturn(true)
-                val filteredSet by collectLastValue(underTest.statusBarNotifs)
-                assertThat(filteredSet).comparingElementsUsing(byKey).doesNotContain("notif1")
-            }
+        testComponent.runTest {
+            whenever(bubbles.isBubbleExpanded(eq("notif1"))).thenReturn(true)
+            val filteredSet by collectLastValue(underTest.statusBarNotifs)
+            assertThat(filteredSet).comparingElementsUsing(byKey).doesNotContain("notif1")
         }
 
     @Test
     fun filteredEntrySet_noAmbient() =
-        with(testComponent) {
-            testScope.runTest {
-                val filteredSet by collectLastValue(underTest.statusBarNotifs)
-                assertThat(filteredSet).comparingElementsUsing(byIsAmbient).doesNotContain(true)
-                assertThat(filteredSet)
-                    .comparingElementsUsing(byIsSuppressedFromStatusBar)
-                    .doesNotContain(true)
-            }
+        testComponent.runTest {
+            val filteredSet by collectLastValue(underTest.statusBarNotifs)
+            assertThat(filteredSet).comparingElementsUsing(byIsAmbient).doesNotContain(true)
+            assertThat(filteredSet)
+                .comparingElementsUsing(byIsSuppressedFromStatusBar)
+                .doesNotContain(true)
         }
 
     @Test
     fun filteredEntrySet_noLowPriority_whenDontShowSilentIcons() =
-        with(testComponent) {
-            testScope.runTest {
-                val filteredSet by collectLastValue(underTest.statusBarNotifs)
-                notificationListenerSettingsRepository.showSilentStatusIcons.value = false
-                assertThat(filteredSet).comparingElementsUsing(byIsSilent).doesNotContain(true)
-            }
+        testComponent.runTest {
+            val filteredSet by collectLastValue(underTest.statusBarNotifs)
+            notificationListenerSettingsRepository.showSilentStatusIcons.value = false
+            assertThat(filteredSet).comparingElementsUsing(byIsSilent).doesNotContain(true)
         }
 
     @Test
     fun filteredEntrySet_showLowPriority_whenShowSilentIcons() =
-        with(testComponent) {
-            testScope.runTest {
-                val filteredSet by collectLastValue(underTest.statusBarNotifs)
-                notificationListenerSettingsRepository.showSilentStatusIcons.value = true
-                assertThat(filteredSet).comparingElementsUsing(byIsSilent).contains(true)
-            }
+        testComponent.runTest {
+            val filteredSet by collectLastValue(underTest.statusBarNotifs)
+            notificationListenerSettingsRepository.showSilentStatusIcons.value = true
+            assertThat(filteredSet).comparingElementsUsing(byIsSilent).contains(true)
         }
 
     @Test
     fun filteredEntrySet_noDismissed() =
-        with(testComponent) {
-            testScope.runTest {
-                val filteredSet by collectLastValue(underTest.statusBarNotifs)
-                assertThat(filteredSet)
-                    .comparingElementsUsing(byIsRowDismissed)
-                    .doesNotContain(true)
-            }
+        testComponent.runTest {
+            val filteredSet by collectLastValue(underTest.statusBarNotifs)
+            assertThat(filteredSet).comparingElementsUsing(byIsRowDismissed).doesNotContain(true)
         }
 
     @Test
     fun filteredEntrySet_noRepliedMessages() =
-        with(testComponent) {
-            testScope.runTest {
-                val filteredSet by collectLastValue(underTest.statusBarNotifs)
-                assertThat(filteredSet)
-                    .comparingElementsUsing(byIsLastMessageFromReply)
-                    .doesNotContain(true)
-            }
+        testComponent.runTest {
+            val filteredSet by collectLastValue(underTest.statusBarNotifs)
+            assertThat(filteredSet)
+                .comparingElementsUsing(byIsLastMessageFromReply)
+                .doesNotContain(true)
         }
 }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt
index 49e1493f642f2ba095c76077b2abe65b5eb2e458..788cfbc47dd37e3498f1376aab31bbf924fc1f84 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerAlwaysOnDisplayViewModelTest.kt
@@ -13,17 +13,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@file:OptIn(ExperimentalCoroutinesApi::class)
 
 package com.android.systemui.statusbar.notification.icon.ui.viewmodel
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.SysUITestComponent
 import com.android.SysUITestModule
 import com.android.TestMocksModule
+import com.android.collectLastValue
+import com.android.runCurrent
+import com.android.runTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.biometrics.domain.BiometricsDomainLayerModule
-import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.flags.FakeFeatureFlagsClassicModule
 import com.android.systemui.flags.Flags
@@ -41,6 +43,7 @@ import com.android.systemui.statusbar.phone.DozeParameters
 import com.android.systemui.statusbar.phone.ScreenOffAnimationController
 import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository
 import com.android.systemui.user.domain.UserDomainLayerModule
+import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
 import com.android.systemui.util.ui.isAnimating
 import com.android.systemui.util.ui.stopAnimating
@@ -48,71 +51,78 @@ import com.android.systemui.util.ui.value
 import com.google.common.truth.Truth.assertThat
 import dagger.BindsInstance
 import dagger.Component
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.runCurrent
-import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.MockitoAnnotations
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
 
-    @Mock private lateinit var dozeParams: DozeParameters
-    @Mock private lateinit var screenOffAnimController: ScreenOffAnimationController
+    @SysUISingleton
+    @Component(
+        modules =
+            [
+                SysUITestModule::class,
+                BiometricsDomainLayerModule::class,
+                UserDomainLayerModule::class,
+            ]
+    )
+    interface TestComponent :
+        SysUITestComponent<NotificationIconContainerAlwaysOnDisplayViewModel> {
 
-    private lateinit var testComponent: TestComponent
-    private val underTest: NotificationIconContainerAlwaysOnDisplayViewModel
-        get() = testComponent.underTest
-    private val deviceProvisioningRepository: FakeDeviceProvisioningRepository
-        get() = testComponent.deviceProvisioningRepository
-    private val keyguardRepository: FakeKeyguardRepository
-        get() = testComponent.keyguardRepository
-    private val keyguardTransitionRepository: FakeKeyguardTransitionRepository
-        get() = testComponent.keyguardTransitionRepository
-    private val powerRepository: FakePowerRepository
-        get() = testComponent.powerRepository
-    private val scope: TestScope
-        get() = testComponent.scope
+        val deviceProvisioningRepository: FakeDeviceProvisioningRepository
+        val keyguardRepository: FakeKeyguardRepository
+        val keyguardTransitionRepository: FakeKeyguardTransitionRepository
+        val powerRepository: FakePowerRepository
 
-    @Before
-    fun setup() {
-        MockitoAnnotations.initMocks(this)
+        @Component.Factory
+        interface Factory {
+            fun create(
+                @BindsInstance test: SysuiTestCase,
+                mocks: TestMocksModule,
+                featureFlags: FakeFeatureFlagsClassicModule,
+            ): TestComponent
+        }
+    }
 
-        testComponent =
-            DaggerNotificationIconContainerAlwaysOnDisplayViewModelTest_TestComponent.factory()
-                .create(
-                    test = this,
-                    featureFlags =
-                        FakeFeatureFlagsClassicModule {
-                            setDefault(Flags.FACE_AUTH_REFACTOR)
-                            set(Flags.FULL_SCREEN_USER_SWITCHER, value = false)
-                            setDefault(Flags.NEW_AOD_TRANSITION)
-                        },
-                    mocks =
-                        TestMocksModule(
-                            dozeParameters = dozeParams,
-                            screenOffAnimationController = screenOffAnimController,
-                        ),
-                )
+    private val dozeParams: DozeParameters = mock()
+    private val screenOffAnimController: ScreenOffAnimationController = mock()
+
+    private val testComponent: TestComponent =
+        DaggerNotificationIconContainerAlwaysOnDisplayViewModelTest_TestComponent.factory()
+            .create(
+                test = this,
+                featureFlags =
+                    FakeFeatureFlagsClassicModule {
+                        setDefault(Flags.FACE_AUTH_REFACTOR)
+                        set(Flags.FULL_SCREEN_USER_SWITCHER, value = false)
+                        setDefault(Flags.NEW_AOD_TRANSITION)
+                    },
+                mocks =
+                    TestMocksModule(
+                        dozeParameters = dozeParams,
+                        screenOffAnimationController = screenOffAnimController,
+                    ),
+            )
 
-        keyguardRepository.setKeyguardShowing(true)
-        keyguardRepository.setKeyguardOccluded(false)
-        deviceProvisioningRepository.setFactoryResetProtectionActive(false)
-        powerRepository.updateWakefulness(
-            rawState = WakefulnessState.AWAKE,
-            lastWakeReason = WakeSleepReason.OTHER,
-            lastSleepReason = WakeSleepReason.OTHER,
-        )
+    @Before
+    fun setup() {
+        testComponent.apply {
+            keyguardRepository.setKeyguardShowing(true)
+            keyguardRepository.setKeyguardOccluded(false)
+            deviceProvisioningRepository.setFactoryResetProtectionActive(false)
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.AWAKE,
+                lastWakeReason = WakeSleepReason.OTHER,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+        }
     }
 
     @Test
     fun animationsEnabled_isFalse_whenFrpIsActive() =
-        scope.runTest {
+        testComponent.runTest {
             deviceProvisioningRepository.setFactoryResetProtectionActive(true)
             keyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
@@ -126,7 +136,7 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
 
     @Test
     fun animationsEnabled_isFalse_whenDeviceAsleepAndNotPulsing() =
-        scope.runTest {
+        testComponent.runTest {
             powerRepository.updateWakefulness(
                 rawState = WakefulnessState.ASLEEP,
                 lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -149,7 +159,7 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
 
     @Test
     fun animationsEnabled_isTrue_whenDeviceAsleepAndPulsing() =
-        scope.runTest {
+        testComponent.runTest {
             powerRepository.updateWakefulness(
                 rawState = WakefulnessState.ASLEEP,
                 lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -172,7 +182,7 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
 
     @Test
     fun animationsEnabled_isFalse_whenStartingToSleepAndNotControlScreenOff() =
-        scope.runTest {
+        testComponent.runTest {
             powerRepository.updateWakefulness(
                 rawState = WakefulnessState.STARTING_TO_SLEEP,
                 lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -193,7 +203,7 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
 
     @Test
     fun animationsEnabled_isTrue_whenStartingToSleepAndControlScreenOff() =
-        scope.runTest {
+        testComponent.runTest {
             powerRepository.updateWakefulness(
                 rawState = WakefulnessState.STARTING_TO_SLEEP,
                 lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -214,7 +224,7 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
 
     @Test
     fun animationsEnabled_isTrue_whenNotAsleep() =
-        scope.runTest {
+        testComponent.runTest {
             powerRepository.updateWakefulness(
                 rawState = WakefulnessState.AWAKE,
                 lastWakeReason = WakeSleepReason.POWER_BUTTON,
@@ -232,7 +242,7 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
 
     @Test
     fun animationsEnabled_isTrue_whenKeyguardIsShowing() =
-        scope.runTest {
+        testComponent.runTest {
             keyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
                     transitionState = TransitionState.STARTED,
@@ -261,7 +271,7 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
 
     @Test
     fun isDozing_startAodTransition() =
-        scope.runTest {
+        testComponent.runTest {
             val isDozing by collectLastValue(underTest.isDozing)
             runCurrent()
             keyguardTransitionRepository.sendTransitionStep(
@@ -278,7 +288,7 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
 
     @Test
     fun isDozing_startDozeTransition() =
-        scope.runTest {
+        testComponent.runTest {
             val isDozing by collectLastValue(underTest.isDozing)
             runCurrent()
             keyguardTransitionRepository.sendTransitionStep(
@@ -295,7 +305,7 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
 
     @Test
     fun isDozing_startDozeToAodTransition() =
-        scope.runTest {
+        testComponent.runTest {
             val isDozing by collectLastValue(underTest.isDozing)
             runCurrent()
             keyguardTransitionRepository.sendTransitionStep(
@@ -312,7 +322,7 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
 
     @Test
     fun isNotDozing_startAodToGoneTransition() =
-        scope.runTest {
+        testComponent.runTest {
             val isDozing by collectLastValue(underTest.isDozing)
             runCurrent()
             keyguardTransitionRepository.sendTransitionStep(
@@ -329,7 +339,7 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
 
     @Test
     fun isDozing_stopAnimation() =
-        scope.runTest {
+        testComponent.runTest {
             val isDozing by collectLastValue(underTest.isDozing)
             runCurrent()
             keyguardTransitionRepository.sendTransitionStep(
@@ -347,33 +357,4 @@ class NotificationIconContainerAlwaysOnDisplayViewModelTest : SysuiTestCase() {
 
             assertThat(isDozing?.isAnimating).isEqualTo(false)
         }
-
-    @SysUISingleton
-    @Component(
-        modules =
-            [
-                SysUITestModule::class,
-                BiometricsDomainLayerModule::class,
-                UserDomainLayerModule::class,
-            ]
-    )
-    interface TestComponent {
-
-        val underTest: NotificationIconContainerAlwaysOnDisplayViewModel
-
-        val deviceProvisioningRepository: FakeDeviceProvisioningRepository
-        val keyguardRepository: FakeKeyguardRepository
-        val keyguardTransitionRepository: FakeKeyguardTransitionRepository
-        val powerRepository: FakePowerRepository
-        val scope: TestScope
-
-        @Component.Factory
-        interface Factory {
-            fun create(
-                @BindsInstance test: SysuiTestCase,
-                mocks: TestMocksModule,
-                featureFlags: FakeFeatureFlagsClassicModule,
-            ): TestComponent
-        }
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
index 44acac8620ee69298bc4044b8da83a3733466a82..1a04a3ea291a592d7412ce4cb93d2a117c893f8a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/icon/ui/viewmodel/NotificationIconContainerStatusBarViewModelTest.kt
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@file:OptIn(ExperimentalCoroutinesApi::class)
 
 package com.android.systemui.statusbar.notification.icon.ui.viewmodel
 
@@ -21,11 +20,14 @@ import android.graphics.Rect
 import android.graphics.drawable.Icon
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.SysUITestComponent
 import com.android.SysUITestModule
 import com.android.TestMocksModule
+import com.android.collectLastValue
+import com.android.runCurrent
+import com.android.runTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.biometrics.domain.BiometricsDomainLayerModule
-import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.flags.FakeFeatureFlagsClassicModule
 import com.android.systemui.flags.Flags
@@ -57,373 +59,334 @@ import com.android.systemui.util.ui.value
 import com.google.common.truth.Truth.assertThat
 import dagger.BindsInstance
 import dagger.Component
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.runCurrent
-import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.MockitoAnnotations
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class NotificationIconContainerStatusBarViewModelTest : SysuiTestCase() {
 
-    @Mock lateinit var dozeParams: DozeParameters
+    @SysUISingleton
+    @Component(
+        modules =
+            [
+                SysUITestModule::class,
+                BiometricsDomainLayerModule::class,
+                UserDomainLayerModule::class,
+            ]
+    )
+    interface TestComponent : SysUITestComponent<NotificationIconContainerStatusBarViewModel> {
 
-    private lateinit var testComponent: TestComponent
+        val activeNotificationsRepository: ActiveNotificationListRepository
+        val darkIconRepository: FakeDarkIconRepository
+        val deviceProvisioningRepository: FakeDeviceProvisioningRepository
+        val headsUpViewStateRepository: HeadsUpNotificationIconViewStateRepository
+        val keyguardTransitionRepository: FakeKeyguardTransitionRepository
+        val keyguardRepository: FakeKeyguardRepository
+        val powerRepository: FakePowerRepository
+        val shadeRepository: FakeShadeRepository
+
+        @Component.Factory
+        interface Factory {
+            fun create(
+                @BindsInstance test: SysuiTestCase,
+                mocks: TestMocksModule,
+                featureFlags: FakeFeatureFlagsClassicModule,
+            ): TestComponent
+        }
+    }
+
+    private val dozeParams: DozeParameters = mock()
+
+    private val testComponent: TestComponent =
+        DaggerNotificationIconContainerStatusBarViewModelTest_TestComponent.factory()
+            .create(
+                test = this,
+                featureFlags =
+                    FakeFeatureFlagsClassicModule {
+                        setDefault(Flags.FACE_AUTH_REFACTOR)
+                        set(Flags.FULL_SCREEN_USER_SWITCHER, value = false)
+                    },
+                mocks =
+                    TestMocksModule(
+                        dozeParameters = dozeParams,
+                    ),
+            )
 
     @Before
     fun setup() {
-        MockitoAnnotations.initMocks(this)
-
-        testComponent =
-            DaggerNotificationIconContainerStatusBarViewModelTest_TestComponent.factory()
-                .create(
-                    test = this,
-                    featureFlags =
-                        FakeFeatureFlagsClassicModule {
-                            set(Flags.FACE_AUTH_REFACTOR, value = false)
-                            set(Flags.FULL_SCREEN_USER_SWITCHER, value = false)
-                        },
-                    mocks =
-                        TestMocksModule(
-                            dozeParameters = dozeParams,
-                        ),
-                )
-                .apply {
-                    keyguardRepository.setKeyguardShowing(false)
-                    deviceProvisioningRepository.setFactoryResetProtectionActive(false)
-                    powerRepository.updateWakefulness(
-                        rawState = WakefulnessState.AWAKE,
-                        lastWakeReason = WakeSleepReason.OTHER,
-                        lastSleepReason = WakeSleepReason.OTHER,
-                    )
-                }
+        testComponent.apply {
+            keyguardRepository.setKeyguardShowing(false)
+            deviceProvisioningRepository.setFactoryResetProtectionActive(false)
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.AWAKE,
+                lastWakeReason = WakeSleepReason.OTHER,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+        }
     }
 
     @Test
     fun animationsEnabled_isFalse_whenFrpIsActive() =
-        with(testComponent) {
-            scope.runTest {
-                deviceProvisioningRepository.setFactoryResetProtectionActive(true)
-                keyguardTransitionRepository.sendTransitionStep(
-                    TransitionStep(
-                        transitionState = TransitionState.STARTED,
-                    )
+        testComponent.runTest {
+            deviceProvisioningRepository.setFactoryResetProtectionActive(true)
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
                 )
-                val animationsEnabled by collectLastValue(underTest.animationsEnabled)
-                runCurrent()
-                assertThat(animationsEnabled).isFalse()
-            }
+            )
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
+            assertThat(animationsEnabled).isFalse()
         }
 
     @Test
     fun animationsEnabled_isFalse_whenDeviceAsleepAndNotPulsing() =
-        with(testComponent) {
-            scope.runTest {
-                powerRepository.updateWakefulness(
-                    rawState = WakefulnessState.ASLEEP,
-                    lastWakeReason = WakeSleepReason.POWER_BUTTON,
-                    lastSleepReason = WakeSleepReason.OTHER,
-                )
-                keyguardTransitionRepository.sendTransitionStep(
-                    TransitionStep(
-                        transitionState = TransitionState.STARTED,
-                    )
+        testComponent.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.ASLEEP,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
                 )
-                keyguardRepository.setDozeTransitionModel(
-                    DozeTransitionModel(
-                        to = DozeStateModel.DOZE_AOD,
-                    )
+            )
+            keyguardRepository.setDozeTransitionModel(
+                DozeTransitionModel(
+                    to = DozeStateModel.DOZE_AOD,
                 )
-                val animationsEnabled by collectLastValue(underTest.animationsEnabled)
-                runCurrent()
-                assertThat(animationsEnabled).isFalse()
-            }
+            )
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
+            assertThat(animationsEnabled).isFalse()
         }
 
     @Test
     fun animationsEnabled_isTrue_whenDeviceAsleepAndPulsing() =
-        with(testComponent) {
-            scope.runTest {
-                powerRepository.updateWakefulness(
-                    rawState = WakefulnessState.ASLEEP,
-                    lastWakeReason = WakeSleepReason.POWER_BUTTON,
-                    lastSleepReason = WakeSleepReason.OTHER,
+        testComponent.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.ASLEEP,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
                 )
-                keyguardTransitionRepository.sendTransitionStep(
-                    TransitionStep(
-                        transitionState = TransitionState.STARTED,
-                    )
+            )
+            keyguardRepository.setDozeTransitionModel(
+                DozeTransitionModel(
+                    to = DozeStateModel.DOZE_PULSING,
                 )
-                keyguardRepository.setDozeTransitionModel(
-                    DozeTransitionModel(
-                        to = DozeStateModel.DOZE_PULSING,
-                    )
-                )
-                val animationsEnabled by collectLastValue(underTest.animationsEnabled)
-                runCurrent()
-                assertThat(animationsEnabled).isTrue()
-            }
+            )
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
+            assertThat(animationsEnabled).isTrue()
         }
 
     @Test
     fun animationsEnabled_isFalse_whenStartingToSleepAndNotControlScreenOff() =
-        with(testComponent) {
-            scope.runTest {
-                powerRepository.updateWakefulness(
-                    rawState = WakefulnessState.STARTING_TO_SLEEP,
-                    lastWakeReason = WakeSleepReason.POWER_BUTTON,
-                    lastSleepReason = WakeSleepReason.OTHER,
-                )
-                keyguardTransitionRepository.sendTransitionStep(
-                    TransitionStep(
-                        from = KeyguardState.GONE,
-                        to = KeyguardState.AOD,
-                        transitionState = TransitionState.STARTED,
-                    )
+        testComponent.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.STARTING_TO_SLEEP,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.AOD,
+                    transitionState = TransitionState.STARTED,
                 )
-                whenever(dozeParams.shouldControlScreenOff()).thenReturn(false)
-                val animationsEnabled by collectLastValue(underTest.animationsEnabled)
-                runCurrent()
-                assertThat(animationsEnabled).isFalse()
-            }
+            )
+            whenever(dozeParams.shouldControlScreenOff()).thenReturn(false)
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
+            assertThat(animationsEnabled).isFalse()
         }
 
     @Test
     fun animationsEnabled_isTrue_whenStartingToSleepAndControlScreenOff() =
-        with(testComponent) {
-            scope.runTest {
-                powerRepository.updateWakefulness(
-                    rawState = WakefulnessState.STARTING_TO_SLEEP,
-                    lastWakeReason = WakeSleepReason.POWER_BUTTON,
-                    lastSleepReason = WakeSleepReason.OTHER,
+        testComponent.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.STARTING_TO_SLEEP,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    from = KeyguardState.GONE,
+                    to = KeyguardState.AOD,
+                    transitionState = TransitionState.STARTED,
                 )
-                keyguardTransitionRepository.sendTransitionStep(
-                    TransitionStep(
-                        from = KeyguardState.GONE,
-                        to = KeyguardState.AOD,
-                        transitionState = TransitionState.STARTED,
-                    )
-                )
-                whenever(dozeParams.shouldControlScreenOff()).thenReturn(true)
-                val animationsEnabled by collectLastValue(underTest.animationsEnabled)
-                runCurrent()
-                assertThat(animationsEnabled).isTrue()
-            }
+            )
+            whenever(dozeParams.shouldControlScreenOff()).thenReturn(true)
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
+            assertThat(animationsEnabled).isTrue()
         }
 
     @Test
     fun animationsEnabled_isTrue_whenNotAsleep() =
-        with(testComponent) {
-            scope.runTest {
-                powerRepository.updateWakefulness(
-                    rawState = WakefulnessState.AWAKE,
-                    lastWakeReason = WakeSleepReason.POWER_BUTTON,
-                    lastSleepReason = WakeSleepReason.OTHER,
-                )
-                keyguardTransitionRepository.sendTransitionStep(
-                    TransitionStep(
-                        transitionState = TransitionState.STARTED,
-                    )
+        testComponent.runTest {
+            powerRepository.updateWakefulness(
+                rawState = WakefulnessState.AWAKE,
+                lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                lastSleepReason = WakeSleepReason.OTHER,
+            )
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
                 )
-                val animationsEnabled by collectLastValue(underTest.animationsEnabled)
-                runCurrent()
-                assertThat(animationsEnabled).isTrue()
-            }
+            )
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+            runCurrent()
+            assertThat(animationsEnabled).isTrue()
         }
 
     @Test
     fun animationsEnabled_isTrue_whenKeyguardIsNotShowing() =
-        with(testComponent) {
-            scope.runTest {
-                val animationsEnabled by collectLastValue(underTest.animationsEnabled)
-
-                keyguardTransitionRepository.sendTransitionStep(
-                    TransitionStep(
-                        transitionState = TransitionState.STARTED,
-                    )
+        testComponent.runTest {
+            val animationsEnabled by collectLastValue(underTest.animationsEnabled)
+
+            keyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    transitionState = TransitionState.STARTED,
                 )
-                keyguardRepository.setKeyguardShowing(true)
-                runCurrent()
+            )
+            keyguardRepository.setKeyguardShowing(true)
+            runCurrent()
 
-                assertThat(animationsEnabled).isFalse()
+            assertThat(animationsEnabled).isFalse()
 
-                keyguardRepository.setKeyguardShowing(false)
-                runCurrent()
+            keyguardRepository.setKeyguardShowing(false)
+            runCurrent()
 
-                assertThat(animationsEnabled).isTrue()
-            }
+            assertThat(animationsEnabled).isTrue()
         }
 
     @Test
     fun iconColors_testsDarkBounds() =
-        with(testComponent) {
-            scope.runTest {
-                darkIconRepository.darkState.value =
-                    SysuiDarkIconDispatcher.DarkChange(
-                        emptyList(),
-                        0f,
-                        0xAABBCC,
-                    )
-                val iconColorsLookup by collectLastValue(underTest.iconColors)
-                assertThat(iconColorsLookup).isNotNull()
-
-                val iconColors = iconColorsLookup?.iconColors(Rect())
-                assertThat(iconColors).isNotNull()
-                iconColors!!
-
-                assertThat(iconColors.tint).isEqualTo(0xAABBCC)
-
-                val staticDrawableColor = iconColors.staticDrawableColor(Rect(), isColorized = true)
-
-                assertThat(staticDrawableColor).isEqualTo(0xAABBCC)
-            }
+        testComponent.runTest {
+            darkIconRepository.darkState.value =
+                SysuiDarkIconDispatcher.DarkChange(
+                    emptyList(),
+                    0f,
+                    0xAABBCC,
+                )
+            val iconColorsLookup by collectLastValue(underTest.iconColors)
+            assertThat(iconColorsLookup).isNotNull()
+
+            val iconColors = iconColorsLookup?.iconColors(Rect())
+            assertThat(iconColors).isNotNull()
+            iconColors!!
+
+            assertThat(iconColors.tint).isEqualTo(0xAABBCC)
+
+            val staticDrawableColor = iconColors.staticDrawableColor(Rect(), isColorized = true)
+
+            assertThat(staticDrawableColor).isEqualTo(0xAABBCC)
         }
 
     @Test
     fun iconColors_staticDrawableColor_nonColorized() =
-        with(testComponent) {
-            scope.runTest {
-                darkIconRepository.darkState.value =
-                    SysuiDarkIconDispatcher.DarkChange(
-                        emptyList(),
-                        0f,
-                        0xAABBCC,
-                    )
-                val iconColorsLookup by collectLastValue(underTest.iconColors)
-                val iconColors = iconColorsLookup?.iconColors(Rect())
-                val staticDrawableColor =
-                    iconColors?.staticDrawableColor(Rect(), isColorized = false)
-                assertThat(staticDrawableColor).isEqualTo(DarkIconDispatcher.DEFAULT_ICON_TINT)
-            }
+        testComponent.runTest {
+            darkIconRepository.darkState.value =
+                SysuiDarkIconDispatcher.DarkChange(
+                    emptyList(),
+                    0f,
+                    0xAABBCC,
+                )
+            val iconColorsLookup by collectLastValue(underTest.iconColors)
+            val iconColors = iconColorsLookup?.iconColors(Rect())
+            val staticDrawableColor = iconColors?.staticDrawableColor(Rect(), isColorized = false)
+            assertThat(staticDrawableColor).isEqualTo(DarkIconDispatcher.DEFAULT_ICON_TINT)
         }
 
     @Test
     fun iconColors_staticDrawableColor_isColorized_notInDarkTintArea() =
-        with(testComponent) {
-            scope.runTest {
-                darkIconRepository.darkState.value =
-                    SysuiDarkIconDispatcher.DarkChange(
-                        listOf(Rect(0, 0, 5, 5)),
-                        0f,
-                        0xAABBCC,
-                    )
-                val iconColorsLookup by collectLastValue(underTest.iconColors)
-                val iconColors = iconColorsLookup?.iconColors(Rect(1, 1, 4, 4))
-                val staticDrawableColor =
-                    iconColors?.staticDrawableColor(Rect(6, 6, 7, 7), isColorized = true)
-                assertThat(staticDrawableColor).isEqualTo(DarkIconDispatcher.DEFAULT_ICON_TINT)
-            }
+        testComponent.runTest {
+            darkIconRepository.darkState.value =
+                SysuiDarkIconDispatcher.DarkChange(
+                    listOf(Rect(0, 0, 5, 5)),
+                    0f,
+                    0xAABBCC,
+                )
+            val iconColorsLookup by collectLastValue(underTest.iconColors)
+            val iconColors = iconColorsLookup?.iconColors(Rect(1, 1, 4, 4))
+            val staticDrawableColor =
+                iconColors?.staticDrawableColor(Rect(6, 6, 7, 7), isColorized = true)
+            assertThat(staticDrawableColor).isEqualTo(DarkIconDispatcher.DEFAULT_ICON_TINT)
         }
 
     @Test
     fun iconColors_notInDarkTintArea() =
-        with(testComponent) {
-            scope.runTest {
-                darkIconRepository.darkState.value =
-                    SysuiDarkIconDispatcher.DarkChange(
-                        listOf(Rect(0, 0, 5, 5)),
-                        0f,
-                        0xAABBCC,
-                    )
-                val iconColorsLookup by collectLastValue(underTest.iconColors)
-                val iconColors = iconColorsLookup?.iconColors(Rect(6, 6, 7, 7))
-                assertThat(iconColors).isNull()
-            }
+        testComponent.runTest {
+            darkIconRepository.darkState.value =
+                SysuiDarkIconDispatcher.DarkChange(
+                    listOf(Rect(0, 0, 5, 5)),
+                    0f,
+                    0xAABBCC,
+                )
+            val iconColorsLookup by collectLastValue(underTest.iconColors)
+            val iconColors = iconColorsLookup?.iconColors(Rect(6, 6, 7, 7))
+            assertThat(iconColors).isNull()
         }
 
     @Test
     fun isolatedIcon_animateOnAppear_shadeCollapsed() =
-        with(testComponent) {
-            scope.runTest {
-                val icon: Icon = mock()
-                shadeRepository.setLegacyShadeExpansion(0f)
-                activeNotificationsRepository.activeNotifications.value =
-                    ActiveNotificationsStore.Builder()
-                        .apply {
-                            addIndividualNotif(
-                                activeNotificationModel(
-                                    key = "notif1",
-                                    groupKey = "group",
-                                    statusBarIcon = icon
-                                )
+        testComponent.runTest {
+            val icon: Icon = mock()
+            shadeRepository.setLegacyShadeExpansion(0f)
+            activeNotificationsRepository.activeNotifications.value =
+                ActiveNotificationsStore.Builder()
+                    .apply {
+                        addIndividualNotif(
+                            activeNotificationModel(
+                                key = "notif1",
+                                groupKey = "group",
+                                statusBarIcon = icon
                             )
-                        }
-                        .build()
-                val isolatedIcon by collectLastValue(underTest.isolatedIcon)
-                runCurrent()
+                        )
+                    }
+                    .build()
+            val isolatedIcon by collectLastValue(underTest.isolatedIcon)
+            runCurrent()
 
-                headsUpViewStateRepository.isolatedNotification.value = "notif1"
-                runCurrent()
+            headsUpViewStateRepository.isolatedNotification.value = "notif1"
+            runCurrent()
 
-                assertThat(isolatedIcon?.value?.notifKey).isEqualTo("notif1")
-                assertThat(isolatedIcon?.isAnimating).isTrue()
-            }
+            assertThat(isolatedIcon?.value?.notifKey).isEqualTo("notif1")
+            assertThat(isolatedIcon?.isAnimating).isTrue()
         }
 
     @Test
     fun isolatedIcon_dontAnimateOnAppear_shadeExpanded() =
-        with(testComponent) {
-            scope.runTest {
-                val icon: Icon = mock()
-                shadeRepository.setLegacyShadeExpansion(.5f)
-                activeNotificationsRepository.activeNotifications.value =
-                    ActiveNotificationsStore.Builder()
-                        .apply {
-                            addIndividualNotif(
-                                activeNotificationModel(
-                                    key = "notif1",
-                                    groupKey = "group",
-                                    statusBarIcon = icon
-                                )
+        testComponent.runTest {
+            val icon: Icon = mock()
+            shadeRepository.setLegacyShadeExpansion(.5f)
+            activeNotificationsRepository.activeNotifications.value =
+                ActiveNotificationsStore.Builder()
+                    .apply {
+                        addIndividualNotif(
+                            activeNotificationModel(
+                                key = "notif1",
+                                groupKey = "group",
+                                statusBarIcon = icon
                             )
-                        }
-                        .build()
-                val isolatedIcon by collectLastValue(underTest.isolatedIcon)
-                runCurrent()
+                        )
+                    }
+                    .build()
+            val isolatedIcon by collectLastValue(underTest.isolatedIcon)
+            runCurrent()
 
-                headsUpViewStateRepository.isolatedNotification.value = "notif1"
-                runCurrent()
+            headsUpViewStateRepository.isolatedNotification.value = "notif1"
+            runCurrent()
 
-                assertThat(isolatedIcon?.value?.notifKey).isEqualTo("notif1")
-                assertThat(isolatedIcon?.isAnimating).isFalse()
-            }
+            assertThat(isolatedIcon?.value?.notifKey).isEqualTo("notif1")
+            assertThat(isolatedIcon?.isAnimating).isFalse()
         }
-
-    @SysUISingleton
-    @Component(
-        modules =
-            [
-                SysUITestModule::class,
-                BiometricsDomainLayerModule::class,
-                UserDomainLayerModule::class,
-            ]
-    )
-    interface TestComponent {
-
-        val underTest: NotificationIconContainerStatusBarViewModel
-
-        val activeNotificationsRepository: ActiveNotificationListRepository
-        val darkIconRepository: FakeDarkIconRepository
-        val deviceProvisioningRepository: FakeDeviceProvisioningRepository
-        val headsUpViewStateRepository: HeadsUpNotificationIconViewStateRepository
-        val keyguardTransitionRepository: FakeKeyguardTransitionRepository
-        val keyguardRepository: FakeKeyguardRepository
-        val powerRepository: FakePowerRepository
-        val shadeRepository: FakeShadeRepository
-        val scope: TestScope
-
-        @Component.Factory
-        interface Factory {
-            fun create(
-                @BindsInstance test: SysuiTestCase,
-                mocks: TestMocksModule,
-                featureFlags: FakeFeatureFlagsClassicModule,
-            ): TestComponent
-        }
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt
index 02a67d04ce8f1abcd29ffb622cb689c5ec187801..7423c2decaecb8dec880207f791982eda640a817 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/shelf/ui/viewmodel/NotificationShelfViewModelTest.kt
@@ -14,17 +14,17 @@
  * limitations under the License.
  */
 
-@file:OptIn(ExperimentalCoroutinesApi::class)
-
 package com.android.systemui.statusbar.notification.shelf.ui.viewmodel
 
 import android.os.PowerManager
 import android.testing.AndroidTestingRunner
 import androidx.test.filters.SmallTest
+import com.android.SysUITestComponent
 import com.android.SysUITestModule
 import com.android.TestMocksModule
+import com.android.collectLastValue
+import com.android.runTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
@@ -34,111 +34,105 @@ import com.android.systemui.statusbar.SysuiStatusBarStateController
 import com.android.systemui.statusbar.notification.row.ui.viewmodel.ActivatableNotificationViewModelModule
 import com.android.systemui.statusbar.phone.ScreenOffAnimationController
 import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
 import dagger.BindsInstance
 import dagger.Component
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.runTest
-import org.junit.Before
-import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.Mock
 import org.mockito.Mockito
 import org.mockito.Mockito.verify
-import org.mockito.junit.MockitoJUnit
-import org.mockito.junit.MockitoRule
 
 @RunWith(AndroidTestingRunner::class)
 @SmallTest
 class NotificationShelfViewModelTest : SysuiTestCase() {
 
-    @Rule @JvmField val mockitoRule: MockitoRule = MockitoJUnit.rule()
-
-    @Mock private lateinit var keyguardTransitionController: LockscreenShadeTransitionController
-    @Mock private lateinit var screenOffAnimationController: ScreenOffAnimationController
-    @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController
-
-    private lateinit var testComponent: TestComponent
-
-    @Before
-    fun setUp() {
-        whenever(screenOffAnimationController.allowWakeUpIfDozing()).thenReturn(true)
-        testComponent =
-            DaggerNotificationShelfViewModelTest_TestComponent.factory()
-                .create(
-                    test = this,
-                    mocks =
-                        TestMocksModule(
-                            lockscreenShadeTransitionController = keyguardTransitionController,
-                            screenOffAnimationController = screenOffAnimationController,
-                            statusBarStateController = statusBarStateController,
-                        )
-                )
+    @Component(modules = [SysUITestModule::class, ActivatableNotificationViewModelModule::class])
+    @SysUISingleton
+    interface TestComponent : SysUITestComponent<NotificationShelfViewModel> {
+
+        val deviceEntryFaceAuthRepository: FakeDeviceEntryFaceAuthRepository
+        val keyguardRepository: FakeKeyguardRepository
+        val powerRepository: FakePowerRepository
+
+        @Component.Factory
+        interface Factory {
+            fun create(
+                @BindsInstance test: SysuiTestCase,
+                mocks: TestMocksModule,
+            ): TestComponent
+        }
     }
 
+    private val keyguardTransitionController: LockscreenShadeTransitionController = mock()
+    private val screenOffAnimationController: ScreenOffAnimationController = mock {
+        whenever(allowWakeUpIfDozing()).thenReturn(true)
+    }
+    private val statusBarStateController: SysuiStatusBarStateController = mock()
+
+    private val testComponent: TestComponent =
+        DaggerNotificationShelfViewModelTest_TestComponent.factory()
+            .create(
+                test = this,
+                mocks =
+                    TestMocksModule(
+                        lockscreenShadeTransitionController = keyguardTransitionController,
+                        screenOffAnimationController = screenOffAnimationController,
+                        statusBarStateController = statusBarStateController,
+                    )
+            )
+
     @Test
     fun canModifyColorOfNotifications_whenKeyguardNotShowing() =
-        with(testComponent) {
-            testScope.runTest {
-                val canModifyNotifColor by collectLastValue(underTest.canModifyColorOfNotifications)
+        testComponent.runTest {
+            val canModifyNotifColor by collectLastValue(underTest.canModifyColorOfNotifications)
 
-                keyguardRepository.setKeyguardShowing(false)
+            keyguardRepository.setKeyguardShowing(false)
 
-                assertThat(canModifyNotifColor).isTrue()
-            }
+            assertThat(canModifyNotifColor).isTrue()
         }
 
     @Test
     fun canModifyColorOfNotifications_whenKeyguardShowingAndNotBypass() =
-        with(testComponent) {
-            testScope.runTest {
-                val canModifyNotifColor by collectLastValue(underTest.canModifyColorOfNotifications)
+        testComponent.runTest {
+            val canModifyNotifColor by collectLastValue(underTest.canModifyColorOfNotifications)
 
-                keyguardRepository.setKeyguardShowing(true)
-                deviceEntryFaceAuthRepository.isBypassEnabled.value = false
+            keyguardRepository.setKeyguardShowing(true)
+            deviceEntryFaceAuthRepository.isBypassEnabled.value = false
 
-                assertThat(canModifyNotifColor).isTrue()
-            }
+            assertThat(canModifyNotifColor).isTrue()
         }
 
     @Test
     fun cannotModifyColorOfNotifications_whenBypass() =
-        with(testComponent) {
-            testScope.runTest {
-                val canModifyNotifColor by collectLastValue(underTest.canModifyColorOfNotifications)
+        testComponent.runTest {
+            val canModifyNotifColor by collectLastValue(underTest.canModifyColorOfNotifications)
 
-                keyguardRepository.setKeyguardShowing(true)
-                deviceEntryFaceAuthRepository.isBypassEnabled.value = true
+            keyguardRepository.setKeyguardShowing(true)
+            deviceEntryFaceAuthRepository.isBypassEnabled.value = true
 
-                assertThat(canModifyNotifColor).isFalse()
-            }
+            assertThat(canModifyNotifColor).isFalse()
         }
 
     @Test
     fun isClickable_whenKeyguardShowing() =
-        with(testComponent) {
-            testScope.runTest {
-                val isClickable by collectLastValue(underTest.isClickable)
+        testComponent.runTest {
+            val isClickable by collectLastValue(underTest.isClickable)
 
-                keyguardRepository.setKeyguardShowing(true)
+            keyguardRepository.setKeyguardShowing(true)
 
-                assertThat(isClickable).isTrue()
-            }
+            assertThat(isClickable).isTrue()
         }
 
     @Test
     fun isNotClickable_whenKeyguardNotShowing() =
-        with(testComponent) {
-            testScope.runTest {
-                val isClickable by collectLastValue(underTest.isClickable)
+        testComponent.runTest {
+            val isClickable by collectLastValue(underTest.isClickable)
 
-                keyguardRepository.setKeyguardShowing(false)
+            keyguardRepository.setKeyguardShowing(false)
 
-                assertThat(isClickable).isFalse()
-            }
+            assertThat(isClickable).isFalse()
         }
 
     @Test
@@ -152,23 +146,4 @@ class NotificationShelfViewModelTest : SysuiTestCase() {
             assertThat(powerRepository.lastWakeReason).isEqualTo(PowerManager.WAKE_REASON_GESTURE)
             verify(keyguardTransitionController).goToLockedShade(Mockito.isNull(), eq(true))
         }
-
-    @Component(modules = [SysUITestModule::class, ActivatableNotificationViewModelModule::class])
-    @SysUISingleton
-    interface TestComponent {
-
-        val underTest: NotificationShelfViewModel
-        val deviceEntryFaceAuthRepository: FakeDeviceEntryFaceAuthRepository
-        val keyguardRepository: FakeKeyguardRepository
-        val powerRepository: FakePowerRepository
-        val testScope: TestScope
-
-        @Component.Factory
-        interface Factory {
-            fun create(
-                @BindsInstance test: SysuiTestCase,
-                mocks: TestMocksModule,
-            ): TestComponent
-        }
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index 3a9d111bacf7b0707bc7b1a299dc7b6f7e526972..22553dfc4cb1b57c4602246bd6564e30da70f776 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -19,12 +19,15 @@ package com.android.systemui.statusbar.notification.stack.ui.viewmodel
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.SysUITestComponent
 import com.android.SysUITestModule
 import com.android.TestMocksModule
+import com.android.collectLastValue
+import com.android.runCurrent
+import com.android.runTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.common.shared.model.SharedNotificationContainerPosition
 import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
-import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.flags.FakeFeatureFlagsClassicModule
 import com.android.systemui.flags.Flags
@@ -47,70 +50,64 @@ import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
 import dagger.BindsInstance
 import dagger.Component
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.runCurrent
-import kotlinx.coroutines.test.runTest
-import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.MockitoAnnotations
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class SharedNotificationContainerViewModelTest : SysuiTestCase() {
 
-    private lateinit var testComponent: TestComponent
-
-    private val shadeRepository
-        get() = testComponent.shadeRepository
-    private val keyguardRepository
-        get() = testComponent.keyguardRepository
-    private val configurationRepository
-        get() = testComponent.configurationRepository
-    private val sharedNotificationContainerInteractor: SharedNotificationContainerInteractor
-        get() = testComponent.sharedNotificationContainerInteractor
-    private val underTest: SharedNotificationContainerViewModel
-        get() = testComponent.underTest
-    private val keyguardInteractor: KeyguardInteractor
-        get() = testComponent.keyguardInteractor
-    private val keyguardTransitionRepository
-        get() = testComponent.keyguardTransitionRepository
-    private val testScope
-        get() = testComponent.testScope
-
-    @Mock private lateinit var notificationStackSizeCalculator: NotificationStackSizeCalculator
-    @Mock
-    private lateinit var notificationStackScrollLayoutController:
-        NotificationStackScrollLayoutController
-
-    @Before
-    fun setUp() {
-        MockitoAnnotations.initMocks(this)
-
-        whenever(notificationStackScrollLayoutController.getView()).thenReturn(mock())
-        whenever(notificationStackScrollLayoutController.getShelfHeight()).thenReturn(0)
-
-        testComponent =
-            DaggerSharedNotificationContainerViewModelTest_TestComponent.factory()
-                .create(
-                    test = this,
-                    featureFlags =
-                        FakeFeatureFlagsClassicModule {
-                            set(Flags.FULL_SCREEN_USER_SWITCHER, true)
-                        },
-                    mocks =
-                        TestMocksModule(
-                            notificationStackSizeCalculator = notificationStackSizeCalculator,
-                            notificationStackScrollLayoutController =
-                                notificationStackScrollLayoutController,
-                        )
-                )
+    @SysUISingleton
+    @Component(
+        modules =
+            [
+                SysUITestModule::class,
+                UserDomainLayerModule::class,
+            ]
+    )
+    interface TestComponent : SysUITestComponent<SharedNotificationContainerViewModel> {
+
+        val configurationRepository: FakeConfigurationRepository
+        val keyguardRepository: FakeKeyguardRepository
+        val keyguardInteractor: KeyguardInteractor
+        val keyguardTransitionRepository: FakeKeyguardTransitionRepository
+        val shadeRepository: FakeShadeRepository
+        val sharedNotificationContainerInteractor: SharedNotificationContainerInteractor
+
+        @Component.Factory
+        interface Factory {
+            fun create(
+                @BindsInstance test: SysuiTestCase,
+                featureFlags: FakeFeatureFlagsClassicModule,
+                mocks: TestMocksModule,
+            ): TestComponent
+        }
     }
 
+    private val notificationStackSizeCalculator: NotificationStackSizeCalculator = mock()
+    private val notificationStackScrollLayoutController: NotificationStackScrollLayoutController =
+        mock {
+            whenever(view).thenReturn(mock())
+            whenever(shelfHeight).thenReturn(0)
+        }
+
+    private val testComponent: TestComponent =
+        DaggerSharedNotificationContainerViewModelTest_TestComponent.factory()
+            .create(
+                test = this,
+                featureFlags =
+                    FakeFeatureFlagsClassicModule { set(Flags.FULL_SCREEN_USER_SWITCHER, true) },
+                mocks =
+                    TestMocksModule(
+                        notificationStackSizeCalculator = notificationStackSizeCalculator,
+                        notificationStackScrollLayoutController =
+                            notificationStackScrollLayoutController,
+                    )
+            )
+
     @Test
     fun validateMarginStartInSplitShade() =
-        testScope.runTest {
+        testComponent.runTest {
             overrideResource(R.bool.config_use_split_notification_shade, true)
             overrideResource(R.dimen.notification_panel_margin_horizontal, 20)
 
@@ -123,7 +120,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
 
     @Test
     fun validateMarginStart() =
-        testScope.runTest {
+        testComponent.runTest {
             overrideResource(R.bool.config_use_split_notification_shade, false)
             overrideResource(R.dimen.notification_panel_margin_horizontal, 20)
 
@@ -136,7 +133,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
 
     @Test
     fun validateMarginEnd() =
-        testScope.runTest {
+        testComponent.runTest {
             overrideResource(R.dimen.notification_panel_margin_horizontal, 50)
 
             val dimens by collectLastValue(underTest.configurationBasedDimensions)
@@ -148,7 +145,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
 
     @Test
     fun validateMarginBottom() =
-        testScope.runTest {
+        testComponent.runTest {
             overrideResource(R.dimen.notification_panel_margin_bottom, 50)
 
             val dimens by collectLastValue(underTest.configurationBasedDimensions)
@@ -160,7 +157,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
 
     @Test
     fun validateMarginTopWithLargeScreenHeader() =
-        testScope.runTest {
+        testComponent.runTest {
             overrideResource(R.bool.config_use_large_screen_shade_header, true)
             overrideResource(R.dimen.large_screen_shade_header_height, 50)
             overrideResource(R.dimen.notification_panel_margin_top, 0)
@@ -174,7 +171,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
 
     @Test
     fun validateMarginTop() =
-        testScope.runTest {
+        testComponent.runTest {
             overrideResource(R.bool.config_use_large_screen_shade_header, false)
             overrideResource(R.dimen.large_screen_shade_header_height, 50)
             overrideResource(R.dimen.notification_panel_margin_top, 0)
@@ -188,7 +185,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
 
     @Test
     fun isOnLockscreen() =
-        testScope.runTest {
+        testComponent.runTest {
             val isOnLockscreen by collectLastValue(underTest.isOnLockscreen)
 
             keyguardTransitionRepository.sendTransitionSteps(
@@ -212,7 +209,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
             keyguardTransitionRepository.sendTransitionSteps(
                 from = KeyguardState.GONE,
                 to = KeyguardState.LOCKSCREEN,
-                this,
+                testScope,
             )
             assertThat(isOnLockscreen).isTrue()
 
@@ -226,7 +223,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
 
     @Test
     fun isOnLockscreenWithoutShade() =
-        testScope.runTest {
+        testComponent.runTest {
             val isOnLockscreenWithoutShade by collectLastValue(underTest.isOnLockscreenWithoutShade)
 
             // First on AOD
@@ -262,7 +259,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
 
     @Test
     fun positionOnLockscreenNotInSplitShade() =
-        testScope.runTest {
+        testComponent.runTest {
             val position by collectLastValue(underTest.position)
 
             // When not in split shade
@@ -282,7 +279,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
 
     @Test
     fun positionOnLockscreenInSplitShade() =
-        testScope.runTest {
+        testComponent.runTest {
             val position by collectLastValue(underTest.position)
 
             // When in split shade
@@ -304,7 +301,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
 
     @Test
     fun positionOnShade() =
-        testScope.runTest {
+        testComponent.runTest {
             val position by collectLastValue(underTest.position)
 
             // Start on lockscreen with shade expanded
@@ -321,7 +318,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
 
     @Test
     fun positionOnQS() =
-        testScope.runTest {
+        testComponent.runTest {
             val position by collectLastValue(underTest.position)
 
             // Start on lockscreen with shade expanded
@@ -338,7 +335,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
 
     @Test
     fun maxNotificationsOnLockscreen() =
-        testScope.runTest {
+        testComponent.runTest {
             whenever(
                     notificationStackSizeCalculator.computeMaxKeyguardNotifications(
                         any(),
@@ -363,7 +360,7 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
 
     @Test
     fun maxNotificationsOnShade() =
-        testScope.runTest {
+        testComponent.runTest {
             whenever(
                     notificationStackSizeCalculator.computeMaxKeyguardNotifications(
                         any(),
@@ -387,66 +384,36 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
             assertThat(maxNotifications).isEqualTo(-1)
         }
 
-    private suspend fun TestScope.showLockscreen() {
+    private suspend fun TestComponent.showLockscreen() {
         shadeRepository.setLockscreenShadeExpansion(0f)
         shadeRepository.setQsExpansion(0f)
         keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
         keyguardTransitionRepository.sendTransitionSteps(
             from = KeyguardState.AOD,
             to = KeyguardState.LOCKSCREEN,
-            this,
+            testScope,
         )
     }
 
-    private suspend fun TestScope.showLockscreenWithShadeExpanded() {
+    private suspend fun TestComponent.showLockscreenWithShadeExpanded() {
         shadeRepository.setLockscreenShadeExpansion(1f)
         shadeRepository.setQsExpansion(0f)
         keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED)
         keyguardTransitionRepository.sendTransitionSteps(
             from = KeyguardState.AOD,
             to = KeyguardState.LOCKSCREEN,
-            this,
+            testScope,
         )
     }
 
-    private suspend fun TestScope.showLockscreenWithQSExpanded() {
+    private suspend fun TestComponent.showLockscreenWithQSExpanded() {
         shadeRepository.setLockscreenShadeExpansion(0f)
         shadeRepository.setQsExpansion(1f)
         keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED)
         keyguardTransitionRepository.sendTransitionSteps(
             from = KeyguardState.AOD,
             to = KeyguardState.LOCKSCREEN,
-            this,
+            testScope,
         )
     }
-
-    @SysUISingleton
-    @Component(
-        modules =
-            [
-                SysUITestModule::class,
-                UserDomainLayerModule::class,
-            ]
-    )
-    interface TestComponent {
-
-        val underTest: SharedNotificationContainerViewModel
-
-        val configurationRepository: FakeConfigurationRepository
-        val keyguardRepository: FakeKeyguardRepository
-        val keyguardInteractor: KeyguardInteractor
-        val keyguardTransitionRepository: FakeKeyguardTransitionRepository
-        val shadeRepository: FakeShadeRepository
-        val sharedNotificationContainerInteractor: SharedNotificationContainerInteractor
-        val testScope: TestScope
-
-        @Component.Factory
-        interface Factory {
-            fun create(
-                @BindsInstance test: SysuiTestCase,
-                featureFlags: FakeFeatureFlagsClassicModule,
-                mocks: TestMocksModule,
-            ): TestComponent
-        }
-    }
 }