Merge "Add SideFpsProgressBar to show a progress bar when rest_to_unlock feature is enabled" into main
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index a1da9e0..1f20cb9 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -314,7 +314,7 @@
     field public static final String REMOVE_DRM_CERTIFICATES = "android.permission.REMOVE_DRM_CERTIFICATES";
     field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
     field public static final String RENOUNCE_PERMISSIONS = "android.permission.RENOUNCE_PERMISSIONS";
-    field public static final String REPORT_USAGE_STATS = "android.permission.REPORT_USAGE_STATS";
+    field @FlaggedApi("backstage_power.report_usage_stats_permission") public static final String REPORT_USAGE_STATS = "android.permission.REPORT_USAGE_STATS";
     field @Deprecated public static final String REQUEST_NETWORK_SCORES = "android.permission.REQUEST_NETWORK_SCORES";
     field public static final String REQUEST_NOTIFICATION_ASSISTANT_SERVICE = "android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE";
     field public static final String RESET_PASSWORD = "android.permission.RESET_PASSWORD";
diff --git a/core/java/android/app/usage/flags.aconfig b/core/java/android/app/usage/flags.aconfig
index afe87de..d1f9067 100644
--- a/core/java/android/app/usage/flags.aconfig
+++ b/core/java/android/app/usage/flags.aconfig
@@ -7,3 +7,9 @@
     bug: "296061232"
 }
 
+flag {
+    name: "report_usage_stats_permission"
+    namespace: "backstage_power"
+    description: "Feature flag for the new REPORT_USAGE_STATS permission."
+    bug: "296056771"
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index a54a563..84690a7 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -6122,7 +6122,9 @@
         android:protectionLevel="signature|privileged|development|appop|retailDemo" />
     <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
 
-    <!-- @SystemApi @hide Allows trusted system components to report events to UsageStatsManager -->
+    <!-- @SystemApi @hide
+         @FlaggedApi("backstage_power.report_usage_stats_permission")
+         Allows trusted system components to report events to UsageStatsManager -->
     <permission android:name="android.permission.REPORT_USAGE_STATS"
                 android:protectionLevel="signature|module" />
 
diff --git a/packages/SystemUI/communal/layout/tests/Android.bp b/packages/SystemUI/communal/layout/tests/Android.bp
index a60b1de..9a05504 100644
--- a/packages/SystemUI/communal/layout/tests/Android.bp
+++ b/packages/SystemUI/communal/layout/tests/Android.bp
@@ -32,7 +32,7 @@
         "mockito-target-extended-minus-junit4",
         "platform-test-annotations",
         "testables",
-        "truth-prebuilt",
+        "truth",
     ],
     libs: [
         "android.test.mock",
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt
index 1a28ddc..0554c58 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpansionStateManager.kt
@@ -72,6 +72,10 @@
         listener.onShadeExpansionFullyChanged(qsExpanded)
     }
 
+    fun removeFullExpansionListener(listener: ShadeFullExpansionListener) {
+        fullExpansionListeners.remove(listener)
+    }
+
     fun addQsExpansionListener(listener: ShadeQsExpansionListener) {
         qsExpansionListeners.add(listener)
         listener.onQsExpansionChanged(qsExpanded)
@@ -95,6 +99,11 @@
         stateListeners.add(listener)
     }
 
+    /** Removes a state listener. */
+    fun removeStateListener(listener: ShadeStateListener) {
+        stateListeners.remove(listener)
+    }
+
     override fun addShadeStateEventsListener(listener: ShadeStateEventsListener) {
         shadeStateEventsListeners.addIfAbsent(listener)
     }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
index 99370e9..e487a6f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
@@ -34,7 +34,7 @@
 import com.android.systemui.statusbar.phone.DozeParameters
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository
 import com.android.systemui.statusbar.policy.data.repository.DeviceProvisioningRepository
-import com.android.systemui.user.data.repository.UserRepository
+import com.android.systemui.user.domain.interactor.UserInteractor
 import com.android.systemui.util.kotlin.pairwise
 import javax.inject.Inject
 import javax.inject.Provider
@@ -71,7 +71,7 @@
     keyguardTransitionInteractor: KeyguardTransitionInteractor,
     powerInteractor: PowerInteractor,
     userSetupRepository: UserSetupRepository,
-    userRepository: UserRepository,
+    userInteractor: UserInteractor,
     sharedNotificationContainerInteractor: SharedNotificationContainerInteractor,
     repository: ShadeRepository,
 ) {
@@ -156,13 +156,12 @@
      *
      * TODO(b/300258424) remove all but the first sentence of this comment
      */
-    val isAnyExpanded: StateFlow<Boolean> =
+    val isAnyExpanded: Flow<Boolean> =
         if (sceneContainerFlags.isEnabled()) {
-                anyExpansion.map { it > 0f }.distinctUntilChanged()
-            } else {
-                repository.legacyExpandedOrAwaitingInputTransfer
-            }
-            .stateIn(scope, SharingStarted.Eagerly, false)
+            anyExpansion.map { it > 0f }.distinctUntilChanged()
+        } else {
+            repository.legacyExpandedOrAwaitingInputTransfer
+        }
 
     /**
      * Whether the user is expanding or collapsing the shade with user input. This will be true even
@@ -228,7 +227,7 @@
             isDeviceProvisioned &&
                 // Disallow QS during setup if it's a simple user switcher. (The user intends to
                 // use the lock screen user switcher, QS is not needed.)
-                (isUserSetup || !userRepository.isSimpleUserSwitcher()) &&
+                (isUserSetup || !userInteractor.isSimpleUserSwitcher) &&
                 isShadeEnabled &&
                 disableFlags.isQuickSettingsEnabled() &&
                 !isDozing
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index ef45d2b..37a4ef1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -18,7 +18,6 @@
 
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_TRANSITION_FROM_AOD;
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_TRANSITION_TO_AOD;
-import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -44,17 +43,15 @@
 import com.android.keyguard.KeyguardClockSwitch;
 import com.android.systemui.DejankUtils;
 import com.android.systemui.Dumpable;
+import com.android.systemui.res.R;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.res.R;
-import com.android.systemui.shade.domain.interactor.ShadeInteractor;
+import com.android.systemui.shade.ShadeExpansionStateManager;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 import com.android.systemui.statusbar.policy.CallbackController;
 import com.android.systemui.util.Compile;
 
-import dagger.Lazy;
-
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Comparator;
@@ -98,7 +95,6 @@
     private final ArrayList<RankedListener> mListeners = new ArrayList<>();
     private final UiEventLogger mUiEventLogger;
     private final InteractionJankMonitor mInteractionJankMonitor;
-    private final Lazy<ShadeInteractor> mShadeInteractorLazy;
     private int mState;
     private int mLastState;
     private int mUpcomingState;
@@ -162,13 +158,15 @@
             UiEventLogger uiEventLogger,
             DumpManager dumpManager,
             InteractionJankMonitor interactionJankMonitor,
-            Lazy<ShadeInteractor> shadeInteractorLazy) {
+            ShadeExpansionStateManager shadeExpansionStateManager
+    ) {
         mUiEventLogger = uiEventLogger;
         mInteractionJankMonitor = interactionJankMonitor;
-        mShadeInteractorLazy = shadeInteractorLazy;
         for (int i = 0; i < HISTORY_SIZE; i++) {
             mHistoricalRecords[i] = new HistoricalState();
         }
+        shadeExpansionStateManager.addFullExpansionListener(this::onShadeExpansionFullyChanged);
+
         dumpManager.registerDumpable(this);
     }
 
@@ -338,8 +336,6 @@
                 && (view != null && view.isAttachedToWindow())) {
             mView = view;
             mClockSwitchView = view.findViewById(R.id.keyguard_clock_container);
-            collectFlow(mView, mShadeInteractorLazy.get().isAnyExpanded(),
-                    this::onShadeOrQsExpanded);
         }
         mDozeAmountTarget = dozeAmount;
         if (animated) {
@@ -349,7 +345,7 @@
         }
     }
 
-    private void onShadeOrQsExpanded(Boolean isExpanded) {
+    private void onShadeExpansionFullyChanged(Boolean isExpanded) {
         if (mIsExpanded != isExpanded) {
             mIsExpanded = isExpanded;
             String tag = getClass().getSimpleName() + "#setIsExpanded";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java
index b0155f1..6ec9dbe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java
@@ -180,9 +180,4 @@
      * Add a component that can suppress visual interruptions.
      */
     void addSuppressor(NotificationInterruptSuppressor suppressor);
-
-    /**
-     * Remove a component that can suppress visual interruptions.
-     */
-    void removeSuppressor(NotificationInterruptSuppressor suppressor);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
index 778a0a9..3819843 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
@@ -175,11 +175,6 @@
     }
 
     @Override
-    public void removeSuppressor(NotificationInterruptSuppressor suppressor) {
-        mSuppressors.remove(suppressor);
-    }
-
-    @Override
     public boolean shouldBubbleUp(NotificationEntry entry) {
         final StatusBarNotification sbn = entry.getSbn();
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapper.kt
index d7f0baf..ebdeded 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderWrapper.kt
@@ -58,10 +58,6 @@
         wrapped.addSuppressor(suppressor)
     }
 
-    override fun removeLegacySuppressor(suppressor: NotificationInterruptSuppressor) {
-        wrapped.removeSuppressor(suppressor)
-    }
-
     override fun makeUnloggedHeadsUpDecision(entry: NotificationEntry): Decision =
         wrapped.checkHeadsUp(entry, /* log= */ false).let { DecisionImpl.of(it) }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProvider.kt
index 920bbe9..454ba02 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/VisualInterruptionDecisionProvider.kt
@@ -60,13 +60,6 @@
     fun addLegacySuppressor(suppressor: NotificationInterruptSuppressor)
 
     /**
-     * Removes a [component][suppressor] that can suppress visual interruptions.
-     *
-     * @param[suppressor] the suppressor to remove
-     */
-    fun removeLegacySuppressor(suppressor: NotificationInterruptSuppressor)
-
-    /**
      * Decides whether a [notification][entry] should display as heads-up or not, but does not log
      * that decision.
      *
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index 407148f..6b4382f73 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -34,7 +34,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.res.R;
-import com.android.systemui.shade.domain.interactor.ShadeInteractor;
+import com.android.systemui.shade.ShadeExpansionStateManager;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.provider.OnReorderingAllowedListener;
@@ -48,7 +48,6 @@
 import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 import com.android.systemui.statusbar.policy.OnHeadsUpPhoneListenerChange;
-import com.android.systemui.util.kotlin.JavaAdapter;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -106,8 +105,7 @@
     ///////////////////////////////////////////////////////////////////////////////////////////////
     //  Constructor:
     @Inject
-    public HeadsUpManagerPhone(
-            @NonNull final Context context,
+    public HeadsUpManagerPhone(@NonNull final Context context,
             HeadsUpManagerLogger logger,
             StatusBarStateController statusBarStateController,
             KeyguardBypassController bypassController,
@@ -117,8 +115,7 @@
             @Main Handler handler,
             AccessibilityManagerWrapper accessibilityManagerWrapper,
             UiEventLogger uiEventLogger,
-            JavaAdapter javaAdapter,
-            ShadeInteractor shadeInteractor) {
+            ShadeExpansionStateManager shadeExpansionStateManager) {
         super(context, logger, handler, accessibilityManagerWrapper, uiEventLogger);
         Resources resources = mContext.getResources();
         mExtensionTime = resources.getInteger(R.integer.ambient_notification_extension_time);
@@ -139,7 +136,8 @@
                 updateResources();
             }
         });
-        javaAdapter.alwaysCollectFlow(shadeInteractor.isAnyExpanded(), this::onShadeOrQsExpanded);
+
+        shadeExpansionStateManager.addFullExpansionListener(this::onShadeExpansionFullyChanged);
     }
 
     public void setAnimationStateHandler(AnimationStateHandler handler) {
@@ -232,7 +230,7 @@
         mTrackingHeadsUp = trackingHeadsUp;
     }
 
-    private void onShadeOrQsExpanded(Boolean isExpanded) {
+    private void onShadeExpansionFullyChanged(Boolean isExpanded) {
         if (isExpanded != mIsExpanded) {
             mIsExpanded = isExpanded;
             if (isExpanded) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHideIconsForBouncerManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHideIconsForBouncerManager.kt
index fa6d279..4d9de09 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHideIconsForBouncerManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHideIconsForBouncerManager.kt
@@ -3,15 +3,12 @@
 import android.app.StatusBarManager
 import com.android.systemui.Dumpable
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.dump.DumpManager
-import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.shade.ShadeExpansionStateManager
 import com.android.systemui.statusbar.CommandQueue
 import com.android.systemui.statusbar.window.StatusBarWindowStateController
 import com.android.systemui.util.concurrency.DelayableExecutor
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.launch
 import java.io.PrintWriter
 import javax.inject.Inject
 
@@ -28,14 +25,14 @@
  */
 @SysUISingleton
 class StatusBarHideIconsForBouncerManager @Inject constructor(
-    @Application private val scope: CoroutineScope,
-    private val commandQueue: CommandQueue,
-    @Main private val mainExecutor: DelayableExecutor,
-    statusBarWindowStateController: StatusBarWindowStateController,
-    val shadeInteractor: ShadeInteractor,
-    dumpManager: DumpManager
+        private val commandQueue: CommandQueue,
+        @Main private val mainExecutor: DelayableExecutor,
+        statusBarWindowStateController: StatusBarWindowStateController,
+        shadeExpansionStateManager: ShadeExpansionStateManager,
+        dumpManager: DumpManager
 ) : Dumpable {
     // State variables set by external classes.
+    private var panelExpanded: Boolean = false
     private var isOccluded: Boolean = false
     private var bouncerShowing: Boolean = false
     private var topAppHidesStatusBar: Boolean = false
@@ -52,9 +49,10 @@
         statusBarWindowStateController.addListener {
                 state -> setStatusBarStateAndTriggerUpdate(state)
         }
-        scope.launch {
-            shadeInteractor.isAnyExpanded.collect {
-                updateHideIconsForBouncer(false)
+        shadeExpansionStateManager.addFullExpansionListener { isExpanded ->
+            if (panelExpanded != isExpanded) {
+                panelExpanded = isExpanded
+                updateHideIconsForBouncer(animate = false)
             }
         }
     }
@@ -103,7 +101,7 @@
             topAppHidesStatusBar &&
                     isOccluded &&
                     (statusBarWindowHidden || bouncerShowing)
-        val hideBecauseKeyguard = !isShadeOrQsExpanded() && !isOccluded && bouncerShowing
+        val hideBecauseKeyguard = !panelExpanded && !isOccluded && bouncerShowing
         val shouldHideIconsForBouncer = hideBecauseApp || hideBecauseKeyguard
         if (hideIconsForBouncer != shouldHideIconsForBouncer) {
             hideIconsForBouncer = shouldHideIconsForBouncer
@@ -127,13 +125,9 @@
         }
     }
 
-    private fun isShadeOrQsExpanded(): Boolean {
-        return shadeInteractor.isAnyExpanded.value
-    }
-
     override fun dump(pw: PrintWriter, args: Array<out String>) {
         pw.println("---- State variables set externally ----")
-        pw.println("isShadeOrQsExpanded=${isShadeOrQsExpanded()}")
+        pw.println("panelExpanded=$panelExpanded")
         pw.println("isOccluded=$isOccluded")
         pw.println("bouncerShowing=$bouncerShowing")
         pw.println("topAppHideStatusBar=$topAppHidesStatusBar")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
index 6d8ec44..ba73c10 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarTouchableRegionManager.java
@@ -39,7 +39,6 @@
 import com.android.systemui.scene.domain.interactor.SceneInteractor;
 import com.android.systemui.scene.shared.flag.SceneContainerFlags;
 import com.android.systemui.shade.ShadeExpansionStateManager;
-import com.android.systemui.shade.domain.interactor.ShadeInteractor;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
@@ -87,9 +86,8 @@
             ConfigurationController configurationController,
             HeadsUpManager headsUpManager,
             ShadeExpansionStateManager shadeExpansionStateManager,
-            ShadeInteractor shadeInteractor,
             Provider<SceneInteractor> sceneInteractor,
-            JavaAdapter javaAdapter,
+            Provider<JavaAdapter> javaAdapter,
             SceneContainerFlags sceneContainerFlags,
             UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
             PrimaryBouncerInteractor primaryBouncerInteractor,
@@ -128,12 +126,12 @@
         });
 
         mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
-        javaAdapter.alwaysCollectFlow(shadeInteractor.isAnyExpanded(), this::onShadeOrQsExpanded);
+        shadeExpansionStateManager.addFullExpansionListener(this::onShadeExpansionFullyChanged);
 
         if (sceneContainerFlags.isEnabled()) {
-            javaAdapter.alwaysCollectFlow(
+            javaAdapter.get().alwaysCollectFlow(
                     sceneInteractor.get().isVisible(),
-                    this::onShadeOrQsExpanded);
+                    this::onShadeExpansionFullyChanged);
         }
 
         mPrimaryBouncerInteractor = primaryBouncerInteractor;
@@ -153,7 +151,7 @@
         pw.println(mTouchableRegion);
     }
 
-    private void onShadeOrQsExpanded(Boolean isExpanded) {
+    private void onShadeExpansionFullyChanged(Boolean isExpanded) {
         if (isExpanded != mIsStatusBarExpanded) {
             mIsStatusBarExpanded = isExpanded;
             if (isExpanded) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index 700c9ae..4f0cec5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -84,7 +84,6 @@
 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
 import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.classifier.FalsingManagerFake;
-import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository;
 import com.android.systemui.common.ui.view.LongPressHandlingView;
 import com.android.systemui.doze.DozeLog;
 import com.android.systemui.dump.DumpManager;
@@ -121,8 +120,6 @@
 import com.android.systemui.power.domain.interactor.PowerInteractor;
 import com.android.systemui.qs.QSFragmentLegacy;
 import com.android.systemui.res.R;
-import com.android.systemui.scene.SceneTestUtils;
-import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags;
 import com.android.systemui.screenrecord.RecordingController;
 import com.android.systemui.shade.data.repository.FakeShadeRepository;
 import com.android.systemui.shade.data.repository.ShadeRepository;
@@ -140,7 +137,6 @@
 import com.android.systemui.statusbar.StatusBarStateControllerImpl;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository;
 import com.android.systemui.statusbar.notification.ConversationNotificationManager;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
@@ -172,7 +168,6 @@
 import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
 import com.android.systemui.statusbar.phone.TapAgainViewController;
 import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository;
 import com.android.systemui.statusbar.policy.CastController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -181,10 +176,8 @@
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcherController;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcherView;
 import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;
-import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository;
 import com.android.systemui.statusbar.window.StatusBarWindowStateController;
 import com.android.systemui.unfold.SysUIUnfoldComponent;
-import com.android.systemui.user.data.repository.FakeUserRepository;
 import com.android.systemui.util.kotlin.JavaAdapter;
 import com.android.systemui.util.time.FakeSystemClock;
 import com.android.systemui.util.time.SystemClock;
@@ -204,8 +197,6 @@
 import java.util.Optional;
 
 import kotlinx.coroutines.CoroutineDispatcher;
-import kotlinx.coroutines.flow.StateFlowKt;
-import kotlinx.coroutines.test.TestScope;
 
 public class NotificationPanelViewControllerBaseTest extends SysuiTestCase {
 
@@ -333,6 +324,7 @@
             mEmptySpaceClickListenerCaptor;
     @Mock protected ActivityStarter mActivityStarter;
     @Mock protected KeyguardFaceAuthInteractor mKeyguardFaceAuthInteractor;
+    @Mock private ShadeInteractor mShadeInteractor;
     @Mock private JavaAdapter mJavaAdapter;
     @Mock private CastController mCastController;
     @Mock private KeyguardRootView mKeyguardRootView;
@@ -343,9 +335,6 @@
     protected KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor;
     protected FakeKeyguardRepository mFakeKeyguardRepository;
     protected KeyguardInteractor mKeyguardInteractor;
-    protected SceneTestUtils mUtils = new SceneTestUtils(this);
-    protected TestScope mTestScope = mUtils.getTestScope();
-    protected ShadeInteractor mShadeInteractor;
     protected PowerInteractor mPowerInteractor;
     protected NotificationPanelViewController.TouchHandler mTouchHandler;
     protected ConfigurationController mConfigurationController;
@@ -381,31 +370,10 @@
         mKeyguardInteractor = keyguardInteractorDeps.getKeyguardInteractor();
         mShadeRepository = new FakeShadeRepository();
         mPowerInteractor = keyguardInteractorDeps.getPowerInteractor();
-        when(mKeyguardTransitionInteractor.isInTransitionToStateWhere(any())).thenReturn(
-                StateFlowKt.MutableStateFlow(false));
-        mShadeInteractor = new ShadeInteractor(
-                mTestScope.getBackgroundScope(),
-                new FakeDeviceProvisioningRepository(),
-                new FakeDisableFlagsRepository(),
-                mDozeParameters,
-                new FakeSceneContainerFlags(),
-                mUtils::sceneInteractor,
-                mFakeKeyguardRepository,
-                mKeyguardTransitionInteractor,
-                mPowerInteractor,
-                new FakeUserSetupRepository(),
-                new FakeUserRepository(),
-                new SharedNotificationContainerInteractor(
-                        new FakeConfigurationRepository(),
-                        mContext,
-                        new ResourcesSplitShadeStateController()
-                ),
-                mShadeRepository
-        );
 
         SystemClock systemClock = new FakeSystemClock();
         mStatusBarStateController = new StatusBarStateControllerImpl(mUiEventLogger, mDumpManager,
-                mInteractionJankMonitor, () -> mShadeInteractor);
+                mInteractionJankMonitor, mShadeExpansionStateManager);
 
         KeyguardStatusView keyguardStatusView = new KeyguardStatusView(mContext);
         keyguardStatusView.setId(R.id.keyguard_status_view);
@@ -564,8 +532,7 @@
                         mDumpManager,
                         mock(HeadsUpManager.class),
                         new StatusBarStateControllerImpl(new UiEventLoggerFake(), mDumpManager,
-                                mInteractionJankMonitor,
-                                () -> mShadeInteractor),
+                                mInteractionJankMonitor, mShadeExpansionStateManager),
                         mKeyguardBypassController,
                         mDozeParameters,
                         mScreenOffAnimationController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
index d4fb387..eb00610 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
@@ -90,7 +90,7 @@
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;
 import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository;
-import com.android.systemui.user.data.repository.FakeUserRepository;
+import com.android.systemui.user.domain.interactor.UserInteractor;
 
 import com.google.common.util.concurrent.MoreExecutors;
 
@@ -230,7 +230,7 @@
                         keyguardTransitionInteractor,
                         powerInteractor,
                         new FakeUserSetupRepository(),
-                        new FakeUserRepository(),
+                        mock(UserInteractor.class),
                         new SharedNotificationContainerInteractor(
                                 configurationRepository,
                                 mContext,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
index 8a876c8..65174ba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
@@ -95,16 +95,15 @@
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;
 import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository;
-import com.android.systemui.user.data.repository.FakeUserRepository;
+import com.android.systemui.user.domain.interactor.UserInteractor;
 import com.android.systemui.util.kotlin.JavaAdapter;
 
-import dagger.Lazy;
-
 import org.junit.After;
 import org.junit.Before;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import dagger.Lazy;
 import kotlinx.coroutines.test.TestScope;
 
 public class QuickSettingsControllerBaseTest extends SysuiTestCase {
@@ -163,6 +162,7 @@
     @Mock protected DumpManager mDumpManager;
     @Mock protected UiEventLogger mUiEventLogger;
     @Mock protected CastController mCastController;
+    @Mock protected UserInteractor mUserInteractor;
     protected FakeDisableFlagsRepository mDisableFlagsRepository =
             new FakeDisableFlagsRepository();
     protected FakeKeyguardRepository mKeyguardRepository = new FakeKeyguardRepository();
@@ -186,7 +186,7 @@
         MockitoAnnotations.initMocks(this);
         when(mPanelViewControllerLazy.get()).thenReturn(mNotificationPanelViewController);
         mStatusBarStateController = new StatusBarStateControllerImpl(mUiEventLogger, mDumpManager,
-                mInteractionJankMonitor, () -> mShadeInteractor);
+                mInteractionJankMonitor, mShadeExpansionStateManager);
 
         FakeDeviceProvisioningRepository deviceProvisioningRepository =
                 new FakeDeviceProvisioningRepository();
@@ -266,7 +266,7 @@
                         keyguardTransitionInteractor,
                         powerInteractor,
                         new FakeUserSetupRepository(),
-                        new FakeUserRepository(),
+                        mUserInteractor,
                         new SharedNotificationContainerInteractor(
                                 configurationRepository,
                                 mContext,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
index 1b26e19..3327e42 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
@@ -23,33 +23,9 @@
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.internal.logging.testing.UiEventLoggerFake
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
-import com.android.systemui.classifier.FalsingCollectorFake
-import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
-import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository
 import com.android.systemui.dump.DumpManager
-import com.android.systemui.flags.FakeFeatureFlagsClassic
-import com.android.systemui.keyguard.data.repository.FakeCommandQueue
-import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
-import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
-import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor
-import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor
-import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
 import com.android.systemui.plugins.statusbar.StatusBarStateController
-import com.android.systemui.power.data.repository.FakePowerRepository
-import com.android.systemui.power.domain.interactor.PowerInteractor
-import com.android.systemui.scene.SceneTestUtils
-import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags
-import com.android.systemui.shade.data.repository.FakeShadeRepository
-import com.android.systemui.shade.domain.interactor.ShadeInteractor
-import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository
-import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository
-import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
-import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository
-import com.android.systemui.user.data.repository.FakeUserRepository
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.shade.ShadeExpansionStateManager
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertFalse
 import org.junit.Assert.assertTrue
@@ -64,22 +40,17 @@
 import org.mockito.Mockito
 import org.mockito.Mockito.mock
 import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
 import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
 
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
 @TestableLooper.RunWithLooper
 class StatusBarStateControllerImplTest : SysuiTestCase() {
 
-    private val utils = SceneTestUtils(this)
-    private val testScope = utils.testScope
-    private lateinit var shadeInteractor: ShadeInteractor
-    private lateinit var fromLockscreenTransitionInteractor: FromLockscreenTransitionInteractor
-    private lateinit var fromPrimaryBouncerTransitionInteractor:
-        FromPrimaryBouncerTransitionInteractor
     @Mock lateinit var interactionJankMonitor: InteractionJankMonitor
-    @Mock lateinit var mockDarkAnimator: ObjectAnimator
+    @Mock private lateinit var mockDarkAnimator: ObjectAnimator
+    @Mock private lateinit var shadeExpansionStateManager: ShadeExpansionStateManager
 
     private lateinit var controller: StatusBarStateControllerImpl
     private lateinit var uiEventLogger: UiEventLoggerFake
@@ -94,74 +65,10 @@
         controller = object : StatusBarStateControllerImpl(
             uiEventLogger,
             mock(DumpManager::class.java),
-            interactionJankMonitor,
-            { shadeInteractor }
+            interactionJankMonitor, shadeExpansionStateManager
         ) {
             override fun createDarkAnimator(): ObjectAnimator { return mockDarkAnimator }
         }
-
-        val powerInteractor = PowerInteractor(
-            FakePowerRepository(),
-            FalsingCollectorFake(),
-            mock(),
-            controller)
-        val keyguardRepository = FakeKeyguardRepository()
-        val keyguardTransitionRepository = FakeKeyguardTransitionRepository()
-        val featureFlags = FakeFeatureFlagsClassic()
-        val shadeRepository = FakeShadeRepository()
-        val sceneContainerFlags = FakeSceneContainerFlags()
-        val configurationRepository = FakeConfigurationRepository()
-        val keyguardInteractor = KeyguardInteractor(
-            keyguardRepository,
-            FakeCommandQueue(),
-            powerInteractor,
-            featureFlags,
-            sceneContainerFlags,
-            FakeDeviceEntryRepository(),
-            FakeKeyguardBouncerRepository(),
-            configurationRepository,
-            shadeRepository,
-            utils::sceneInteractor)
-        val keyguardTransitionInteractor = KeyguardTransitionInteractor(
-            testScope.backgroundScope,
-            keyguardTransitionRepository,
-            { keyguardInteractor },
-            { fromLockscreenTransitionInteractor },
-            { fromPrimaryBouncerTransitionInteractor })
-        fromLockscreenTransitionInteractor = FromLockscreenTransitionInteractor(
-            keyguardTransitionRepository,
-            keyguardTransitionInteractor,
-            testScope.backgroundScope,
-            keyguardInteractor,
-            featureFlags,
-            shadeRepository,
-            powerInteractor)
-        fromPrimaryBouncerTransitionInteractor = FromPrimaryBouncerTransitionInteractor(
-            keyguardTransitionRepository,
-            keyguardTransitionInteractor,
-            testScope.backgroundScope,
-            keyguardInteractor,
-            featureFlags,
-            mock(),
-            powerInteractor)
-        shadeInteractor = ShadeInteractor(
-            testScope.backgroundScope,
-            FakeDeviceProvisioningRepository(),
-            FakeDisableFlagsRepository(),
-            mock(),
-            sceneContainerFlags,
-            utils::sceneInteractor,
-            keyguardRepository,
-            keyguardTransitionInteractor,
-            powerInteractor,
-            FakeUserSetupRepository(),
-            FakeUserRepository(),
-            SharedNotificationContainerInteractor(
-                configurationRepository,
-                mContext,
-                ResourcesSplitShadeStateController()),
-            shadeRepository,
-        )
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
index 48b95d4..cda2a74 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
@@ -34,7 +34,7 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.res.R;
-import com.android.systemui.shade.domain.interactor.ShadeInteractor;
+import com.android.systemui.shade.ShadeExpansionStateManager;
 import com.android.systemui.statusbar.AlertingNotificationManager;
 import com.android.systemui.statusbar.AlertingNotificationManagerTest;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
@@ -45,7 +45,6 @@
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.HeadsUpManagerLogger;
-import com.android.systemui.util.kotlin.JavaAdapter;
 
 import org.junit.After;
 import org.junit.Before;
@@ -57,8 +56,6 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
-import kotlinx.coroutines.flow.StateFlowKt;
-
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
@@ -73,9 +70,8 @@
     @Mock private KeyguardBypassController mBypassController;
     @Mock private ConfigurationControllerImpl mConfigurationController;
     @Mock private AccessibilityManagerWrapper mAccessibilityManagerWrapper;
+    @Mock private ShadeExpansionStateManager mShadeExpansionStateManager;
     @Mock private UiEventLogger mUiEventLogger;
-    @Mock private JavaAdapter mJavaAdapter;
-    @Mock private ShadeInteractor mShadeInteractor;
 
     private static final class TestableHeadsUpManagerPhone extends HeadsUpManagerPhone {
         TestableHeadsUpManagerPhone(
@@ -89,8 +85,7 @@
                 Handler handler,
                 AccessibilityManagerWrapper accessibilityManagerWrapper,
                 UiEventLogger uiEventLogger,
-                JavaAdapter javaAdapter,
-                ShadeInteractor shadeInteractor
+                ShadeExpansionStateManager shadeExpansionStateManager
         ) {
             super(
                     context,
@@ -103,8 +98,7 @@
                     handler,
                     accessibilityManagerWrapper,
                     uiEventLogger,
-                    javaAdapter,
-                    shadeInteractor
+                    shadeExpansionStateManager
             );
             mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
             mAutoDismissNotificationDecay = TEST_AUTO_DISMISS_TIME;
@@ -123,8 +117,7 @@
                 mTestHandler,
                 mAccessibilityManagerWrapper,
                 mUiEventLogger,
-                mJavaAdapter,
-                mShadeInteractor
+                mShadeExpansionStateManager
         );
     }
 
@@ -136,7 +129,6 @@
     @Before
     @Override
     public void setUp() {
-        when(mShadeInteractor.isAnyExpanded()).thenReturn(StateFlowKt.MutableStateFlow(false));
         final AccessibilityManagerWrapper accessibilityMgr =
                 mDependency.injectMockDependency(AccessibilityManagerWrapper.class);
         when(accessibilityMgr.getRecommendedTimeoutMillis(anyInt(), anyInt()))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 123362a..c832702 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -156,7 +156,7 @@
 import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository;
-import com.android.systemui.user.data.repository.FakeUserRepository;
+import com.android.systemui.user.domain.interactor.UserInteractor;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.WindowManagerShellWrapper;
 import com.android.wm.shell.bubbles.Bubble;
@@ -450,7 +450,7 @@
                         keyguardTransitionInteractor,
                         powerInteractor,
                         new FakeUserSetupRepository(),
-                        new FakeUserRepository(),
+                        mock(UserInteractor.class),
                         new SharedNotificationContainerInteractor(
                                 configurationRepository,
                                 mContext,
diff --git a/services/core/java/com/android/server/inputmethod/ImeTrackerService.java b/services/core/java/com/android/server/inputmethod/ImeTrackerService.java
index b090334..27e1b9a 100644
--- a/services/core/java/com/android/server/inputmethod/ImeTrackerService.java
+++ b/services/core/java/com/android/server/inputmethod/ImeTrackerService.java
@@ -60,84 +60,99 @@
     private static final long TIMEOUT_MS = 10_000;
 
     /** Handler for registering timeouts for live entries. */
+    @GuardedBy("mLock")
     private final Handler mHandler;
 
     /** Singleton instance of the History. */
-    @GuardedBy("ImeTrackerService.this")
+    @GuardedBy("mLock")
     private final History mHistory = new History();
 
+    private final Object mLock = new Object();
+
     ImeTrackerService(@NonNull Looper looper) {
         mHandler = new Handler(looper, null /* callback */, true /* async */);
     }
 
     @NonNull
     @Override
-    public synchronized ImeTracker.Token onRequestShow(@NonNull String tag, int uid,
+    public ImeTracker.Token onRequestShow(@NonNull String tag, int uid,
             @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason) {
         final var binder = new Binder();
         final var token = new ImeTracker.Token(binder, tag);
         final var entry = new History.Entry(tag, uid, ImeTracker.TYPE_SHOW, ImeTracker.STATUS_RUN,
                 origin, reason);
-        mHistory.addEntry(binder, entry);
+        synchronized (mLock) {
+            mHistory.addEntry(binder, entry);
 
-        // Register a delayed task to handle the case where the new entry times out.
-        mHandler.postDelayed(() -> {
-            synchronized (ImeTrackerService.this) {
-                mHistory.setFinished(token, ImeTracker.STATUS_TIMEOUT, ImeTracker.PHASE_NOT_SET);
-            }
-        }, TIMEOUT_MS);
-
+            // Register a delayed task to handle the case where the new entry times out.
+            mHandler.postDelayed(() -> {
+                synchronized (mLock) {
+                    mHistory.setFinished(token, ImeTracker.STATUS_TIMEOUT,
+                            ImeTracker.PHASE_NOT_SET);
+                }
+            }, TIMEOUT_MS);
+        }
         return token;
     }
 
     @NonNull
     @Override
-    public synchronized ImeTracker.Token onRequestHide(@NonNull String tag, int uid,
+    public ImeTracker.Token onRequestHide(@NonNull String tag, int uid,
             @ImeTracker.Origin int origin, @SoftInputShowHideReason int reason) {
         final var binder = new Binder();
         final var token = new ImeTracker.Token(binder, tag);
         final var entry = new History.Entry(tag, uid, ImeTracker.TYPE_HIDE, ImeTracker.STATUS_RUN,
                 origin, reason);
-        mHistory.addEntry(binder, entry);
+        synchronized (mLock) {
+            mHistory.addEntry(binder, entry);
 
-        // Register a delayed task to handle the case where the new entry times out.
-        mHandler.postDelayed(() -> {
-            synchronized (ImeTrackerService.this) {
-                mHistory.setFinished(token, ImeTracker.STATUS_TIMEOUT, ImeTracker.PHASE_NOT_SET);
-            }
-        }, TIMEOUT_MS);
-
+            // Register a delayed task to handle the case where the new entry times out.
+            mHandler.postDelayed(() -> {
+                synchronized (mLock) {
+                    mHistory.setFinished(token, ImeTracker.STATUS_TIMEOUT,
+                            ImeTracker.PHASE_NOT_SET);
+                }
+            }, TIMEOUT_MS);
+        }
         return token;
     }
 
     @Override
-    public synchronized void onProgress(@NonNull IBinder binder, @ImeTracker.Phase int phase) {
-        final var entry = mHistory.getEntry(binder);
-        if (entry == null) return;
+    public void onProgress(@NonNull IBinder binder, @ImeTracker.Phase int phase) {
+        synchronized (mLock) {
+            final var entry = mHistory.getEntry(binder);
+            if (entry == null) return;
 
-        entry.mPhase = phase;
+            entry.mPhase = phase;
+        }
     }
 
     @Override
-    public synchronized void onFailed(@NonNull ImeTracker.Token statsToken,
-            @ImeTracker.Phase int phase) {
-        mHistory.setFinished(statsToken, ImeTracker.STATUS_FAIL, phase);
+    public void onFailed(@NonNull ImeTracker.Token statsToken, @ImeTracker.Phase int phase) {
+        synchronized (mLock) {
+            mHistory.setFinished(statsToken, ImeTracker.STATUS_FAIL, phase);
+        }
     }
 
     @Override
-    public synchronized void onCancelled(@NonNull ImeTracker.Token statsToken,
-            @ImeTracker.Phase int phase) {
-        mHistory.setFinished(statsToken, ImeTracker.STATUS_CANCEL, phase);
+    public void onCancelled(@NonNull ImeTracker.Token statsToken, @ImeTracker.Phase int phase) {
+        synchronized (mLock) {
+            mHistory.setFinished(statsToken, ImeTracker.STATUS_CANCEL, phase);
+        }
     }
 
     @Override
-    public synchronized void onShown(@NonNull ImeTracker.Token statsToken) {
-        mHistory.setFinished(statsToken, ImeTracker.STATUS_SUCCESS, ImeTracker.PHASE_NOT_SET);
+    public void onShown(@NonNull ImeTracker.Token statsToken) {
+        synchronized (mLock) {
+            mHistory.setFinished(statsToken, ImeTracker.STATUS_SUCCESS, ImeTracker.PHASE_NOT_SET);
+        }
     }
 
     @Override
-    public synchronized void onHidden(@NonNull ImeTracker.Token statsToken) {
-        mHistory.setFinished(statsToken, ImeTracker.STATUS_SUCCESS, ImeTracker.PHASE_NOT_SET);
+    public void onHidden(@NonNull ImeTracker.Token statsToken) {
+        synchronized (mLock) {
+            mHistory.setFinished(statsToken, ImeTracker.STATUS_SUCCESS, ImeTracker.PHASE_NOT_SET);
+        }
     }
 
     /**
@@ -146,25 +161,30 @@
      * @param statsToken the token corresponding to the current IME request.
      * @param requestWindowName the name of the window that created the IME request.
      */
-    public synchronized void onImmsUpdate(@NonNull ImeTracker.Token statsToken,
+    public void onImmsUpdate(@NonNull ImeTracker.Token statsToken,
             @NonNull String requestWindowName) {
-        final var entry = mHistory.getEntry(statsToken.getBinder());
-        if (entry == null) return;
+        synchronized (mLock) {
+            final var entry = mHistory.getEntry(statsToken.getBinder());
+            if (entry == null) return;
 
-        entry.mRequestWindowName = requestWindowName;
+            entry.mRequestWindowName = requestWindowName;
+        }
     }
 
     /** Dumps the contents of the history. */
-    public synchronized void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
-        mHistory.dump(pw, prefix);
+    public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
+        synchronized (mLock) {
+            mHistory.dump(pw, prefix);
+        }
     }
 
     @EnforcePermission(Manifest.permission.TEST_INPUT_METHOD)
     @Override
-    public synchronized boolean hasPendingImeVisibilityRequests() {
+    public boolean hasPendingImeVisibilityRequests() {
         super.hasPendingImeVisibilityRequests_enforcePermission();
-
-        return !mHistory.mLiveEntries.isEmpty();
+        synchronized (mLock) {
+            return !mHistory.mLiveEntries.isEmpty();
+        }
     }
 
     /**
diff --git a/services/core/jni/OWNERS b/services/core/jni/OWNERS
index 7e8ce60..0e45f61 100644
--- a/services/core/jni/OWNERS
+++ b/services/core/jni/OWNERS
@@ -20,6 +20,7 @@
 per-file com_android_server_location_* = file:/location/java/android/location/OWNERS
 per-file com_android_server_locksettings_* = file:/services/core/java/com/android/server/locksettings/OWNERS
 per-file com_android_server_net_* = file:/services/core/java/com/android/server/net/OWNERS
+per-file com_android_server_pdb_* = file:/services/core/java/com/android/server/pdb/OWNERS
 per-file com_android_server_pm_* = file:/services/core/java/com/android/server/pm/OWNERS
 per-file com_android_server_power_* = file:/services/core/java/com/android/server/power/OWNERS
 per-file com_android_server_powerstats_* = file:/services/core/java/com/android/server/powerstats/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/pdb/OWNERS b/services/tests/servicestests/src/com/android/server/pdb/OWNERS
new file mode 100644
index 0000000..6dfb888
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pdb/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pdb/OWNERS
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index f3bf026..8b2de2f 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -53,6 +53,7 @@
 import android.app.usage.BroadcastResponseStatsList;
 import android.app.usage.ConfigurationStats;
 import android.app.usage.EventStats;
+import android.app.usage.Flags;
 import android.app.usage.IUsageStatsManager;
 import android.app.usage.UsageEvents;
 import android.app.usage.UsageEvents.Event;
@@ -2124,12 +2125,15 @@
         }
 
         private boolean canReportUsageStats() {
-            if (isCallingUidSystem()) {
-                return true; // System UID can always report UsageStats
+            final boolean isSystem = isCallingUidSystem();
+            if (!Flags.reportUsageStatsPermission()) {
+                // If the flag is disabled, do no check for the new permission and instead return
+                // true only if the calling uid is system since System UID can always report stats.
+                return isSystem;
             }
-
-            return getContext().checkCallingPermission(Manifest.permission.REPORT_USAGE_STATS)
-                    == PackageManager.PERMISSION_GRANTED;
+            return isSystem
+                    || getContext().checkCallingPermission(Manifest.permission.REPORT_USAGE_STATS)
+                        == PackageManager.PERMISSION_GRANTED;
         }
 
         private boolean hasObserverPermission() {