Merge "Do not show satellite icon when mobile connection is emergency only" into main
diff --git a/Android.bp b/Android.bp
index 019bf6508..5ada10d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -386,7 +386,7 @@
         // TODO(b/120066492): remove gps_debug and protolog.conf.json when the build
         // system propagates "required" properly.
         "gps_debug.conf",
-        "protolog.conf.json.gz",
+        "core.protolog.pb",
         "framework-res",
         // any install dependencies should go into framework-minus-apex-install-dependencies
         // rather than here to avoid bloating incremental build time
diff --git a/INPUT_OWNERS b/INPUT_OWNERS
index 44b2f38..06ead06 100644
--- a/INPUT_OWNERS
+++ b/INPUT_OWNERS
@@ -1,4 +1,6 @@
 # Bug component: 136048
+arpitks@google.com
+asmitapoddar@google.com
 hcutts@google.com
 joseprio@google.com
 michaelwr@google.com
diff --git a/OWNERS b/OWNERS
index 6bab92b..7ceca32 100644
--- a/OWNERS
+++ b/OWNERS
@@ -32,6 +32,7 @@
 per-file TestProtoLibraries.bp = file:platform/platform_testing:/libraries/health/OWNERS
 per-file TestProtoLibraries.bp = file:platform/tools/tradefederation:/OWNERS
 
+per-file INPUT_OWNERS = file:/INPUT_OWNERS
 per-file ZYGOTE_OWNERS = file:/ZYGOTE_OWNERS
 per-file SQLITE_OWNERS = file:/SQLITE_OWNERS
 
diff --git a/Ravenwood.bp b/Ravenwood.bp
index 2df6d58..c73e048 100644
--- a/Ravenwood.bp
+++ b/Ravenwood.bp
@@ -145,6 +145,16 @@
 }
 
 java_library {
+    name: "services.fakes.ravenwood-jarjar",
+    installable: false,
+    srcs: [":services.fakes-sources"],
+    libs: [
+        "services.core.ravenwood",
+    ],
+    jarjar_rules: ":ravenwood-services-jarjar-rules",
+}
+
+java_library {
     name: "mockito-ravenwood-prebuilt",
     installable: false,
     static_libs: [
@@ -189,6 +199,7 @@
         "ravenwood-helper-runtime",
         "hoststubgen-helper-runtime.ravenwood",
         "services.core.ravenwood-jarjar",
+        "services.fakes.ravenwood-jarjar",
 
         // Provide runtime versions of utils linked in below
         "junit",
@@ -197,6 +208,9 @@
         "mockito-ravenwood-prebuilt",
         "inline-mockito-ravenwood-prebuilt",
     ],
+    jni_libs: [
+        "libandroid_runtime",
+    ],
 }
 
 android_ravenwood_libgroup {
diff --git a/apex/jobscheduler/service/aconfig/device_idle.aconfig b/apex/jobscheduler/service/aconfig/device_idle.aconfig
index fc24b30..e4cb5ad 100644
--- a/apex/jobscheduler/service/aconfig/device_idle.aconfig
+++ b/apex/jobscheduler/service/aconfig/device_idle.aconfig
@@ -4,5 +4,5 @@
     name: "disable_wakelocks_in_light_idle"
     namespace: "backstage_power"
     description: "Disable wakelocks for background apps while Light Device Idle is active"
-    bug: "299329948"
+    bug: "326607666"
 }
diff --git a/apex/jobscheduler/service/aconfig/job.aconfig b/apex/jobscheduler/service/aconfig/job.aconfig
index ef9ac73..5e6d377 100644
--- a/apex/jobscheduler/service/aconfig/job.aconfig
+++ b/apex/jobscheduler/service/aconfig/job.aconfig
@@ -4,7 +4,7 @@
     name: "batch_active_bucket_jobs"
     namespace: "backstage_power"
     description: "Include jobs in the ACTIVE bucket in the job batching effort. Don't let them run as freely as they're ready."
-    bug: "299329948"
+    bug: "326607666"
 }
 
 flag {
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index 696c317..4832ea6 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -893,8 +893,9 @@
             }
             // Fall through when quick doze is not requested.
 
-            if (!mIsOffBody) {
-                // Quick doze was not requested and device is on body so turn the device active.
+            if (!mIsOffBody && !mForceIdle) {
+                // Quick doze wasn't requested, doze wasn't forced and device is on body
+                // so turn the device active.
                 mActiveReason = ACTIVE_REASON_ONBODY;
                 becomeActiveLocked("on_body", Process.myUid());
             }
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java
index aec464d..e96d07f 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/FlexibilityController.java
@@ -55,6 +55,7 @@
 import android.util.SparseArrayMap;
 import android.util.SparseIntArray;
 import android.util.SparseLongArray;
+import android.util.SparseSetArray;
 import android.util.TimeUtils;
 
 import com.android.internal.annotations.GuardedBy;
@@ -158,19 +159,6 @@
     @GuardedBy("mLock")
     private final SparseLongArray mLastSeenConstraintTimesElapsed = new SparseLongArray();
 
-    private DeviceIdleInternal mDeviceIdleInternal;
-    private final ArraySet<String> mPowerAllowlistedApps = new ArraySet<>();
-
-    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            switch (intent.getAction()) {
-                case PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED:
-                    mHandler.post(FlexibilityController.this::updatePowerAllowlistCache);
-                    break;
-            }
-        }
-    };
     @VisibleForTesting
     @GuardedBy("mLock")
     final FlexibilityTracker mFlexibilityTracker;
@@ -182,6 +170,7 @@
     private final FcHandler mHandler;
     @VisibleForTesting
     final PrefetchController mPrefetchController;
+    private final SpecialAppTracker mSpecialAppTracker;
 
     /**
      * Stores the beginning of prefetch jobs lifecycle per app as a maximum of
@@ -355,16 +344,16 @@
         mPercentsToDropConstraints =
                 FcConfig.DEFAULT_PERCENTS_TO_DROP_FLEXIBLE_CONSTRAINTS;
         mPrefetchController = prefetchController;
+        mSpecialAppTracker = new SpecialAppTracker();
 
         if (mFlexibilityEnabled) {
-            registerBroadcastReceiver();
+            mSpecialAppTracker.startTracking();
         }
     }
 
     @Override
     public void onSystemServicesReady() {
-        mDeviceIdleInternal = LocalServices.getService(DeviceIdleInternal.class);
-        mHandler.post(FlexibilityController.this::updatePowerAllowlistCache);
+        mSpecialAppTracker.onSystemServicesReady();
     }
 
     @Override
@@ -453,6 +442,7 @@
         final int userId = UserHandle.getUserId(uid);
         mPrefetchLifeCycleStart.delete(userId, packageName);
         mJobScoreTrackers.delete(uid, packageName);
+        mSpecialAppTracker.onAppRemoved(userId, packageName);
         for (int i = mJobsToCheck.size() - 1; i >= 0; --i) {
             final JobStatus js = mJobsToCheck.valueAt(i);
             if ((js.getSourceUid() == uid && js.getSourcePackageName().equals(packageName))
@@ -466,6 +456,7 @@
     @GuardedBy("mLock")
     public void onUserRemovedLocked(int userId) {
         mPrefetchLifeCycleStart.delete(userId);
+        mSpecialAppTracker.onUserRemoved(userId);
         for (int u = mJobScoreTrackers.numMaps() - 1; u >= 0; --u) {
             final int uid = mJobScoreTrackers.keyAt(u);
             if (UserHandle.getUserId(uid) == userId) {
@@ -496,9 +487,10 @@
                 // Only exclude DEFAULT+ priority jobs for BFGS+ apps
                 || (mService.getUidBias(js.getSourceUid()) >= JobInfo.BIAS_BOUND_FOREGROUND_SERVICE
                         && js.getEffectivePriority() >= PRIORITY_DEFAULT)
-                // For apps in the power allowlist, automatically exclude DEFAULT+ priority jobs.
+                // For special/privileged apps, automatically exclude DEFAULT+ priority jobs.
                 || (js.getEffectivePriority() >= PRIORITY_DEFAULT
-                        && mPowerAllowlistedApps.contains(js.getSourcePackageName()))
+                        && mSpecialAppTracker.isSpecialApp(
+                                js.getSourceUserId(), js.getSourcePackageName()))
                 || hasEnoughSatisfiedConstraintsLocked(js)
                 || mService.isCurrentlyRunningLocked(js);
     }
@@ -827,39 +819,6 @@
         mFcConfig.processConstantLocked(properties, key);
     }
 
-    private void registerBroadcastReceiver() {
-        IntentFilter filter = new IntentFilter(PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
-        mContext.registerReceiver(mBroadcastReceiver, filter);
-    }
-
-    private void unregisterBroadcastReceiver() {
-        mContext.unregisterReceiver(mBroadcastReceiver);
-    }
-
-    private void updatePowerAllowlistCache() {
-        if (mDeviceIdleInternal == null) {
-            return;
-        }
-
-        // Don't call out to DeviceIdleController with the lock held.
-        final String[] allowlistedPkgs = mDeviceIdleInternal.getFullPowerWhitelistExceptIdle();
-        final ArraySet<String> changedPkgs = new ArraySet<>();
-        synchronized (mLock) {
-            changedPkgs.addAll(mPowerAllowlistedApps);
-            mPowerAllowlistedApps.clear();
-            for (final String pkgName : allowlistedPkgs) {
-                mPowerAllowlistedApps.add(pkgName);
-                if (changedPkgs.contains(pkgName)) {
-                    changedPkgs.remove(pkgName);
-                } else {
-                    changedPkgs.add(pkgName);
-                }
-            }
-            mPackagesToCheck.addAll(changedPkgs);
-            mHandler.sendEmptyMessage(MSG_CHECK_PACKAGES);
-        }
-    }
-
     @VisibleForTesting
     class FlexibilityTracker {
         final ArrayList<ArraySet<JobStatus>> mTrackedJobs;
@@ -1343,12 +1302,12 @@
                             mFlexibilityEnabled = true;
                             mPrefetchController
                                     .registerPrefetchChangedListener(mPrefetchChangedListener);
-                            registerBroadcastReceiver();
+                            mSpecialAppTracker.startTracking();
                         } else {
                             mFlexibilityEnabled = false;
                             mPrefetchController
                                     .unRegisterPrefetchChangedListener(mPrefetchChangedListener);
-                            unregisterBroadcastReceiver();
+                            mSpecialAppTracker.stopTracking();
                         }
                     }
                     break;
@@ -1653,6 +1612,176 @@
         return mFcConfig;
     }
 
+    private class SpecialAppTracker {
+        /**
+         * Lock for objects inside this class. This should never be held when attempting to acquire
+         * {@link #mLock}. It is fine to acquire this if already holding {@link #mLock}.
+         */
+        private final Object mSatLock = new Object();
+
+        private DeviceIdleInternal mDeviceIdleInternal;
+
+        /** Set of all apps that have been deemed special, keyed by user ID. */
+        private final SparseSetArray<String> mSpecialApps = new SparseSetArray<>();
+        @GuardedBy("mSatLock")
+        private final ArraySet<String> mPowerAllowlistedApps = new ArraySet<>();
+
+        private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                switch (intent.getAction()) {
+                    case PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED:
+                        mHandler.post(SpecialAppTracker.this::updatePowerAllowlistCache);
+                        break;
+                }
+            }
+        };
+
+        public boolean isSpecialApp(final int userId, @NonNull String packageName) {
+            synchronized (mSatLock) {
+                if (mSpecialApps.contains(UserHandle.USER_ALL, packageName)) {
+                    return true;
+                }
+                if (mSpecialApps.contains(userId, packageName)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        private boolean isSpecialAppInternal(final int userId, @NonNull String packageName) {
+            synchronized (mSatLock) {
+                if (mPowerAllowlistedApps.contains(packageName)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        private void onAppRemoved(final int userId, String packageName) {
+            synchronized (mSatLock) {
+                // Don't touch the USER_ALL set here. If the app is completely removed from the
+                // device, any list that affects USER_ALL should update and this would eventually
+                // be updated with those lists no longer containing the app.
+                mSpecialApps.remove(userId, packageName);
+            }
+        }
+
+        private void onSystemServicesReady() {
+            mDeviceIdleInternal = LocalServices.getService(DeviceIdleInternal.class);
+
+            synchronized (mLock) {
+                if (mFlexibilityEnabled) {
+                    mHandler.post(SpecialAppTracker.this::updatePowerAllowlistCache);
+                }
+            }
+        }
+
+        private void onUserRemoved(final int userId) {
+            synchronized (mSatLock) {
+                mSpecialApps.remove(userId);
+            }
+        }
+
+        private void startTracking() {
+            IntentFilter filter = new IntentFilter(
+                    PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
+            mContext.registerReceiver(mBroadcastReceiver, filter);
+
+            updatePowerAllowlistCache();
+        }
+
+        private void stopTracking() {
+            mContext.unregisterReceiver(mBroadcastReceiver);
+
+            synchronized (mSatLock) {
+                mPowerAllowlistedApps.clear();
+                mSpecialApps.clear();
+            }
+        }
+
+        /**
+         * Update the processed special app set for the specified user ID, only looking at the
+         * specified set of apps. This method must <b>NEVER</b> be called while holding
+         * {@link #mSatLock}.
+         */
+        private void updateSpecialAppSetUnlocked(final int userId, @NonNull ArraySet<String> pkgs) {
+            // This method may need to acquire mLock, so ensure that mSatLock isn't held to avoid
+            // lock inversion.
+            if (Thread.holdsLock(mSatLock)) {
+                throw new IllegalStateException("Must never hold local mSatLock");
+            }
+            if (pkgs.size() == 0) {
+                return;
+            }
+            final ArraySet<String> changedPkgs = new ArraySet<>();
+
+            synchronized (mSatLock) {
+                for (int i = pkgs.size() - 1; i >= 0; --i) {
+                    final String pkgName = pkgs.valueAt(i);
+                    if (isSpecialAppInternal(userId, pkgName)) {
+                        if (mSpecialApps.add(userId, pkgName)) {
+                            changedPkgs.add(pkgName);
+                        }
+                    } else if (mSpecialApps.remove(userId, pkgName)) {
+                        changedPkgs.add(pkgName);
+                    }
+                }
+            }
+
+            if (changedPkgs.size() > 0) {
+                synchronized (mLock) {
+                    mPackagesToCheck.addAll(changedPkgs);
+                    mHandler.sendEmptyMessage(MSG_CHECK_PACKAGES);
+                }
+            }
+        }
+
+        private void updatePowerAllowlistCache() {
+            if (mDeviceIdleInternal == null) {
+                return;
+            }
+
+            // Don't call out to DeviceIdleController with the lock held.
+            final String[] allowlistedPkgs = mDeviceIdleInternal.getFullPowerWhitelistExceptIdle();
+            final ArraySet<String> changedPkgs = new ArraySet<>();
+            synchronized (mSatLock) {
+                changedPkgs.addAll(mPowerAllowlistedApps);
+                mPowerAllowlistedApps.clear();
+                for (String pkgName : allowlistedPkgs) {
+                    mPowerAllowlistedApps.add(pkgName);
+                    if (!changedPkgs.remove(pkgName)) {
+                        // The package wasn't in the previous set of allowlisted apps. Add it
+                        // since its state has changed.
+                        changedPkgs.add(pkgName);
+                    }
+                }
+            }
+
+            // The full allowlist is currently user-agnostic, so use USER_ALL for these packages.
+            updateSpecialAppSetUnlocked(UserHandle.USER_ALL, changedPkgs);
+        }
+
+        public void dump(@NonNull IndentingPrintWriter pw) {
+            pw.println("Special apps:");
+            pw.increaseIndent();
+
+            synchronized (mSatLock) {
+                for (int u = 0; u < mSpecialApps.size(); ++u) {
+                    pw.print(mSpecialApps.keyAt(u));
+                    pw.print(": ");
+                    pw.println(mSpecialApps.valuesAt(u));
+                }
+
+                pw.println();
+                pw.print("Power allowlisted packages: ");
+                pw.println(mPowerAllowlistedApps);
+            }
+
+            pw.decreaseIndent();
+        }
+    }
+
     @Override
     @GuardedBy("mLock")
     public void dumpConstants(IndentingPrintWriter pw) {
@@ -1690,8 +1819,7 @@
         pw.decreaseIndent();
 
         pw.println();
-        pw.print("Power allowlisted packages: ");
-        pw.println(mPowerAllowlistedApps);
+        mSpecialAppTracker.dump(pw);
 
         pw.println();
         mFlexibilityTracker.dump(pw, predicate, nowElapsed);
diff --git a/boot/Android.bp b/boot/Android.bp
index cdfa7c80..f60bb9e 100644
--- a/boot/Android.bp
+++ b/boot/Android.bp
@@ -31,6 +31,7 @@
         "car_bootclasspath_fragment",
         "nfc_apex_bootclasspath_fragment",
         "release_crashrecovery_module",
+        "release_package_profiling_module",
     ],
     properties: [
         "fragments",
@@ -122,10 +123,6 @@
             module: "com.android.permission-bootclasspath-fragment",
         },
         {
-            apex: "com.android.profiling",
-            module: "com.android.profiling-bootclasspath-fragment",
-        },
-        {
             apex: "com.android.scheduling",
             module: "com.android.scheduling-bootclasspath-fragment",
         },
@@ -179,6 +176,15 @@
                 },
             ],
         },
+        release_package_profiling_module: {
+            fragments: [
+                // only used if profiling is enabled.
+                {
+                    apex: "com.android.profiling",
+                    module: "com.android.profiling-bootclasspath-fragment",
+                },
+            ],
+        },
     },
 
     // Additional information needed by hidden api processing.
diff --git a/core/api/current.txt b/core/api/current.txt
index 3fd67db..ac98a94 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -203,7 +203,7 @@
     field public static final String MANAGE_DEVICE_POLICY_SYSTEM_APPS = "android.permission.MANAGE_DEVICE_POLICY_SYSTEM_APPS";
     field public static final String MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS = "android.permission.MANAGE_DEVICE_POLICY_SYSTEM_DIALOGS";
     field public static final String MANAGE_DEVICE_POLICY_SYSTEM_UPDATES = "android.permission.MANAGE_DEVICE_POLICY_SYSTEM_UPDATES";
-    field @FlaggedApi("com.android.net.thread.flags.thread_user_restriction_enabled") public static final String MANAGE_DEVICE_POLICY_THREAD_NETWORK = "android.permission.MANAGE_DEVICE_POLICY_THREAD_NETWORK";
+    field @FlaggedApi("com.android.net.thread.platform.flags.thread_user_restriction_enabled") public static final String MANAGE_DEVICE_POLICY_THREAD_NETWORK = "android.permission.MANAGE_DEVICE_POLICY_THREAD_NETWORK";
     field public static final String MANAGE_DEVICE_POLICY_TIME = "android.permission.MANAGE_DEVICE_POLICY_TIME";
     field public static final String MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING = "android.permission.MANAGE_DEVICE_POLICY_USB_DATA_SIGNALLING";
     field public static final String MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER = "android.permission.MANAGE_DEVICE_POLICY_USB_FILE_TRANSFER";
@@ -3350,7 +3350,6 @@
     method @FlaggedApi("android.view.accessibility.a11y_overlay_callbacks") public void attachAccessibilityOverlayToWindow(int, @NonNull android.view.SurfaceControl, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer);
     method public boolean clearCache();
     method public boolean clearCachedSubtree(@NonNull android.view.accessibility.AccessibilityNodeInfo);
-    method @FlaggedApi("android.view.accessibility.braille_display_hid") public void clearTestBrailleDisplayController();
     method public final void disableSelf();
     method public final boolean dispatchGesture(@NonNull android.accessibilityservice.GestureDescription, @Nullable android.accessibilityservice.AccessibilityService.GestureResultCallback, @Nullable android.os.Handler);
     method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
@@ -3386,7 +3385,6 @@
     method public boolean setCacheEnabled(boolean);
     method public void setGestureDetectionPassthroughRegion(int, @NonNull android.graphics.Region);
     method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo);
-    method @FlaggedApi("android.view.accessibility.braille_display_hid") public void setTestBrailleDisplayController(@NonNull android.accessibilityservice.BrailleDisplayController);
     method public void setTouchExplorationPassthroughRegion(int, @NonNull android.graphics.Region);
     method public void takeScreenshot(int, @NonNull java.util.concurrent.Executor, @NonNull android.accessibilityservice.AccessibilityService.TakeScreenshotCallback);
     method public void takeScreenshotOfWindow(int, @NonNull java.util.concurrent.Executor, @NonNull android.accessibilityservice.AccessibilityService.TakeScreenshotCallback);
@@ -10733,6 +10731,7 @@
     field public static final String DROPBOX_SERVICE = "dropbox";
     field public static final String EUICC_SERVICE = "euicc";
     field public static final String FILE_INTEGRITY_SERVICE = "file_integrity";
+    field public static final String FINGERPRINT_SERVICE = "fingerprint";
     field public static final String GAME_SERVICE = "game";
     field public static final String GRAMMATICAL_INFLECTION_SERVICE = "grammatical_inflection";
     field public static final String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
@@ -13217,7 +13216,7 @@
     field public static final String FEATURE_TELEPHONY_RADIO_ACCESS = "android.hardware.telephony.radio.access";
     field public static final String FEATURE_TELEPHONY_SUBSCRIPTION = "android.hardware.telephony.subscription";
     field @Deprecated public static final String FEATURE_TELEVISION = "android.hardware.type.television";
-    field @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform") public static final String FEATURE_THREAD_NETWORK = "android.hardware.thread_network";
+    field @FlaggedApi("com.android.net.thread.platform.flags.thread_enabled_platform") public static final String FEATURE_THREAD_NETWORK = "android.hardware.thread_network";
     field public static final String FEATURE_TOUCHSCREEN = "android.hardware.touchscreen";
     field public static final String FEATURE_TOUCHSCREEN_MULTITOUCH = "android.hardware.touchscreen.multitouch";
     field public static final String FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT = "android.hardware.touchscreen.multitouch.distinct";
@@ -13509,7 +13508,7 @@
     field public static final int FLAG_USE_APP_ZYGOTE = 8; // 0x8
     field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_CAMERA}, anyOf={android.Manifest.permission.CAMERA}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_CAMERA = 64; // 0x40
     field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE}, anyOf={android.Manifest.permission.BLUETOOTH_ADVERTISE, android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_SCAN, android.Manifest.permission.CHANGE_NETWORK_STATE, android.Manifest.permission.CHANGE_WIFI_STATE, android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE, android.Manifest.permission.NFC, android.Manifest.permission.TRANSMIT_IR, android.Manifest.permission.UWB_RANGING}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE = 16; // 0x10
-    field @Deprecated @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_DATA_SYNC, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_DATA_SYNC = 1; // 0x1
+    field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_DATA_SYNC, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_DATA_SYNC = 1; // 0x1
     field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_HEALTH}, anyOf={android.Manifest.permission.ACTIVITY_RECOGNITION, android.Manifest.permission.BODY_SENSORS, android.Manifest.permission.HIGH_SAMPLING_RATE_SENSORS}) public static final int FOREGROUND_SERVICE_TYPE_HEALTH = 256; // 0x100
     field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_LOCATION}, anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_LOCATION = 8; // 0x8
     field public static final int FOREGROUND_SERVICE_TYPE_MANIFEST = -1; // 0xffffffff
@@ -18053,6 +18052,24 @@
     method public android.graphics.pdf.PdfDocument.PageInfo.Builder setContentRect(android.graphics.Rect);
   }
 
+  public final class PdfRenderer implements java.lang.AutoCloseable {
+    ctor public PdfRenderer(@NonNull android.os.ParcelFileDescriptor) throws java.io.IOException;
+    method public void close();
+    method public int getPageCount();
+    method public android.graphics.pdf.PdfRenderer.Page openPage(int);
+    method public boolean shouldScaleForPrinting();
+  }
+
+  public final class PdfRenderer.Page implements java.lang.AutoCloseable {
+    method public void close();
+    method public int getHeight();
+    method public int getIndex();
+    method public int getWidth();
+    method public void render(@NonNull android.graphics.Bitmap, @Nullable android.graphics.Rect, @Nullable android.graphics.Matrix, int);
+    field public static final int RENDER_MODE_FOR_DISPLAY = 1; // 0x1
+    field public static final int RENDER_MODE_FOR_PRINT = 2; // 0x2
+  }
+
 }
 
 package android.graphics.text {
@@ -20363,6 +20380,54 @@
 
 }
 
+package android.hardware.fingerprint {
+
+  @Deprecated public class FingerprintManager {
+    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.USE_BIOMETRIC, android.Manifest.permission.USE_FINGERPRINT}) public void authenticate(@Nullable android.hardware.fingerprint.FingerprintManager.CryptoObject, @Nullable android.os.CancellationSignal, int, @NonNull android.hardware.fingerprint.FingerprintManager.AuthenticationCallback, @Nullable android.os.Handler);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean hasEnrolledFingerprints();
+    method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean isHardwareDetected();
+    field public static final int FINGERPRINT_ACQUIRED_GOOD = 0; // 0x0
+    field public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3; // 0x3
+    field public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2; // 0x2
+    field public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1; // 0x1
+    field public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5; // 0x5
+    field public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4; // 0x4
+    field public static final int FINGERPRINT_ERROR_CANCELED = 5; // 0x5
+    field public static final int FINGERPRINT_ERROR_HW_NOT_PRESENT = 12; // 0xc
+    field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1
+    field public static final int FINGERPRINT_ERROR_LOCKOUT = 7; // 0x7
+    field public static final int FINGERPRINT_ERROR_LOCKOUT_PERMANENT = 9; // 0x9
+    field public static final int FINGERPRINT_ERROR_NO_FINGERPRINTS = 11; // 0xb
+    field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
+    field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
+    field public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
+    field public static final int FINGERPRINT_ERROR_USER_CANCELED = 10; // 0xa
+    field public static final int FINGERPRINT_ERROR_VENDOR = 8; // 0x8
+  }
+
+  @Deprecated public abstract static class FingerprintManager.AuthenticationCallback {
+    ctor @Deprecated public FingerprintManager.AuthenticationCallback();
+    method @Deprecated public void onAuthenticationError(int, CharSequence);
+    method @Deprecated public void onAuthenticationFailed();
+    method @Deprecated public void onAuthenticationHelp(int, CharSequence);
+    method @Deprecated public void onAuthenticationSucceeded(android.hardware.fingerprint.FingerprintManager.AuthenticationResult);
+  }
+
+  @Deprecated public static class FingerprintManager.AuthenticationResult {
+    method @Deprecated public android.hardware.fingerprint.FingerprintManager.CryptoObject getCryptoObject();
+  }
+
+  @Deprecated public static final class FingerprintManager.CryptoObject {
+    ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull java.security.Signature);
+    ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull javax.crypto.Cipher);
+    ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull javax.crypto.Mac);
+    method @Deprecated public javax.crypto.Cipher getCipher();
+    method @Deprecated public javax.crypto.Mac getMac();
+    method @Deprecated public java.security.Signature getSignature();
+  }
+
+}
+
 package android.hardware.input {
 
   public final class HostUsiVersion implements android.os.Parcelable {
@@ -34019,7 +34084,7 @@
     field @FlaggedApi("android.app.admin.flags.esim_management_enabled") public static final String DISALLOW_SIM_GLOBALLY = "no_sim_globally";
     field public static final String DISALLOW_SMS = "no_sms";
     field public static final String DISALLOW_SYSTEM_ERROR_DIALOGS = "no_system_error_dialogs";
-    field @FlaggedApi("com.android.net.thread.flags.thread_user_restriction_enabled") public static final String DISALLOW_THREAD_NETWORK = "no_thread_network";
+    field @FlaggedApi("com.android.net.thread.platform.flags.thread_user_restriction_enabled") public static final String DISALLOW_THREAD_NETWORK = "no_thread_network";
     field public static final String DISALLOW_ULTRA_WIDEBAND_RADIO = "no_ultra_wideband_radio";
     field public static final String DISALLOW_UNIFIED_PASSWORD = "no_unified_password";
     field public static final String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
@@ -35750,54 +35815,6 @@
     field public static final String LONGITUDE = "longitude";
   }
 
-  @FlaggedApi("android.provider.user_keys") public final class ContactKeysManager {
-    method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.ContactKeysManager.ContactKey> getAllContactKeys(@NonNull String);
-    method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.ContactKeysManager.SelfKey> getAllSelfKeys();
-    method @Nullable @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public android.provider.ContactKeysManager.ContactKey getContactKey(@NonNull String, @NonNull String, @NonNull String);
-    method public static int getMaxKeySizeBytes();
-    method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.ContactKeysManager.ContactKey> getOwnerContactKeys(@NonNull String);
-    method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.ContactKeysManager.SelfKey> getOwnerSelfKeys();
-    method @Nullable @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public android.provider.ContactKeysManager.SelfKey getSelfKey(@NonNull String, @NonNull String);
-    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean removeContactKey(@NonNull String, @NonNull String, @NonNull String);
-    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean removeSelfKey(@NonNull String, @NonNull String);
-    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateContactKeyLocalVerificationState(@NonNull String, @NonNull String, @NonNull String, int);
-    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateContactKeyRemoteVerificationState(@NonNull String, @NonNull String, @NonNull String, int);
-    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public void updateOrInsertContactKey(@NonNull String, @NonNull String, @NonNull String, @NonNull byte[]);
-    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateOrInsertSelfKey(@NonNull String, @NonNull String, @NonNull byte[]);
-    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateSelfKeyRemoteVerificationState(@NonNull String, @NonNull String, int);
-    field public static final int VERIFICATION_STATE_UNVERIFIED = 0; // 0x0
-    field public static final int VERIFICATION_STATE_VERIFICATION_FAILED = 1; // 0x1
-    field public static final int VERIFICATION_STATE_VERIFIED = 2; // 0x2
-  }
-
-  public static final class ContactKeysManager.ContactKey implements android.os.Parcelable {
-    method public int describeContents();
-    method @NonNull public String getAccountId();
-    method @Nullable public String getDeviceId();
-    method @Nullable public String getDisplayName();
-    method @Nullable public String getEmailAddress();
-    method @Nullable public byte[] getKeyValue();
-    method public int getLocalVerificationState();
-    method @NonNull public String getOwnerPackageName();
-    method @Nullable public String getPhoneNumber();
-    method public int getRemoteVerificationState();
-    method public long getTimeUpdated();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.provider.ContactKeysManager.ContactKey> CREATOR;
-  }
-
-  public static final class ContactKeysManager.SelfKey implements android.os.Parcelable {
-    method public int describeContents();
-    method @NonNull public String getAccountId();
-    method @Nullable public String getDeviceId();
-    method @Nullable public byte[] getKeyValue();
-    method @NonNull public String getOwnerPackageName();
-    method public int getRemoteVerificationState();
-    method public long getTimeUpdated();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.provider.ContactKeysManager.SelfKey> CREATOR;
-  }
-
   @Deprecated public class Contacts {
     field @Deprecated public static final String AUTHORITY = "contacts";
     field @Deprecated public static final android.net.Uri CONTENT_URI;
@@ -37098,6 +37115,54 @@
     method public final int update(android.net.Uri, android.content.ContentValues, String, String[]);
   }
 
+  @FlaggedApi("android.provider.user_keys") public final class E2eeContactKeysManager {
+    method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.E2eeContactKeysManager.E2eeContactKey> getAllE2eeContactKeys(@NonNull String);
+    method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.E2eeContactKeysManager.E2eeSelfKey> getAllE2eeSelfKeys();
+    method @Nullable @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public android.provider.E2eeContactKeysManager.E2eeContactKey getE2eeContactKey(@NonNull String, @NonNull String, @NonNull String);
+    method @Nullable @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public android.provider.E2eeContactKeysManager.E2eeSelfKey getE2eeSelfKey(@NonNull String, @NonNull String);
+    method public static int getMaxKeySizeBytes();
+    method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.E2eeContactKeysManager.E2eeContactKey> getOwnerE2eeContactKeys(@NonNull String);
+    method @NonNull @RequiresPermission(android.Manifest.permission.READ_CONTACTS) public java.util.List<android.provider.E2eeContactKeysManager.E2eeSelfKey> getOwnerE2eeSelfKeys();
+    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean removeE2eeContactKey(@NonNull String, @NonNull String, @NonNull String);
+    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean removeE2eeSelfKey(@NonNull String, @NonNull String);
+    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateE2eeContactKeyLocalVerificationState(@NonNull String, @NonNull String, @NonNull String, int);
+    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateE2eeContactKeyRemoteVerificationState(@NonNull String, @NonNull String, @NonNull String, int);
+    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateE2eeSelfKeyRemoteVerificationState(@NonNull String, @NonNull String, int);
+    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public void updateOrInsertE2eeContactKey(@NonNull String, @NonNull String, @NonNull String, @NonNull byte[]);
+    method @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS) public boolean updateOrInsertE2eeSelfKey(@NonNull String, @NonNull String, @NonNull byte[]);
+    field public static final int VERIFICATION_STATE_UNVERIFIED = 0; // 0x0
+    field public static final int VERIFICATION_STATE_VERIFICATION_FAILED = 1; // 0x1
+    field public static final int VERIFICATION_STATE_VERIFIED = 2; // 0x2
+  }
+
+  public static final class E2eeContactKeysManager.E2eeContactKey implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public String getAccountId();
+    method @Nullable public String getDeviceId();
+    method @Nullable public String getDisplayName();
+    method @Nullable public String getEmailAddress();
+    method @Nullable public byte[] getKeyValue();
+    method public int getLocalVerificationState();
+    method @NonNull public String getOwnerPackageName();
+    method @Nullable public String getPhoneNumber();
+    method public int getRemoteVerificationState();
+    method public long getTimeUpdated();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.provider.E2eeContactKeysManager.E2eeContactKey> CREATOR;
+  }
+
+  public static final class E2eeContactKeysManager.E2eeSelfKey implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public String getAccountId();
+    method @Nullable public String getDeviceId();
+    method @Nullable public byte[] getKeyValue();
+    method @NonNull public String getOwnerPackageName();
+    method public int getRemoteVerificationState();
+    method public long getTimeUpdated();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.provider.E2eeContactKeysManager.E2eeSelfKey> CREATOR;
+  }
+
   @Deprecated public final class FontRequest {
     ctor @Deprecated public FontRequest(@NonNull String, @NonNull String, @NonNull String);
     ctor @Deprecated public FontRequest(@NonNull String, @NonNull String, @NonNull String, @NonNull java.util.List<java.util.List<byte[]>>);
@@ -39734,6 +39799,7 @@
     method @Deprecated public boolean isInsideSecureHardware();
     method public boolean isInvalidatedByBiometricEnrollment();
     method public boolean isTrustedUserPresenceRequired();
+    method @FlaggedApi("android.security.keyinfo_unlocked_device_required") public boolean isUnlockedDeviceRequired();
     method public boolean isUserAuthenticationRequired();
     method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware();
     method public boolean isUserAuthenticationValidWhileOnBody();
diff --git a/core/api/removed.txt b/core/api/removed.txt
index c61f163..3c7c0d6 100644
--- a/core/api/removed.txt
+++ b/core/api/removed.txt
@@ -35,7 +35,6 @@
     method @Deprecated @Nullable public String getFeatureId();
     method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
     method public abstract java.io.File getSharedPreferencesPath(String);
-    field public static final String FINGERPRINT_SERVICE = "fingerprint";
   }
 
   public class ContextWrapper extends android.content.Context {
@@ -146,54 +145,6 @@
 
 }
 
-package android.hardware.fingerprint {
-
-  @Deprecated public class FingerprintManager {
-    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.USE_BIOMETRIC, android.Manifest.permission.USE_FINGERPRINT}) public void authenticate(@Nullable android.hardware.fingerprint.FingerprintManager.CryptoObject, @Nullable android.os.CancellationSignal, int, @NonNull android.hardware.fingerprint.FingerprintManager.AuthenticationCallback, @Nullable android.os.Handler);
-    method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean hasEnrolledFingerprints();
-    method @Deprecated @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT) public boolean isHardwareDetected();
-    field public static final int FINGERPRINT_ACQUIRED_GOOD = 0; // 0x0
-    field public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3; // 0x3
-    field public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2; // 0x2
-    field public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1; // 0x1
-    field public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5; // 0x5
-    field public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4; // 0x4
-    field public static final int FINGERPRINT_ERROR_CANCELED = 5; // 0x5
-    field public static final int FINGERPRINT_ERROR_HW_NOT_PRESENT = 12; // 0xc
-    field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1
-    field public static final int FINGERPRINT_ERROR_LOCKOUT = 7; // 0x7
-    field public static final int FINGERPRINT_ERROR_LOCKOUT_PERMANENT = 9; // 0x9
-    field public static final int FINGERPRINT_ERROR_NO_FINGERPRINTS = 11; // 0xb
-    field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
-    field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
-    field public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
-    field public static final int FINGERPRINT_ERROR_USER_CANCELED = 10; // 0xa
-    field public static final int FINGERPRINT_ERROR_VENDOR = 8; // 0x8
-  }
-
-  @Deprecated public abstract static class FingerprintManager.AuthenticationCallback {
-    ctor public FingerprintManager.AuthenticationCallback();
-    method public void onAuthenticationError(int, CharSequence);
-    method public void onAuthenticationFailed();
-    method public void onAuthenticationHelp(int, CharSequence);
-    method public void onAuthenticationSucceeded(android.hardware.fingerprint.FingerprintManager.AuthenticationResult);
-  }
-
-  @Deprecated public static class FingerprintManager.AuthenticationResult {
-    method public android.hardware.fingerprint.FingerprintManager.CryptoObject getCryptoObject();
-  }
-
-  @Deprecated public static final class FingerprintManager.CryptoObject {
-    ctor public FingerprintManager.CryptoObject(@NonNull java.security.Signature);
-    ctor public FingerprintManager.CryptoObject(@NonNull javax.crypto.Cipher);
-    ctor public FingerprintManager.CryptoObject(@NonNull javax.crypto.Mac);
-    method public javax.crypto.Cipher getCipher();
-    method public javax.crypto.Mac getMac();
-    method public java.security.Signature getSignature();
-  }
-
-}
-
 package android.media {
 
   public final class AudioFormat implements android.os.Parcelable {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index cc7d97a..67ccd9d 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -327,7 +327,7 @@
     field public static final String RECOVER_KEYSTORE = "android.permission.RECOVER_KEYSTORE";
     field public static final String REGISTER_CALL_PROVIDER = "android.permission.REGISTER_CALL_PROVIDER";
     field public static final String REGISTER_CONNECTION_MANAGER = "android.permission.REGISTER_CONNECTION_MANAGER";
-    field @FlaggedApi("com.android.net.flags.register_nsd_offload_engine") public static final String REGISTER_NSD_OFFLOAD_ENGINE = "android.permission.REGISTER_NSD_OFFLOAD_ENGINE";
+    field @FlaggedApi("android.net.platform.flags.register_nsd_offload_engine") public static final String REGISTER_NSD_OFFLOAD_ENGINE = "android.permission.REGISTER_NSD_OFFLOAD_ENGINE";
     field public static final String REGISTER_SIM_SUBSCRIPTION = "android.permission.REGISTER_SIM_SUBSCRIPTION";
     field public static final String REGISTER_STATS_PULL_ATOM = "android.permission.REGISTER_STATS_PULL_ATOM";
     field public static final String REMOTE_DISPLAY_PROVIDER = "android.permission.REMOTE_DISPLAY_PROVIDER";
@@ -388,7 +388,7 @@
     field public static final String SYSTEM_APPLICATION_OVERLAY = "android.permission.SYSTEM_APPLICATION_OVERLAY";
     field public static final String SYSTEM_CAMERA = "android.permission.SYSTEM_CAMERA";
     field public static final String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED";
-    field @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform") public static final String THREAD_NETWORK_PRIVILEGED = "android.permission.THREAD_NETWORK_PRIVILEGED";
+    field @FlaggedApi("com.android.net.thread.platform.flags.thread_enabled_platform") public static final String THREAD_NETWORK_PRIVILEGED = "android.permission.THREAD_NETWORK_PRIVILEGED";
     field public static final String TIS_EXTENSION_INTERFACE = "android.permission.TIS_EXTENSION_INTERFACE";
     field public static final String TOGGLE_AUTOMOTIVE_PROJECTION = "android.permission.TOGGLE_AUTOMOTIVE_PROJECTION";
     field public static final String TRIGGER_LOST_MODE = "android.permission.TRIGGER_LOST_MODE";
@@ -1146,7 +1146,6 @@
   public static final class StatusBarManager.DisableInfo implements android.os.Parcelable {
     method public boolean areAllComponentsEnabled();
     method public int describeContents();
-    method public boolean isBackDisabled();
     method public boolean isNavigateToHomeDisabled();
     method public boolean isNotificationPeekingDisabled();
     method public boolean isRecentsDisabled();
@@ -1648,14 +1647,12 @@
     method public int getDensityLevel();
     method @NonNull public java.time.Instant getEndTime();
     method public int getEventType();
-    method @FlaggedApi("android.app.ambient_heart_rate") @IntRange(from=0xffffffff) public int getRatePerMinute();
     method @NonNull public java.time.Instant getStartTime();
     method @NonNull public android.os.PersistableBundle getVendorData();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.ambientcontext.AmbientContextEvent> CREATOR;
     field public static final int EVENT_BACK_DOUBLE_TAP = 3; // 0x3
     field public static final int EVENT_COUGH = 1; // 0x1
-    field @FlaggedApi("android.app.ambient_heart_rate") public static final int EVENT_HEART_RATE = 4; // 0x4
     field public static final int EVENT_SNORE = 2; // 0x2
     field public static final int EVENT_UNKNOWN = 0; // 0x0
     field public static final int EVENT_VENDOR_WEARABLE_START = 100000; // 0x186a0
@@ -1666,7 +1663,6 @@
     field public static final int LEVEL_MEDIUM_HIGH = 4; // 0x4
     field public static final int LEVEL_MEDIUM_LOW = 2; // 0x2
     field public static final int LEVEL_UNKNOWN = 0; // 0x0
-    field @FlaggedApi("android.app.ambient_heart_rate") public static final int RATE_PER_MINUTE_UNKNOWN = -1; // 0xffffffff
   }
 
   public static final class AmbientContextEvent.Builder {
@@ -1676,7 +1672,6 @@
     method @NonNull public android.app.ambientcontext.AmbientContextEvent.Builder setDensityLevel(int);
     method @NonNull public android.app.ambientcontext.AmbientContextEvent.Builder setEndTime(@NonNull java.time.Instant);
     method @NonNull public android.app.ambientcontext.AmbientContextEvent.Builder setEventType(int);
-    method @FlaggedApi("android.app.ambient_heart_rate") @NonNull public android.app.ambientcontext.AmbientContextEvent.Builder setRatePerMinute(@IntRange(from=0xffffffff) int);
     method @NonNull public android.app.ambientcontext.AmbientContextEvent.Builder setStartTime(@NonNull java.time.Instant);
     method @NonNull public android.app.ambientcontext.AmbientContextEvent.Builder setVendorData(@NonNull android.os.PersistableBundle);
   }
@@ -3788,7 +3783,7 @@
     field public static final String SYSTEM_CONFIG_SERVICE = "system_config";
     field public static final String SYSTEM_UPDATE_SERVICE = "system_update";
     field public static final String TETHERING_SERVICE = "tethering";
-    field @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform") public static final String THREAD_NETWORK_SERVICE = "thread_network";
+    field @FlaggedApi("com.android.net.thread.platform.flags.thread_enabled_platform") public static final String THREAD_NETWORK_SERVICE = "thread_network";
     field public static final String TIME_MANAGER_SERVICE = "time_manager";
     field public static final String TRANSLATION_MANAGER_SERVICE = "translation";
     field public static final String UI_TRANSLATION_SERVICE = "ui_translation";
@@ -10422,8 +10417,7 @@
 
   @FlaggedApi("android.nfc.enable_nfc_mainline") public final class ApduServiceInfo implements android.os.Parcelable {
     ctor @FlaggedApi("android.nfc.enable_nfc_mainline") public ApduServiceInfo(@NonNull android.content.pm.PackageManager, @NonNull android.content.pm.ResolveInfo, boolean) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void addPollingLoopFilter(@NonNull String);
-    method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void addPollingLoopFilterToAutoTransact(@NonNull String);
+    method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void addPollingLoopFilter(@NonNull String, boolean);
     method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean defaultToObserveMode();
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public int describeContents();
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public void dump(@NonNull android.os.ParcelFileDescriptor, @NonNull java.io.PrintWriter, @NonNull String[]);
@@ -11531,7 +11525,7 @@
 
   public final class PermissionManager {
     method public int checkDeviceIdentifierAccess(@Nullable String, @Nullable String, @Nullable String, int, int);
-    method @FlaggedApi("android.permission.flags.device_aware_permission_apis_enabled") public static int checkPermission(@NonNull String, @NonNull String, @NonNull String, int);
+    method @FlaggedApi("android.permission.flags.device_aware_permission_apis_enabled") public int checkPermission(@NonNull String, @NonNull String, @NonNull String);
     method @RequiresPermission(value=android.Manifest.permission.UPDATE_APP_OPS_STATS, conditional=true) public int checkPermissionForDataDelivery(@NonNull String, @NonNull android.content.AttributionSource, @Nullable String);
     method @RequiresPermission(value=android.Manifest.permission.UPDATE_APP_OPS_STATS, conditional=true) public int checkPermissionForDataDeliveryFromDataSource(@NonNull String, @NonNull android.content.AttributionSource, @Nullable String);
     method public int checkPermissionForPreflight(@NonNull String, @NonNull android.content.AttributionSource);
@@ -11710,12 +11704,6 @@
     field public static final int ERROR_UNKNOWN = 0; // 0x0
   }
 
-  @FlaggedApi("android.provider.user_keys") public final class ContactKeysManager {
-    method @RequiresPermission(allOf={android.Manifest.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS, android.Manifest.permission.WRITE_CONTACTS}) public boolean updateContactKeyLocalVerificationState(@NonNull String, @NonNull String, @NonNull String, @NonNull String, int);
-    method @RequiresPermission(allOf={android.Manifest.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS, android.Manifest.permission.WRITE_CONTACTS}) public boolean updateContactKeyRemoteVerificationState(@NonNull String, @NonNull String, @NonNull String, @NonNull String, int);
-    method @RequiresPermission(allOf={android.Manifest.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS, android.Manifest.permission.WRITE_CONTACTS}) public boolean updateSelfKeyRemoteVerificationState(@NonNull String, @NonNull String, @NonNull String, int);
-  }
-
   @Deprecated public static final class ContactsContract.MetadataSync implements android.provider.BaseColumns android.provider.ContactsContract.MetadataSyncColumns {
     field @Deprecated public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_metadata";
     field @Deprecated public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact_metadata";
@@ -11773,6 +11761,12 @@
     field public static final int FLAG_REMOVABLE_USB = 524288; // 0x80000
   }
 
+  @FlaggedApi("android.provider.user_keys") public final class E2eeContactKeysManager {
+    method @RequiresPermission(allOf={android.Manifest.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS, android.Manifest.permission.WRITE_CONTACTS}) public boolean updateE2eeContactKeyLocalVerificationState(@NonNull String, @NonNull String, @NonNull String, @NonNull String, int);
+    method @RequiresPermission(allOf={android.Manifest.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS, android.Manifest.permission.WRITE_CONTACTS}) public boolean updateE2eeContactKeyRemoteVerificationState(@NonNull String, @NonNull String, @NonNull String, @NonNull String, int);
+    method @RequiresPermission(allOf={android.Manifest.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS, android.Manifest.permission.WRITE_CONTACTS}) public boolean updateE2eeSelfKeyRemoteVerificationState(@NonNull String, @NonNull String, @NonNull String, int);
+  }
+
   public abstract class SearchIndexableData {
     ctor public SearchIndexableData();
     ctor public SearchIndexableData(android.content.Context);
@@ -14204,7 +14198,8 @@
     method @Deprecated public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsForPackage();
     method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsSupportingScheme(String);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isInEmergencyCall();
-    method @FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies") @RequiresPermission(allOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isInSelfManagedCall(@NonNull String, @NonNull android.os.UserHandle, boolean);
+    method @FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies") @RequiresPermission(allOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isInSelfManagedCall(@NonNull String, @NonNull android.os.UserHandle);
+    method @FlaggedApi("com.android.server.telecom.flags.telecom_resolve_hidden_dependencies") @RequiresPermission(allOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isInSelfManagedCall(@NonNull String, boolean);
     method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUserSelectedOutgoingPhoneAccount(@Nullable android.telecom.PhoneAccountHandle);
     field public static final String ACTION_CURRENT_TTY_MODE_CHANGED = "android.telecom.action.CURRENT_TTY_MODE_CHANGED";
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index e1e9d09..b8c32a4 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -251,6 +251,7 @@
     method @RequiresPermission("android.permission.MANAGE_APPOPS") public void getHistoricalOpsFromDiskRaw(@NonNull android.app.AppOpsManager.HistoricalOpsRequest, @Nullable java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.app.AppOpsManager.HistoricalOps>);
     method public static int getNumOps();
     method public boolean isOperationActive(int, int, String);
+    method public int noteOpNoThrow(int, @NonNull android.content.AttributionSource, @Nullable String);
     method @RequiresPermission("android.permission.MANAGE_APPOPS") public void offsetHistory(long);
     method public static String opToPermission(int);
     method public static int permissionToOpCode(String);
@@ -1711,6 +1712,15 @@
 
 }
 
+package android.hardware.fingerprint {
+
+  @Deprecated public class FingerprintManager {
+    method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public android.hardware.biometrics.BiometricTestSession createTestSession(int);
+    method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public java.util.List<android.hardware.biometrics.SensorProperties> getSensorProperties();
+  }
+
+}
+
 package android.hardware.hdmi {
 
   public final class HdmiControlServiceWrapper {
@@ -3957,6 +3967,7 @@
   }
 
   public final class InputMethodInfo implements android.os.Parcelable {
+    ctor public InputMethodInfo(@NonNull String, @NonNull String, @NonNull CharSequence, @NonNull String, @NonNull String, boolean, @NonNull String);
     ctor @FlaggedApi("android.view.inputmethod.connectionless_handwriting") public InputMethodInfo(@NonNull String, @NonNull String, @NonNull CharSequence, @NonNull String, @NonNull String, boolean, boolean, @NonNull String);
     ctor public InputMethodInfo(@NonNull String, @NonNull String, @NonNull CharSequence, @NonNull String, int);
     field public static final int COMPONENT_NAME_MAX_LENGTH = 1000; // 0x3e8
diff --git a/core/api/test-removed.txt b/core/api/test-removed.txt
index 2e44176..d802177 100644
--- a/core/api/test-removed.txt
+++ b/core/api/test-removed.txt
@@ -1,10 +1 @@
 // Signature format: 2.0
-package android.hardware.fingerprint {
-
-  @Deprecated public class FingerprintManager {
-    method @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public android.hardware.biometrics.BiometricTestSession createTestSession(int);
-    method @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public java.util.List<android.hardware.biometrics.SensorProperties> getSensorProperties();
-  }
-
-}
-
diff --git a/core/java/Android.bp b/core/java/Android.bp
index eba500d..ab1c9a4 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -126,6 +126,7 @@
     srcs: [
         "android/os/IExternalVibrationController.aidl",
         "android/os/IExternalVibratorService.aidl",
+        "android/os/ExternalVibrationScale.aidl",
     ],
 }
 
@@ -527,14 +528,10 @@
     ],
 }
 
-// common protolog sources without classes that rely on Android SDK
-filegroup {
-    name: "protolog-common-no-android-src",
+java_library {
+    name: "protolog-group",
     srcs: [
-        ":protolog-common-src",
-    ],
-    exclude_srcs: [
-        "com/android/internal/protolog/common/ProtoLog.java",
+        "com/android/internal/protolog/common/IProtoLogGroup.java",
     ],
 }
 
@@ -547,13 +544,20 @@
     ],
 }
 
+filegroup {
+    name: "protolog-impl",
+    srcs: [
+        "com/android/internal/protolog/ProtoLogImpl.java",
+    ],
+}
+
 java_library {
     name: "protolog-lib",
     platform_apis: true,
     srcs: [
         "com/android/internal/protolog/ProtoLogImpl.java",
         "com/android/internal/protolog/ProtoLogViewerConfigReader.java",
-        ":protolog-common-src",
+        ":perfetto_trace_javastream_protos",
     ],
 }
 
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 42c3272..d70fa19 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -81,7 +81,6 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.Collections;
 import java.util.List;
-import java.util.Objects;
 import java.util.concurrent.Executor;
 import java.util.function.Consumer;
 import java.util.function.IntConsumer;
@@ -853,7 +852,6 @@
     private final SparseArray<AccessibilityButtonController> mAccessibilityButtonControllers =
             new SparseArray<>(0);
     private BrailleDisplayController mBrailleDisplayController;
-    private BrailleDisplayController mTestBrailleDisplayController;
 
     private int mGestureStatusCallbackSequence;
 
@@ -3650,46 +3648,10 @@
     public BrailleDisplayController getBrailleDisplayController() {
         BrailleDisplayController.checkApiFlagIsEnabled();
         synchronized (mLock) {
-            if (mTestBrailleDisplayController != null) {
-                return mTestBrailleDisplayController;
-            }
-
             if (mBrailleDisplayController == null) {
                 mBrailleDisplayController = new BrailleDisplayControllerImpl(this, mLock);
             }
             return mBrailleDisplayController;
         }
     }
-
-    /**
-     * Set the {@link BrailleDisplayController} implementation that will be returned by
-     * {@link #getBrailleDisplayController}, to allow this accessibility service to test its
-     * interaction with BrailleDisplayController without requiring a real Braille display.
-     *
-     * <p>For full test fidelity, ensure that this test-only implementation follows the same
-     * behavior specified in the documentation for {@link BrailleDisplayController}, including
-     * thrown exceptions.
-     *
-     * @param controller A test-only implementation of {@link BrailleDisplayController}.
-     */
-    @FlaggedApi(android.view.accessibility.Flags.FLAG_BRAILLE_DISPLAY_HID)
-    public void setTestBrailleDisplayController(@NonNull BrailleDisplayController controller) {
-        BrailleDisplayController.checkApiFlagIsEnabled();
-        Objects.requireNonNull(controller);
-        synchronized (mLock) {
-            mTestBrailleDisplayController = controller;
-        }
-    }
-
-    /**
-     * Clears the {@link BrailleDisplayController} previously set by
-     * {@link #setTestBrailleDisplayController}.
-     */
-    @FlaggedApi(android.view.accessibility.Flags.FLAG_BRAILLE_DISPLAY_HID)
-    public void clearTestBrailleDisplayController() {
-        BrailleDisplayController.checkApiFlagIsEnabled();
-        synchronized (mLock) {
-            mTestBrailleDisplayController = null;
-        }
-    }
 }
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 251f823..57c67be 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1002,6 +1002,9 @@
             new ActivityManager.TaskDescription();
     private int mLastTaskDescriptionHashCode;
 
+    @ActivityInfo.ScreenOrientation
+    private int mLastRequestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSET;
+
     protected static final int[] FOCUSED_STATE_SET = {com.android.internal.R.attr.state_focused};
 
     @SuppressWarnings("unused")
@@ -7530,11 +7533,15 @@
      * {@link ActivityInfo#screenOrientation ActivityInfo.screenOrientation}.
      */
     public void setRequestedOrientation(@ActivityInfo.ScreenOrientation int requestedOrientation) {
+        if (requestedOrientation == mLastRequestedOrientation) {
+            return;
+        }
         if (mParent == null) {
             ActivityClient.getInstance().setRequestedOrientation(mToken, requestedOrientation);
         } else {
             mParent.setRequestedOrientation(requestedOrientation);
         }
+        mLastRequestedOrientation = requestedOrientation;
     }
 
     /**
@@ -7548,6 +7555,9 @@
      */
     @ActivityInfo.ScreenOrientation
     public int getRequestedOrientation() {
+        if (mLastRequestedOrientation != ActivityInfo.SCREEN_ORIENTATION_UNSET) {
+            return mLastRequestedOrientation;
+        }
         if (mParent == null) {
             return ActivityClient.getInstance().getRequestedOrientation(mToken);
         } else {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index ae556c9..41151c0 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -211,6 +211,7 @@
 import android.view.translation.TranslationSpec;
 import android.view.translation.UiTranslationSpec;
 import android.webkit.WebView;
+import android.window.ActivityWindowInfo;
 import android.window.ITaskFragmentOrganizer;
 import android.window.SizeConfigurationBuckets;
 import android.window.SplashScreen;
@@ -603,6 +604,9 @@
         boolean hideForNow;
         Configuration createdConfig;
         Configuration overrideConfig;
+        @NonNull
+        private ActivityWindowInfo mActivityWindowInfo;
+
         // Used for consolidating configs before sending on to Activity.
         private final Configuration tmpConfig = new Configuration();
         // Callback used for updating activity override config and camera compat control state.
@@ -670,7 +674,8 @@
                 List<ReferrerIntent> pendingNewIntents, SceneTransitionInfo sceneTransitionInfo,
                 boolean isForward, ProfilerInfo profilerInfo, ClientTransactionHandler client,
                 IBinder assistToken, IBinder shareableActivityToken, boolean launchedFromBubble,
-                IBinder taskFragmentToken, IBinder initialCallerInfoAccessToken) {
+                IBinder taskFragmentToken, IBinder initialCallerInfoAccessToken,
+                ActivityWindowInfo activityWindowInfo) {
             this.token = token;
             this.assistToken = assistToken;
             this.shareableActivityToken = shareableActivityToken;
@@ -691,6 +696,7 @@
             mSceneTransitionInfo = sceneTransitionInfo;
             mLaunchedFromBubble = launchedFromBubble;
             mTaskFragmentToken = taskFragmentToken;
+            mActivityWindowInfo = activityWindowInfo;
             init();
         }
 
@@ -711,7 +717,7 @@
                     }
                     activity.mMainThread.handleActivityConfigurationChanged(
                             ActivityClientRecord.this, overrideConfig, newDisplayId,
-                            false /* alwaysReportChange */);
+                            mActivityWindowInfo, false /* alwaysReportChange */);
                 }
 
                 @Override
@@ -779,6 +785,11 @@
             return activity != null && activity.mVisibleFromServer;
         }
 
+        @NonNull
+        public ActivityWindowInfo getActivityWindowInfo() {
+            return mActivityWindowInfo;
+        }
+
         public String toString() {
             ComponentName componentName = intent != null ? intent.getComponent() : null;
             return "ActivityRecord{"
@@ -5987,9 +5998,11 @@
     }
 
     @Override
-    public ActivityClientRecord prepareRelaunchActivity(IBinder token,
-            List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
-            int configChanges, MergedConfiguration config, boolean preserveWindow) {
+    public ActivityClientRecord prepareRelaunchActivity(@NonNull IBinder token,
+            @Nullable List<ResultInfo> pendingResults,
+            @Nullable List<ReferrerIntent> pendingNewIntents, int configChanges,
+            @NonNull MergedConfiguration config, boolean preserveWindow,
+            @NonNull ActivityWindowInfo activityWindowInfo) {
         ActivityClientRecord target = null;
         boolean scheduleRelaunch = false;
 
@@ -6030,14 +6043,15 @@
             target.createdConfig = config.getGlobalConfiguration();
             target.overrideConfig = config.getOverrideConfiguration();
             target.pendingConfigChanges |= configChanges;
+            target.mActivityWindowInfo = activityWindowInfo;
         }
 
         return scheduleRelaunch ? target : null;
     }
 
     @Override
-    public void handleRelaunchActivity(ActivityClientRecord tmp,
-            PendingTransactionActions pendingActions) {
+    public void handleRelaunchActivity(@NonNull ActivityClientRecord tmp,
+            @NonNull PendingTransactionActions pendingActions) {
         // If we are getting ready to gc after going to the background, well
         // we are back active so skip it.
         unscheduleGcIdler();
@@ -6117,7 +6131,8 @@
         r.activity.mChangingConfigurations = true;
 
         handleRelaunchActivityInner(r, configChanges, tmp.pendingResults, tmp.pendingIntents,
-                pendingActions, tmp.startsNotResumed, tmp.overrideConfig, "handleRelaunchActivity");
+                pendingActions, tmp.startsNotResumed, tmp.overrideConfig, tmp.mActivityWindowInfo,
+                "handleRelaunchActivity");
     }
 
     void scheduleRelaunchActivity(IBinder token) {
@@ -6172,7 +6187,8 @@
                 r.overrideConfig);
         final ActivityRelaunchItem activityRelaunchItem = ActivityRelaunchItem.obtain(
                 r.token, null /* pendingResults */, null /* pendingIntents */,
-                0 /* configChanges */, mergedConfiguration, r.mPreserveWindow);
+                0 /* configChanges */, mergedConfiguration, r.mPreserveWindow,
+                r.getActivityWindowInfo());
         // Make sure to match the existing lifecycle state in the end of the transaction.
         final ActivityLifecycleItem lifecycleRequest =
                 TransactionExecutorHelper.getLifecycleRequestForCurrentState(r);
@@ -6183,10 +6199,12 @@
         executeTransaction(transaction);
     }
 
-    private void handleRelaunchActivityInner(ActivityClientRecord r, int configChanges,
-            List<ResultInfo> pendingResults, List<ReferrerIntent> pendingIntents,
-            PendingTransactionActions pendingActions, boolean startsNotResumed,
-            Configuration overrideConfig, String reason) {
+    private void handleRelaunchActivityInner(@NonNull ActivityClientRecord r, int configChanges,
+            @Nullable List<ResultInfo> pendingResults,
+            @Nullable List<ReferrerIntent> pendingIntents,
+            @NonNull PendingTransactionActions pendingActions, boolean startsNotResumed,
+            @NonNull Configuration overrideConfig, @NonNull ActivityWindowInfo activityWindowInfo,
+            @NonNull String reason) {
         // Preserve last used intent, it may be set from Activity#setIntent().
         final Intent customIntent = r.activity.mIntent;
         // Need to ensure state is saved.
@@ -6219,6 +6237,7 @@
         }
         r.startsNotResumed = startsNotResumed;
         r.overrideConfig = overrideConfig;
+        r.mActivityWindowInfo = activityWindowInfo;
 
         handleLaunchActivity(r, pendingActions, mLastReportedDeviceId, customIntent);
     }
@@ -6640,11 +6659,12 @@
     /**
      * Sets the supplied {@code overrideConfig} as pending for the {@code token}. Calling
      * this method prevents any calls to
-     * {@link #handleActivityConfigurationChanged(ActivityClientRecord, Configuration, int)} from
-     * processing any configurations older than {@code overrideConfig}.
+     * {@link #handleActivityConfigurationChanged(ActivityClientRecord, Configuration, int,
+     * ActivityWindowInfo)} from processing any configurations older than {@code overrideConfig}.
      */
     @Override
-    public void updatePendingActivityConfiguration(IBinder token, Configuration overrideConfig) {
+    public void updatePendingActivityConfiguration(@NonNull IBinder token,
+            @NonNull Configuration overrideConfig) {
         synchronized (mPendingOverrideConfigs) {
             final Configuration pendingOverrideConfig = mPendingOverrideConfigs.get(token);
             if (pendingOverrideConfig != null
@@ -6661,9 +6681,10 @@
     }
 
     @Override
-    public void handleActivityConfigurationChanged(ActivityClientRecord r,
-            @NonNull Configuration overrideConfig, int displayId) {
-        handleActivityConfigurationChanged(r, overrideConfig, displayId,
+    public void handleActivityConfigurationChanged(@NonNull ActivityClientRecord r,
+            @NonNull Configuration overrideConfig, int displayId,
+            @NonNull ActivityWindowInfo activityWindowInfo) {
+        handleActivityConfigurationChanged(r, overrideConfig, displayId, activityWindowInfo,
                 // This is the only place that uses alwaysReportChange=true. The entry point should
                 // be from ActivityConfigurationChangeItem or MoveToDisplayItem, so the server side
                 // has confirmed the activity should handle the configuration instead of relaunch.
@@ -6681,9 +6702,11 @@
      * @param overrideConfig Activity override config.
      * @param displayId Id of the display where activity was moved to, -1 if there was no move and
      *                  value didn't change.
+     * @param activityWindowInfo the window info of the given activity.
      */
-    void handleActivityConfigurationChanged(ActivityClientRecord r,
-            @NonNull Configuration overrideConfig, int displayId, boolean alwaysReportChange) {
+    void handleActivityConfigurationChanged(@NonNull ActivityClientRecord r,
+            @NonNull Configuration overrideConfig, int displayId,
+            @NonNull ActivityWindowInfo activityWindowInfo, boolean alwaysReportChange) {
         synchronized (mPendingOverrideConfigs) {
             final Configuration pendingOverrideConfig = mPendingOverrideConfigs.get(r.token);
             if (overrideConfig.isOtherSeqNewer(pendingOverrideConfig)) {
@@ -6716,6 +6739,8 @@
 
         // Perform updates.
         r.overrideConfig = overrideConfig;
+        r.mActivityWindowInfo = activityWindowInfo;
+        // TODO(b/287582673): notify on ActivityWindowInfo change
         final ViewRootImpl viewRoot = r.activity.mDecor != null
             ? r.activity.mDecor.getViewRootImpl() : null;
 
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 16c7753..2afc78c 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -74,6 +74,7 @@
 import android.os.UserManager;
 import android.permission.PermissionGroupUsage;
 import android.permission.PermissionUsageHelper;
+import android.permission.flags.Flags;
 import android.provider.DeviceConfig;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -99,7 +100,6 @@
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.Parcelling;
 import com.android.internal.util.Preconditions;
-import com.android.media.flags.Flags;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
@@ -2077,7 +2077,8 @@
      * @hide
      */
     @SystemApi
-    @FlaggedApi(Flags.FLAG_ENABLE_PRIVILEGED_ROUTING_FOR_MEDIA_ROUTING_CONTROL)
+    @FlaggedApi(com.android.media.flags.Flags
+            .FLAG_ENABLE_PRIVILEGED_ROUTING_FOR_MEDIA_ROUTING_CONTROL)
     public static final String OPSTR_MEDIA_ROUTING_CONTROL = "android:media_routing_control";
 
     /**
@@ -2243,7 +2244,7 @@
      *
      * @hide
      */
-    @FlaggedApi(android.permission.flags.Flags.FLAG_ENHANCED_CONFIRMATION_MODE_APIS_ENABLED)
+    @FlaggedApi(Flags.FLAG_ENHANCED_CONFIRMATION_MODE_APIS_ENABLED)
     @SystemApi
     public static final String OPSTR_ACCESS_RESTRICTED_SETTINGS =
             "android:access_restricted_settings";
@@ -3432,7 +3433,8 @@
             }
         }
 
-        public static final @android.annotation.NonNull Creator<PackageOps> CREATOR = new Creator<PackageOps>() {
+        public static final @android.annotation.NonNull Creator<PackageOps> CREATOR =
+                new Creator<PackageOps>() {
             @Override public PackageOps createFromParcel(Parcel source) {
                 return new PackageOps(source);
             }
@@ -7410,7 +7412,7 @@
          * @param userId User id of the app whose Op changed.
          * @param persistentDeviceId persistent device id whose Op changed.
          */
-        @FlaggedApi(android.permission.flags.Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
+        @FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
         default void onOpChanged(@NonNull String op, @NonNull String packageName, int userId,
                 @NonNull String persistentDeviceId) {
             if (Objects.equals(persistentDeviceId,
@@ -7480,7 +7482,7 @@
          * @param attributionFlags the attribution flags for this operation.
          * @param attributionChainId the unique id of the attribution chain this op is a part of.
          */
-        @FlaggedApi(android.permission.flags.Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
+        @FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
         default void onOpActiveChanged(@NonNull String op, int uid, @NonNull String packageName,
                 @Nullable String attributionTag, int virtualDeviceId, boolean active,
                 @AttributionFlags int attributionFlags, int attributionChainId) {
@@ -7534,7 +7536,7 @@
          * @param flags The flags of this op
          * @param result The result of the note.
          */
-        @FlaggedApi(android.permission.flags.Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
+        @FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
         default void onOpNoted(@NonNull String op, int uid, @NonNull String packageName,
                 @Nullable String attributionTag, int virtualDeviceId, @OpFlags int flags,
                 @Mode int result) {
@@ -7798,7 +7800,7 @@
         }
         final List<AppOpsManager.PackageOps> result;
         try {
-            result =  mService.getPackagesForOpsForDevice(opCodes, persistentDeviceId);
+            result = mService.getPackagesForOpsForDevice(opCodes, persistentDeviceId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -8270,14 +8272,24 @@
                 cb = new IAppOpsCallback.Stub() {
                     public void opChanged(int op, int uid, String packageName,
                             String persistentDeviceId) {
-                        if (callback instanceof OnOpChangedInternalListener) {
-                            ((OnOpChangedInternalListener)callback).onOpChanged(op, packageName,
-                                persistentDeviceId);
-                        }
-                        if (sAppOpInfos[op].name != null) {
-
-                            callback.onOpChanged(sAppOpInfos[op].name, packageName,
-                                    UserHandle.getUserId(uid), persistentDeviceId);
+                        if (Flags.deviceAwarePermissionApisEnabled()) {
+                            if (callback instanceof OnOpChangedInternalListener) {
+                                ((OnOpChangedInternalListener)callback).onOpChanged(op, packageName,
+                                        persistentDeviceId);
+                            }
+                            if (sAppOpInfos[op].name != null) {
+                                callback.onOpChanged(sAppOpInfos[op].name, packageName,
+                                        UserHandle.getUserId(uid), persistentDeviceId);
+                            }
+                        } else {
+                            if (callback instanceof OnOpChangedInternalListener) {
+                                ((OnOpChangedInternalListener) callback).onOpChanged(op,
+                                        packageName);
+                            }
+                            if (sAppOpInfos[op].name != null) {
+                                callback.onOpChanged(sAppOpInfos[op].name, packageName,
+                                        UserHandle.getUserId(uid));
+                            }
                         }
                     }
                 };
@@ -8361,14 +8373,26 @@
                         String attributionTag, int virtualDeviceId, boolean active,
                         @AttributionFlags int attributionFlags, int attributionChainId) {
                     executor.execute(() -> {
-                        if (callback instanceof OnOpActiveChangedInternalListener) {
-                            ((OnOpActiveChangedInternalListener) callback).onOpActiveChanged(op,
-                                    uid, packageName, virtualDeviceId, active);
-                        }
-                        if (sAppOpInfos[op].name != null) {
-                            callback.onOpActiveChanged(sAppOpInfos[op].name, uid, packageName,
-                                    attributionTag, virtualDeviceId, active, attributionFlags,
-                                    attributionChainId);
+                        if (Flags.deviceAwarePermissionApisEnabled()) {
+                            if (callback instanceof OnOpActiveChangedInternalListener) {
+                                ((OnOpActiveChangedInternalListener) callback).onOpActiveChanged(op,
+                                        uid, packageName, virtualDeviceId, active);
+                            }
+                            if (sAppOpInfos[op].name != null) {
+                                callback.onOpActiveChanged(sAppOpInfos[op].name, uid, packageName,
+                                        attributionTag, virtualDeviceId, active, attributionFlags,
+                                        attributionChainId);
+                            }
+                        } else {
+                            if (callback instanceof OnOpActiveChangedInternalListener) {
+                                ((OnOpActiveChangedInternalListener) callback).onOpActiveChanged(op,
+                                        uid, packageName, active);
+                            }
+                            if (sAppOpInfos[op].name != null) {
+                                callback.onOpActiveChanged(sAppOpInfos[op].name, uid, packageName,
+                                        attributionTag, active, attributionFlags,
+                                        attributionChainId);
+                            }
                         }
                     });
                 }
@@ -8613,9 +8637,13 @@
                     try {
                         executor.execute(() -> {
                             if (sAppOpInfos[op].name != null) {
-                                listener.onOpNoted(sAppOpInfos[op].name, uid, packageName,
-                                        attributionTag, virtualDeviceId,
-                                        flags, mode);
+                                if (Flags.deviceAwarePermissionApisEnabled()) {
+                                    listener.onOpNoted(sAppOpInfos[op].name, uid, packageName,
+                                            attributionTag, virtualDeviceId, flags, mode);
+                                } else {
+                                    listener.onOpNoted(sAppOpInfos[op].name, uid, packageName,
+                                            attributionTag, flags, mode);
+                                }
                             }
                         });
                     } finally {
@@ -8922,6 +8950,8 @@
      *
      * @hide
      */
+    @TestApi
+    @SuppressLint("UnflaggedApi")
     public int noteOpNoThrow(int op, @NonNull AttributionSource attributionSource,
             @Nullable String message) {
         return noteOpNoThrow(op, attributionSource.getUid(), attributionSource.getPackageName(),
diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java
index f6373d6..6ad0313 100644
--- a/core/java/android/app/AutomaticZenRule.java
+++ b/core/java/android/app/AutomaticZenRule.java
@@ -377,6 +377,9 @@
      * Sets the {@link ZenDeviceEffects} associated to this rule. Device effects specify changes to
      * the device behavior that should apply while the rule is active, but are not directly related
      * to suppressing notifications (for example: disabling always-on display).
+     *
+     * <p>When updating an existing rule via {@link NotificationManager#updateAutomaticZenRule},
+     * a {@code null} value here means the previous set of effects is retained.
      */
     @FlaggedApi(Flags.FLAG_MODES_API)
     public void setDeviceEffects(@Nullable ZenDeviceEffects deviceEffects) {
@@ -749,6 +752,9 @@
 
         /**
          * Sets the zen policy.
+         *
+         * <p>When updating an existing rule via {@link NotificationManager#updateAutomaticZenRule},
+         * a {@code null} value here means the previous policy is retained.
          */
         public @NonNull Builder setZenPolicy(@Nullable ZenPolicy policy) {
             mPolicy = policy;
@@ -759,6 +765,9 @@
          * Sets the {@link ZenDeviceEffects} associated to this rule. Device effects specify changes
          * to the device behavior that should apply while the rule is active, but are not directly
          * related to suppressing notifications (for example: disabling always-on display).
+         *
+         * <p>When updating an existing rule via {@link NotificationManager#updateAutomaticZenRule},
+         * a {@code null} value here means the previous set of effects is retained.
          */
         @NonNull
         public Builder setDeviceEffects(@Nullable ZenDeviceEffects deviceEffects) {
diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java
index b300674..b5b3669 100644
--- a/core/java/android/app/ClientTransactionHandler.java
+++ b/core/java/android/app/ClientTransactionHandler.java
@@ -30,6 +30,7 @@
 import android.os.IBinder;
 import android.util.MergedConfiguration;
 import android.view.SurfaceControl;
+import android.window.ActivityWindowInfo;
 import android.window.SplashScreenView.SplashScreenViewParcelable;
 import android.window.WindowContext;
 import android.window.WindowContextInfo;
@@ -166,11 +167,12 @@
 
     /** Set pending activity configuration in case it will be updated by other transaction item. */
     public abstract void updatePendingActivityConfiguration(@NonNull IBinder token,
-            Configuration overrideConfig);
+            @NonNull Configuration overrideConfig);
 
     /** Deliver activity (override) configuration change. */
     public abstract void handleActivityConfigurationChanged(@NonNull ActivityClientRecord r,
-            Configuration overrideConfig, int displayId);
+            @NonNull Configuration overrideConfig, int displayId,
+            @NonNull ActivityWindowInfo activityWindowInfo);
 
     /** Deliver {@link android.window.WindowContextInfo} change. */
     public abstract void handleWindowContextInfoChanged(@NonNull IBinder clientToken,
@@ -232,12 +234,15 @@
      * @param config New configuration applied to the activity.
      * @param preserveWindow Whether the activity should try to reuse the window it created,
      *                        including the decor view after the relaunch.
+     * @param activityWindowInfo Window information about the relaunched Activity.
      * @return An initialized instance of {@link ActivityThread.ActivityClientRecord} to use during
      *         relaunch, or {@code null} if relaunch cancelled.
      */
-    public abstract ActivityClientRecord prepareRelaunchActivity(IBinder token,
-            List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
-            int configChanges, MergedConfiguration config, boolean preserveWindow);
+    public abstract ActivityClientRecord prepareRelaunchActivity(@NonNull IBinder token,
+            @Nullable List<ResultInfo> pendingResults,
+            @Nullable List<ReferrerIntent> pendingNewIntents, int configChanges,
+            @NonNull MergedConfiguration config, boolean preserveWindow,
+            @NonNull ActivityWindowInfo activityWindowInfo);
 
     /**
      * Perform activity relaunch.
@@ -245,7 +250,7 @@
      * @param pendingActions Pending actions to be used on later stages of activity transaction.
      * */
     public abstract void handleRelaunchActivity(@NonNull ActivityClientRecord r,
-            PendingTransactionActions pendingActions);
+            @NonNull PendingTransactionActions pendingActions);
 
     /**
      * Report that relaunch request was handled.
diff --git a/core/java/android/app/ForegroundServiceTypePolicy.java b/core/java/android/app/ForegroundServiceTypePolicy.java
index 7e06735..d1e517b 100644
--- a/core/java/android/app/ForegroundServiceTypePolicy.java
+++ b/core/java/android/app/ForegroundServiceTypePolicy.java
@@ -62,7 +62,6 @@
 import android.hardware.usb.UsbAccessory;
 import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbManager;
-import android.os.Build;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
@@ -128,14 +127,10 @@
      * The FGS type enforcement:
      * deprecating the {@link android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_DATA_SYNC}.
      *
-     * <p>Starting a FGS with this type from apps with targetSdkVersion
-     * {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} or later will result in a warning
-     * in the log.
-     *
      * @hide
      */
     @ChangeId
-    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+    @Disabled
     @Overridable
     public static final long FGS_TYPE_DATA_SYNC_DEPRECATION_CHANGE_ID = 255039210L;
 
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 26f85f7..1129f9d 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -7543,6 +7543,7 @@
         /**
          * @hide
          */
+        @SuppressWarnings("HiddenAbstractMethod")
         public abstract boolean areNotificationsVisiblyDifferent(Style other);
 
         /**
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index e6e46dd..301fef8 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -1448,7 +1448,6 @@
          *
          * @hide
          */
-        @SystemApi
         public boolean isBackDisabled() {
             return mBack;
         }
@@ -1862,38 +1861,38 @@
         };
 
         @DataClass.Generated(
-                time = 1707345957771L,
+                time = 1708625947132L,
                 codegenVersion = "1.0.23",
                 sourceFile = "frameworks/base/core/java/android/app/StatusBarManager.java",
-                inputSignatures = "private  boolean mStatusBarExpansion\nprivate  "
-                        + "boolean mNavigateHome\nprivate  boolean mNotificationPeeking\nprivate  "
-                        + "boolean mRecents\nprivate  boolean mBack\nprivate  boolean "
-                        + "mSearch\nprivate  boolean mSystemIcons\nprivate  boolean mClock\nprivate"
-                        + "  boolean mNotificationIcons\nprivate  boolean mRotationSuggestion\n"
+                inputSignatures = "private  boolean mStatusBarExpansion\nprivate  boolean "
+                        + "mNavigateHome\nprivate  boolean mNotificationPeeking\nprivate  "
+                        + "boolean mRecents\nprivate  boolean mBack\nprivate  boolean mSearch\n"
+                        + "private  boolean mSystemIcons\nprivate  boolean mClock\nprivate  "
+                        + "boolean mNotificationIcons\nprivate  boolean mRotationSuggestion\n"
                         + "private  boolean mNotificationTicker\npublic "
                         + "@android.annotation.SystemApi boolean isStatusBarExpansionDisabled()\n"
                         + "public  void setStatusBarExpansionDisabled(boolean)\npublic "
-                        + "@android.annotation.SystemApi boolean isNavigateToHomeDisabled()\n"
-                        + "public  void setNavigationHomeDisabled(boolean)\npublic "
-                        + "@android.annotation.SystemApi boolean isNotificationPeekingDisabled()\n"
-                        + "public  void setNotificationPeekingDisabled(boolean)\npublic "
+                        + "@android.annotation.SystemApi boolean isNavigateToHomeDisabled()\npublic"
+                        + "  void setNavigationHomeDisabled(boolean)\npublic "
+                        + "@android.annotation.SystemApi boolean isNotificationPeekingDisabled()"
+                        + "\npublic  void setNotificationPeekingDisabled(boolean)\npublic "
                         + "@android.annotation.SystemApi boolean isRecentsDisabled()\npublic  "
-                        + "void setRecentsDisabled(boolean)\npublic @android.annotation.SystemApi "
-                        + "boolean isBackDisabled()\npublic  void setBackDisabled(boolean)\npublic "
+                        + "void setRecentsDisabled(boolean)\npublic  boolean isBackDisabled()"
+                        + "\npublic  void setBackDisabled(boolean)\npublic "
                         + "@android.annotation.SystemApi boolean isSearchDisabled()\npublic  "
                         + "void setSearchDisabled(boolean)\npublic  boolean "
-                        + "areSystemIconsDisabled()\npublic  void setSystemIconsDisabled(boolean)"
-                        + "\npublic  boolean isClockDisabled()\npublic  "
-                        + "void setClockDisabled(boolean)\npublic  "
-                        + "boolean areNotificationIconsDisabled()\npublic  "
-                        + "void setNotificationIconsDisabled(boolean)\npublic  boolean "
+                        + "areSystemIconsDisabled()\npublic  void setSystemIconsDisabled(boolean)\n"
+                        + "public  boolean isClockDisabled()\npublic  "
+                        + "void setClockDisabled(boolean)\npublic  boolean "
+                        + "areNotificationIconsDisabled()\npublic  void "
+                        + "setNotificationIconsDisabled(boolean)\npublic  boolean "
                         + "isNotificationTickerDisabled()\npublic  void "
                         + "setNotificationTickerDisabled(boolean)\npublic "
                         + "@android.annotation.TestApi boolean isRotationSuggestionDisabled()\n"
                         + "public  void setRotationSuggestionDisabled(boolean)\npublic "
-                        + "@android.annotation.SystemApi boolean areAllComponentsEnabled()\n"
-                        + "public  void setEnableAll()\npublic  boolean areAllComponentsDisabled()"
-                        + "\npublic  void setDisableAll()\npublic @android.annotation.NonNull "
+                        + "@android.annotation.SystemApi boolean areAllComponentsEnabled()\npublic"
+                        + "  void setEnableAll()\npublic  boolean areAllComponentsDisabled()\n"
+                        + "public  void setDisableAll()\npublic @android.annotation.NonNull "
                         + "@java.lang.Override java.lang.String toString()\npublic  "
                         + "android.util.Pair<java.lang.Integer,java.lang.Integer> toFlags()\n"
                         + "class DisableInfo extends java.lang.Object implements "
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 08c193f..d01626e 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -212,7 +212,7 @@
 import android.permission.PermissionManager;
 import android.print.IPrintManager;
 import android.print.PrintManager;
-import android.provider.ContactKeysManager;
+import android.provider.E2eeContactKeysManager;
 import android.safetycenter.SafetyCenterFrameworkInitializer;
 import android.scheduling.SchedulingFrameworkInitializer;
 import android.security.FileIntegrityManager;
@@ -1608,16 +1608,16 @@
                     }
                 });
 
-        registerService(Context.CONTACT_KEYS_SERVICE, ContactKeysManager.class,
-                new CachedServiceFetcher<ContactKeysManager>() {
+        registerService(Context.CONTACT_KEYS_SERVICE, E2eeContactKeysManager.class,
+                new CachedServiceFetcher<E2eeContactKeysManager>() {
                     @Override
-                    public ContactKeysManager createService(ContextImpl ctx)
+                    public E2eeContactKeysManager createService(ContextImpl ctx)
                             throws ServiceNotFoundException {
                         if (!android.provider.Flags.userKeys()) {
                             throw new ServiceNotFoundException(
                                     "ContactKeysManager is not supported");
                         }
-                        return new ContactKeysManager(ctx);
+                        return new E2eeContactKeysManager(ctx);
                     }});
 
         // DO NOT do a flag check like this unless the flag is read-only.
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 83fb393..02d6944 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -981,12 +981,12 @@
     /**
      * <strong> Important note: </strong>
      * <ul>
-     *     <li>Up to version S, this method requires the
+     *     <li>Up to Android 12, this method requires the
      *     {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission.</li>
-     *     <li>Starting in T, directly accessing the wallpaper is not possible anymore,
+     *     <li>Starting in Android 13, directly accessing the wallpaper is not possible anymore,
      *     instead the default system wallpaper is returned
-     *     (some versions of T may throw a {@code SecurityException}).</li>
-     *     <li>From version U, this method should not be used
+     *     (some versions of Android 13 may throw a {@code SecurityException}).</li>
+     *     <li>From Android 14, this method should not be used
      *     and will always throw a {@code SecurityException}.</li>
      *     <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE}
      *     can still access the real wallpaper on all versions. </li>
@@ -1265,12 +1265,12 @@
     /**
      * <strong> Important note: </strong>
      * <ul>
-     *     <li>Up to version S, this method requires the
+     *     <li>Up to Android 12, this method requires the
      *     {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission.</li>
-     *     <li>Starting in T, directly accessing the wallpaper is not possible anymore,
+     *     <li>Starting in Android 13, directly accessing the wallpaper is not possible anymore,
      *     instead the default system wallpaper is returned
-     *     (some versions of T may throw a {@code SecurityException}).</li>
-     *     <li>From version U, this method should not be used
+     *     (some versions of Android 13 may throw a {@code SecurityException}).</li>
+     *     <li>From Android 14, this method should not be used
      *     and will always throw a {@code SecurityException}.</li>
      *     <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE}
      *     can still access the real wallpaper on all versions. </li>
@@ -1318,12 +1318,12 @@
     /**
      * <strong> Important note: </strong>
      * <ul>
-     *     <li>Up to version S, this method requires the
+     *     <li>Up to Android 12, this method requires the
      *     {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission.</li>
-     *     <li>Starting in T, directly accessing the wallpaper is not possible anymore,
+     *     <li>Starting in Android 13, directly accessing the wallpaper is not possible anymore,
      *     instead the default wallpaper is returned
-     *     (some versions of T may throw a {@code SecurityException}).</li>
-     *     <li>From version U, this method should not be used
+     *     (some versions of Android 13 may throw a {@code SecurityException}).</li>
+     *     <li>From Android 14, this method should not be used
      *     and will always throw a {@code SecurityException}.</li>
      *     <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE}
      *     can still access the real wallpaper on all versions. </li>
@@ -1677,12 +1677,12 @@
     /**
      * <strong> Important note: </strong>
      * <ul>
-     *     <li>Up to version S, this method requires the
+     *     <li>Up to Android 12, this method requires the
      *     {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission.</li>
-     *     <li>Starting in T, directly accessing the wallpaper is not possible anymore,
+     *     <li>Starting in Android 13, directly accessing the wallpaper is not possible anymore,
      *     instead the default system wallpaper is returned
-     *     (some versions of T may throw a {@code SecurityException}).</li>
-     *     <li>From version U, this method should not be used
+     *     (some versions of Android 13 may throw a {@code SecurityException}).</li>
+     *     <li>From Android 14, this method should not be used
      *     and will always throw a {@code SecurityException}.</li>
      *     <li> Apps with {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE}
      *     can still access the real wallpaper on all versions. </li>
@@ -1904,14 +1904,14 @@
      * caller doesn't have the appropriate permissions, this returns {@code null}.
      *
      * <p>
-     * Before Android U, this method requires the
+     * For devices running Android 13 or earlier, this method requires the
      * {@link android.Manifest.permission#QUERY_ALL_PACKAGES} permission.
      * </p>
      *
      * <p>
-     * Starting from Android U, in order to use this, apps should declare a {@code <queries>} tag
-     * with the action {@code "android.service.wallpaper.WallpaperService"}. Otherwise,
-     * this method will return {@code null} if the caller doesn't otherwise have
+     * For devices running Android 14 or later, in order to use this, apps should declare a
+     * {@code <queries>} tag with the action {@code "android.service.wallpaper.WallpaperService"}.
+     * Otherwise, this method will return {@code null} if the caller doesn't otherwise have
      * <a href="{@docRoot}training/package-visibility">visibility</a> of the wallpaper package.
      * </p>
      */
diff --git a/core/java/android/app/admin/DevicePolicyCache.java b/core/java/android/app/admin/DevicePolicyCache.java
index 29f657e..16cb4ec 100644
--- a/core/java/android/app/admin/DevicePolicyCache.java
+++ b/core/java/android/app/admin/DevicePolicyCache.java
@@ -15,6 +15,9 @@
  */
 package android.app.admin;
 
+import static android.app.admin.DevicePolicyManager.CONTENT_PROTECTION_DISABLED;
+import static android.app.admin.DevicePolicyManager.ContentProtectionPolicy;
+
 import android.annotation.UserIdInt;
 
 import com.android.server.LocalServices;
@@ -59,6 +62,12 @@
     public abstract int getPermissionPolicy(@UserIdInt int userHandle);
 
     /**
+     * Caches {@link DevicePolicyManager#getContentProtectionPolicy(android.content.ComponentName)}
+     * of the given user.
+     */
+    public abstract @ContentProtectionPolicy int getContentProtectionPolicy(@UserIdInt int userId);
+
+    /**
      * True if there is an admin on the device who can grant sensor permissions.
      */
     public abstract boolean canAdminGrantSensorsPermissions();
@@ -92,6 +101,11 @@
         }
 
         @Override
+        public @ContentProtectionPolicy int getContentProtectionPolicy(@UserIdInt int userId) {
+            return CONTENT_PROTECTION_DISABLED;
+        }
+
+        @Override
         public boolean canAdminGrantSensorsPermissions() {
             return false;
         }
diff --git a/core/java/android/app/admin/PolicySizeVerifier.java b/core/java/android/app/admin/PolicySizeVerifier.java
index d5e8ea4..792ebc6 100644
--- a/core/java/android/app/admin/PolicySizeVerifier.java
+++ b/core/java/android/app/admin/PolicySizeVerifier.java
@@ -88,6 +88,10 @@
      * Throw if Parcelable contains any string that's too long to be serialized.
      */
     public static void enforceMaxParcelableFieldsLength(Parcelable parcelable) {
+        // TODO(b/326662716) rework to protect against infinite recursion.
+        if (true) {
+            return;
+        }
         Class<?> clazz = parcelable.getClass();
 
         Field[] fields = clazz.getDeclaredFields();
diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig
index cbd8e5b..10954ab 100644
--- a/core/java/android/app/admin/flags/flags.aconfig
+++ b/core/java/android/app/admin/flags/flags.aconfig
@@ -117,6 +117,9 @@
     namespace: "enterprise"
     description: "Exempt the default sms app of the context user for suspension when calling setPersonalAppsSuspended"
     bug: "309183330"
+    metadata {
+      purpose: PURPOSE_BUGFIX
+    }
 }
 
 flag {
diff --git a/core/java/android/app/ambient_context.aconfig b/core/java/android/app/ambient_context.aconfig
deleted file mode 100644
index 3f73da2..0000000
--- a/core/java/android/app/ambient_context.aconfig
+++ /dev/null
@@ -1,8 +0,0 @@
-package: "android.app"
-
-flag {
-  namespace: "biometrics_integration"
-  name: "ambient_heart_rate"
-  description: "Feature flag for adding heart rate api to ambient context."
-  bug: "318309481"
-}
diff --git a/core/java/android/app/ambientcontext/AmbientContextEvent.java b/core/java/android/app/ambientcontext/AmbientContextEvent.java
index 5ab7991..13d959c 100644
--- a/core/java/android/app/ambientcontext/AmbientContextEvent.java
+++ b/core/java/android/app/ambientcontext/AmbientContextEvent.java
@@ -16,9 +16,7 @@
 
 package android.app.ambientcontext;
 
-import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
-import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.Parcelable;
@@ -70,14 +68,6 @@
     public static final int EVENT_BACK_DOUBLE_TAP = 3;
 
     /**
-     * The integer indicating a heart rate measurement was done.
-     *
-     * @see #getRatePerMinute
-     */
-    @Event @FlaggedApi(android.app.Flags.FLAG_AMBIENT_HEART_RATE)
-    public static final int EVENT_HEART_RATE = 4;
-
-    /**
      * Integer indicating the start of wearable vendor defined events that can be detected.
      * These depend on the vendor implementation.
      */
@@ -89,19 +79,12 @@
      */
     public static final String KEY_VENDOR_WEARABLE_EVENT_NAME = "wearable_event_name";
 
-    /**
-     * Default value for {@link #getRatePerMinute}. Indicates that the rate of the event is unknown.
-     */
-    @FlaggedApi(android.app.Flags.FLAG_AMBIENT_HEART_RATE)
-    public static final int RATE_PER_MINUTE_UNKNOWN = -1;
-
     /** @hide */
     @IntDef(prefix = { "EVENT_" }, value = {
             EVENT_UNKNOWN,
             EVENT_COUGH,
             EVENT_SNORE,
             EVENT_BACK_DOUBLE_TAP,
-            EVENT_HEART_RATE,
             EVENT_VENDOR_WEARABLE_START,
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -187,16 +170,6 @@
         return new PersistableBundle();
     }
 
-    /**
-     * Rate per minute of the event during the start to end time.
-     *
-     * @return the rate per minute, or {@link #RATE_PER_MINUTE_UNKNOWN} if the rate is unknown.
-     */
-    private final @IntRange(from = -1) int mRatePerMinute;
-    private static int defaultRatePerMinute() {
-        return RATE_PER_MINUTE_UNKNOWN;
-    }
-
 
 
     // Code below generated by codegen v1.0.23.
@@ -206,8 +179,6 @@
     //
     // To regenerate run:
     // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/app/ambientcontext/AmbientContextEvent.java
-    // then manually add @FlaggedApi(android.app.Flags.FLAG_AMBIENT_HEART_RATE) back to flagged
-    // APIs.
     //
     // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
     //   Settings > Editor > Code Style > Formatter Control
@@ -220,7 +191,6 @@
         EVENT_COUGH,
         EVENT_SNORE,
         EVENT_BACK_DOUBLE_TAP,
-        EVENT_HEART_RATE,
         EVENT_VENDOR_WEARABLE_START
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -239,8 +209,6 @@
                     return "EVENT_SNORE";
             case EVENT_BACK_DOUBLE_TAP:
                     return "EVENT_BACK_DOUBLE_TAP";
-            case EVENT_HEART_RATE:
-                    return "EVENT_HEART_RATE";
             case EVENT_VENDOR_WEARABLE_START:
                     return "EVENT_VENDOR_WEARABLE_START";
             default: return Integer.toHexString(value);
@@ -287,8 +255,7 @@
             @NonNull Instant endTime,
             @LevelValue int confidenceLevel,
             @LevelValue int densityLevel,
-            @NonNull PersistableBundle vendorData,
-            @IntRange(from = -1) int ratePerMinute) {
+            @NonNull PersistableBundle vendorData) {
         this.mEventType = eventType;
         com.android.internal.util.AnnotationValidations.validate(
                 EventCode.class, null, mEventType);
@@ -307,10 +274,6 @@
         this.mVendorData = vendorData;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mVendorData);
-        this.mRatePerMinute = ratePerMinute;
-        com.android.internal.util.AnnotationValidations.validate(
-                IntRange.class, null, mRatePerMinute,
-                "from", -1);
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -367,17 +330,6 @@
         return mVendorData;
     }
 
-    /**
-     * Rate per minute of the event during the start to end time.
-     *
-     * @return the rate per minute, or {@link #RATE_PER_MINUTE_UNKNOWN} if the rate is unknown.
-     */
-    @DataClass.Generated.Member
-    @FlaggedApi(android.app.Flags.FLAG_AMBIENT_HEART_RATE)
-    public @IntRange(from = -1) int getRatePerMinute() {
-        return mRatePerMinute;
-    }
-
     @Override
     @DataClass.Generated.Member
     public String toString() {
@@ -390,8 +342,7 @@
                 "endTime = " + mEndTime + ", " +
                 "confidenceLevel = " + mConfidenceLevel + ", " +
                 "densityLevel = " + mDensityLevel + ", " +
-                "vendorData = " + mVendorData + ", " +
-                "ratePerMinute = " + mRatePerMinute +
+                "vendorData = " + mVendorData +
         " }";
     }
 
@@ -429,7 +380,6 @@
         dest.writeInt(mConfidenceLevel);
         dest.writeInt(mDensityLevel);
         dest.writeTypedObject(mVendorData, flags);
-        dest.writeInt(mRatePerMinute);
     }
 
     @Override
@@ -449,7 +399,6 @@
         int confidenceLevel = in.readInt();
         int densityLevel = in.readInt();
         PersistableBundle vendorData = (PersistableBundle) in.readTypedObject(PersistableBundle.CREATOR);
-        int ratePerMinute = in.readInt();
 
         this.mEventType = eventType;
         com.android.internal.util.AnnotationValidations.validate(
@@ -469,10 +418,6 @@
         this.mVendorData = vendorData;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mVendorData);
-        this.mRatePerMinute = ratePerMinute;
-        com.android.internal.util.AnnotationValidations.validate(
-                IntRange.class, null, mRatePerMinute,
-                "from", -1);
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -504,7 +449,6 @@
         private @LevelValue int mConfidenceLevel;
         private @LevelValue int mDensityLevel;
         private @NonNull PersistableBundle mVendorData;
-        private @IntRange(from = -1) int mRatePerMinute;
 
         private long mBuilderFieldsSet = 0L;
 
@@ -581,22 +525,10 @@
             return this;
         }
 
-        /**
-         * Rate per minute of the event during the start to end time.
-         */
-        @DataClass.Generated.Member
-        @FlaggedApi(android.app.Flags.FLAG_AMBIENT_HEART_RATE)
-        public @NonNull Builder setRatePerMinute(@IntRange(from = -1) int value) {
-            checkNotUsed();
-            mBuilderFieldsSet |= 0x40;
-            mRatePerMinute = value;
-            return this;
-        }
-
         /** Builds the instance. This builder should not be touched after calling this! */
         public @NonNull AmbientContextEvent build() {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x80; // Mark builder used
+            mBuilderFieldsSet |= 0x40; // Mark builder used
 
             if ((mBuilderFieldsSet & 0x1) == 0) {
                 mEventType = defaultEventType();
@@ -616,22 +548,18 @@
             if ((mBuilderFieldsSet & 0x20) == 0) {
                 mVendorData = defaultVendorData();
             }
-            if ((mBuilderFieldsSet & 0x40) == 0) {
-                mRatePerMinute = defaultRatePerMinute();
-            }
             AmbientContextEvent o = new AmbientContextEvent(
                     mEventType,
                     mStartTime,
                     mEndTime,
                     mConfidenceLevel,
                     mDensityLevel,
-                    mVendorData,
-                    mRatePerMinute);
+                    mVendorData);
             return o;
         }
 
         private void checkNotUsed() {
-            if ((mBuilderFieldsSet & 0x80) != 0) {
+            if ((mBuilderFieldsSet & 0x40) != 0) {
                 throw new IllegalStateException(
                         "This Builder should not be reused. Use a new Builder instance instead");
             }
@@ -639,10 +567,10 @@
     }
 
     @DataClass.Generated(
-            time = 1705575046107L,
+            time = 1709014715064L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/app/ambientcontext/AmbientContextEvent.java",
-            inputSignatures = "public static final  int EVENT_UNKNOWN\npublic static final  int EVENT_COUGH\npublic static final  int EVENT_SNORE\npublic static final  int EVENT_BACK_DOUBLE_TAP\npublic static final @android.app.ambientcontext.AmbientContextEvent.Event @android.annotation.FlaggedApi int EVENT_HEART_RATE\npublic static final  int EVENT_VENDOR_WEARABLE_START\npublic static final  java.lang.String KEY_VENDOR_WEARABLE_EVENT_NAME\npublic static final @android.annotation.FlaggedApi int RATE_PER_MINUTE_UNKNOWN\npublic static final  int LEVEL_UNKNOWN\npublic static final  int LEVEL_LOW\npublic static final  int LEVEL_MEDIUM_LOW\npublic static final  int LEVEL_MEDIUM\npublic static final  int LEVEL_MEDIUM_HIGH\npublic static final  int LEVEL_HIGH\nprivate final @android.app.ambientcontext.AmbientContextEvent.EventCode int mEventType\nprivate final @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInstant.class) @android.annotation.NonNull java.time.Instant mStartTime\nprivate final @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInstant.class) @android.annotation.NonNull java.time.Instant mEndTime\nprivate final @android.app.ambientcontext.AmbientContextEvent.LevelValue int mConfidenceLevel\nprivate final @android.app.ambientcontext.AmbientContextEvent.LevelValue int mDensityLevel\nprivate final @android.annotation.NonNull android.os.PersistableBundle mVendorData\nprivate final @android.annotation.IntRange int mRatePerMinute\nprivate static  int defaultEventType()\nprivate static @android.annotation.NonNull java.time.Instant defaultStartTime()\nprivate static @android.annotation.NonNull java.time.Instant defaultEndTime()\nprivate static  int defaultConfidenceLevel()\nprivate static  int defaultDensityLevel()\nprivate static  android.os.PersistableBundle defaultVendorData()\nprivate static  int defaultRatePerMinute()\nclass AmbientContextEvent extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=false, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
+            inputSignatures = "public static final  int EVENT_UNKNOWN\npublic static final  int EVENT_COUGH\npublic static final  int EVENT_SNORE\npublic static final  int EVENT_BACK_DOUBLE_TAP\npublic static final  int EVENT_VENDOR_WEARABLE_START\npublic static final  java.lang.String KEY_VENDOR_WEARABLE_EVENT_NAME\npublic static final  int LEVEL_UNKNOWN\npublic static final  int LEVEL_LOW\npublic static final  int LEVEL_MEDIUM_LOW\npublic static final  int LEVEL_MEDIUM\npublic static final  int LEVEL_MEDIUM_HIGH\npublic static final  int LEVEL_HIGH\nprivate final @android.app.ambientcontext.AmbientContextEvent.EventCode int mEventType\nprivate final @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInstant.class) @android.annotation.NonNull java.time.Instant mStartTime\nprivate final @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInstant.class) @android.annotation.NonNull java.time.Instant mEndTime\nprivate final @android.app.ambientcontext.AmbientContextEvent.LevelValue int mConfidenceLevel\nprivate final @android.app.ambientcontext.AmbientContextEvent.LevelValue int mDensityLevel\nprivate final @android.annotation.NonNull android.os.PersistableBundle mVendorData\nprivate static  int defaultEventType()\nprivate static @android.annotation.NonNull java.time.Instant defaultStartTime()\nprivate static @android.annotation.NonNull java.time.Instant defaultEndTime()\nprivate static  int defaultConfidenceLevel()\nprivate static  int defaultDensityLevel()\nprivate static  android.os.PersistableBundle defaultVendorData()\nclass AmbientContextEvent extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genBuilder=true, genConstructor=false, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
index bc8fac5..48ea846 100644
--- a/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
+++ b/core/java/android/app/servertransaction/ActivityConfigurationChangeItem.java
@@ -29,6 +29,7 @@
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Trace;
+import android.window.ActivityWindowInfo;
 
 import java.util.Objects;
 
@@ -49,11 +50,13 @@
     }
 
     @Override
-    public void execute(@NonNull ClientTransactionHandler client, @Nullable ActivityClientRecord r,
+    public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r,
             @NonNull PendingTransactionActions pendingActions) {
         // TODO(lifecycler): detect if PIP or multi-window mode changed and report it here.
         Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityConfigChanged");
-        client.handleActivityConfigurationChanged(r, mConfiguration, INVALID_DISPLAY);
+        client.handleActivityConfigurationChanged(r, mConfiguration, INVALID_DISPLAY,
+                // TODO(b/287582673): add ActivityWindowInfo
+                new ActivityWindowInfo());
         Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
     }
 
diff --git a/core/java/android/app/servertransaction/ActivityRelaunchItem.java b/core/java/android/app/servertransaction/ActivityRelaunchItem.java
index cbb0ae7..6da871a 100644
--- a/core/java/android/app/servertransaction/ActivityRelaunchItem.java
+++ b/core/java/android/app/servertransaction/ActivityRelaunchItem.java
@@ -30,6 +30,7 @@
 import android.os.Trace;
 import android.util.MergedConfiguration;
 import android.util.Slog;
+import android.window.ActivityWindowInfo;
 
 import com.android.internal.content.ReferrerIntent;
 
@@ -50,6 +51,7 @@
     private int mConfigChanges;
     private MergedConfiguration mConfig;
     private boolean mPreserveWindow;
+    private ActivityWindowInfo mActivityWindowInfo;
 
     /**
      * A record that was properly configured for relaunch. Execution will be cancelled if not
@@ -64,7 +66,7 @@
             CompatibilityInfo.applyOverrideScaleIfNeeded(mConfig);
         }
         mActivityClientRecord = client.prepareRelaunchActivity(getActivityToken(), mPendingResults,
-                mPendingNewIntents, mConfigChanges, mConfig, mPreserveWindow);
+                mPendingNewIntents, mConfigChanges, mConfig, mPreserveWindow, mActivityWindowInfo);
     }
 
     @Override
@@ -101,7 +103,8 @@
     public static ActivityRelaunchItem obtain(@NonNull IBinder activityToken,
             @Nullable List<ResultInfo> pendingResults,
             @Nullable List<ReferrerIntent> pendingNewIntents, int configChanges,
-            @NonNull MergedConfiguration config, boolean preserveWindow) {
+            @NonNull MergedConfiguration config, boolean preserveWindow,
+            @NonNull ActivityWindowInfo activityWindowInfo) {
         ActivityRelaunchItem instance = ObjectPool.obtain(ActivityRelaunchItem.class);
         if (instance == null) {
             instance = new ActivityRelaunchItem();
@@ -113,6 +116,7 @@
         instance.mConfigChanges = configChanges;
         instance.mConfig = new MergedConfiguration(config);
         instance.mPreserveWindow = preserveWindow;
+        instance.mActivityWindowInfo = new ActivityWindowInfo(activityWindowInfo);
 
         return instance;
     }
@@ -126,6 +130,7 @@
         mConfig = null;
         mPreserveWindow = false;
         mActivityClientRecord = null;
+        mActivityWindowInfo = null;
         ObjectPool.recycle(this);
     }
 
@@ -141,6 +146,7 @@
         dest.writeInt(mConfigChanges);
         dest.writeTypedObject(mConfig, flags);
         dest.writeBoolean(mPreserveWindow);
+        dest.writeTypedObject(mActivityWindowInfo, flags);
     }
 
     /** Read from Parcel. */
@@ -151,6 +157,7 @@
         mConfigChanges = in.readInt();
         mConfig = in.readTypedObject(MergedConfiguration.CREATOR);
         mPreserveWindow = in.readBoolean();
+        mActivityWindowInfo = in.readTypedObject(ActivityWindowInfo.CREATOR);
     }
 
     public static final @NonNull Creator<ActivityRelaunchItem> CREATOR =
@@ -176,7 +183,8 @@
         return Objects.equals(mPendingResults, other.mPendingResults)
                 && Objects.equals(mPendingNewIntents, other.mPendingNewIntents)
                 && mConfigChanges == other.mConfigChanges && Objects.equals(mConfig, other.mConfig)
-                && mPreserveWindow == other.mPreserveWindow;
+                && mPreserveWindow == other.mPreserveWindow
+                && Objects.equals(mActivityWindowInfo, other.mActivityWindowInfo);
     }
 
     @Override
@@ -188,6 +196,7 @@
         result = 31 * result + mConfigChanges;
         result = 31 * result + Objects.hashCode(mConfig);
         result = 31 * result + (mPreserveWindow ? 1 : 0);
+        result = 31 * result + Objects.hashCode(mActivityWindowInfo);
         return result;
     }
 
@@ -198,6 +207,7 @@
                 + ",pendingNewIntents=" + mPendingNewIntents
                 + ",configChanges="  + mConfigChanges
                 + ",config=" + mConfig
-                + ",preserveWindow" + mPreserveWindow + "}";
+                + ",preserveWindow=" + mPreserveWindow
+                + ",activityWindowInfo=" + mActivityWindowInfo + "}";
     }
 }
diff --git a/core/java/android/app/servertransaction/LaunchActivityItem.java b/core/java/android/app/servertransaction/LaunchActivityItem.java
index 95f5ad0..f02cb21 100644
--- a/core/java/android/app/servertransaction/LaunchActivityItem.java
+++ b/core/java/android/app/servertransaction/LaunchActivityItem.java
@@ -42,6 +42,7 @@
 import android.os.Parcel;
 import android.os.PersistableBundle;
 import android.os.Trace;
+import android.window.ActivityWindowInfo;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IVoiceInteractor;
@@ -81,6 +82,8 @@
     private boolean mLaunchedFromBubble;
     private IBinder mTaskFragmentToken;
     private IBinder mInitialCallerInfoAccessToken;
+    private ActivityWindowInfo mActivityWindowInfo;
+
     /**
      * It is only non-null if the process is the first time to launch activity. It is only an
      * optimization for quick look up of the interface so the field is ignored for comparison.
@@ -107,7 +110,7 @@
                 mOverrideConfig, mReferrer, mVoiceInteractor, mState, mPersistentState,
                 mPendingResults, mPendingNewIntents, mSceneTransitionInfo, mIsForward,
                 mProfilerInfo, client, mAssistToken, mShareableActivityToken, mLaunchedFromBubble,
-                mTaskFragmentToken, mInitialCallerInfoAccessToken);
+                mTaskFragmentToken, mInitialCallerInfoAccessToken, mActivityWindowInfo);
         client.handleLaunchActivity(r, pendingActions, mDeviceId, null /* customIntent */);
         Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
     }
@@ -141,7 +144,8 @@
             boolean isForward, @Nullable ProfilerInfo profilerInfo, @NonNull IBinder assistToken,
             @Nullable IActivityClientController activityClientController,
             @NonNull IBinder shareableActivityToken, boolean launchedFromBubble,
-            @Nullable IBinder taskFragmentToken, @NonNull IBinder initialCallerInfoAccessToken) {
+            @Nullable IBinder taskFragmentToken, @NonNull IBinder initialCallerInfoAccessToken,
+            @NonNull ActivityWindowInfo activityWindowInfo) {
         LaunchActivityItem instance = ObjectPool.obtain(LaunchActivityItem.class);
         if (instance == null) {
             instance = new LaunchActivityItem();
@@ -156,7 +160,8 @@
                 sceneTransitionInfo, isForward,
                 profilerInfo != null ? new ProfilerInfo(profilerInfo) : null,
                 assistToken, activityClientController, shareableActivityToken,
-                launchedFromBubble, taskFragmentToken, initialCallerInfoAccessToken);
+                launchedFromBubble, taskFragmentToken, initialCallerInfoAccessToken,
+                new ActivityWindowInfo(activityWindowInfo));
 
         return instance;
     }
@@ -171,7 +176,7 @@
     @Override
     public void recycle() {
         setValues(this, null, null, 0, null, null, null, 0, null, null, 0, null, null, null, null,
-                null, false, null, null, null, null, false, null, null);
+                null, false, null, null, null, null, false, null, null, null);
         ObjectPool.recycle(this);
     }
 
@@ -203,6 +208,7 @@
         dest.writeBoolean(mLaunchedFromBubble);
         dest.writeStrongBinder(mTaskFragmentToken);
         dest.writeStrongBinder(mInitialCallerInfoAccessToken);
+        dest.writeTypedObject(mActivityWindowInfo, flags);
     }
 
     /** Read from Parcel. */
@@ -223,7 +229,8 @@
                 in.readStrongBinder(),
                 in.readBoolean(),
                 in.readStrongBinder(),
-                in.readStrongBinder());
+                in.readStrongBinder(),
+                in.readTypedObject(ActivityWindowInfo.CREATOR));
     }
 
     public static final @NonNull Creator<LaunchActivityItem> CREATOR = new Creator<>() {
@@ -264,7 +271,8 @@
                 && Objects.equals(mShareableActivityToken, other.mShareableActivityToken)
                 && Objects.equals(mTaskFragmentToken, other.mTaskFragmentToken)
                 && Objects.equals(mInitialCallerInfoAccessToken,
-                        other.mInitialCallerInfoAccessToken);
+                        other.mInitialCallerInfoAccessToken)
+                && Objects.equals(mActivityWindowInfo, other.mActivityWindowInfo);
     }
 
     @Override
@@ -289,6 +297,7 @@
         result = 31 * result + Objects.hashCode(mShareableActivityToken);
         result = 31 * result + Objects.hashCode(mTaskFragmentToken);
         result = 31 * result + Objects.hashCode(mInitialCallerInfoAccessToken);
+        result = 31 * result + Objects.hashCode(mActivityWindowInfo);
         return result;
     }
 
@@ -335,7 +344,9 @@
                 + ",sceneTransitionInfo=" + mSceneTransitionInfo
                 + ",profilerInfo=" + mProfilerInfo
                 + ",assistToken=" + mAssistToken
-                + ",shareableActivityToken=" + mShareableActivityToken + "}";
+                + ",shareableActivityToken=" + mShareableActivityToken
+                + ",activityWindowInfo=" + mActivityWindowInfo
+                + "}";
     }
 
     // Using the same method to set and clear values to make sure we don't forget anything
@@ -351,7 +362,8 @@
             @Nullable ProfilerInfo profilerInfo, @Nullable IBinder assistToken,
             @Nullable IActivityClientController activityClientController,
             @Nullable IBinder shareableActivityToken, boolean launchedFromBubble,
-            @Nullable IBinder taskFragmentToken, @Nullable IBinder initialCallerInfoAccessToken) {
+            @Nullable IBinder taskFragmentToken, @Nullable IBinder initialCallerInfoAccessToken,
+            @Nullable ActivityWindowInfo activityWindowInfo) {
         instance.mActivityToken = activityToken;
         instance.mIntent = intent;
         instance.mIdent = ident;
@@ -375,5 +387,6 @@
         instance.mLaunchedFromBubble = launchedFromBubble;
         instance.mTaskFragmentToken = taskFragmentToken;
         instance.mInitialCallerInfoAccessToken = initialCallerInfoAccessToken;
+        instance.mActivityWindowInfo = activityWindowInfo;
     }
 }
diff --git a/core/java/android/app/servertransaction/MoveToDisplayItem.java b/core/java/android/app/servertransaction/MoveToDisplayItem.java
index 1353d16..0702c45 100644
--- a/core/java/android/app/servertransaction/MoveToDisplayItem.java
+++ b/core/java/android/app/servertransaction/MoveToDisplayItem.java
@@ -28,6 +28,7 @@
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Trace;
+import android.window.ActivityWindowInfo;
 
 import java.util.Objects;
 
@@ -39,6 +40,7 @@
 
     private int mTargetDisplayId;
     private Configuration mConfiguration;
+    private ActivityWindowInfo mActivityWindowInfo;
 
     @Override
     public void preExecute(@NonNull ClientTransactionHandler client) {
@@ -52,7 +54,8 @@
     public void execute(@NonNull ClientTransactionHandler client, @NonNull ActivityClientRecord r,
             @NonNull PendingTransactionActions pendingActions) {
         Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityMovedToDisplay");
-        client.handleActivityConfigurationChanged(r, mConfiguration, mTargetDisplayId);
+        client.handleActivityConfigurationChanged(r, mConfiguration, mTargetDisplayId,
+                mActivityWindowInfo);
         Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
     }
 
@@ -69,7 +72,7 @@
     /** Obtain an instance initialized with provided params. */
     @NonNull
     public static MoveToDisplayItem obtain(@NonNull IBinder activityToken, int targetDisplayId,
-            @NonNull Configuration configuration) {
+            @NonNull Configuration configuration, @NonNull ActivityWindowInfo activityWindowInfo) {
         MoveToDisplayItem instance = ObjectPool.obtain(MoveToDisplayItem.class);
         if (instance == null) {
             instance = new MoveToDisplayItem();
@@ -77,6 +80,7 @@
         instance.setActivityToken(activityToken);
         instance.mTargetDisplayId = targetDisplayId;
         instance.mConfiguration = new Configuration(configuration);
+        instance.mActivityWindowInfo = new ActivityWindowInfo(activityWindowInfo);
 
         return instance;
     }
@@ -86,6 +90,7 @@
         super.recycle();
         mTargetDisplayId = 0;
         mConfiguration = null;
+        mActivityWindowInfo = null;
         ObjectPool.recycle(this);
     }
 
@@ -97,6 +102,7 @@
         super.writeToParcel(dest, flags);
         dest.writeInt(mTargetDisplayId);
         dest.writeTypedObject(mConfiguration, flags);
+        dest.writeTypedObject(mActivityWindowInfo, flags);
     }
 
     /** Read from Parcel. */
@@ -104,6 +110,7 @@
         super(in);
         mTargetDisplayId = in.readInt();
         mConfiguration = in.readTypedObject(Configuration.CREATOR);
+        mActivityWindowInfo = in.readTypedObject(ActivityWindowInfo.CREATOR);
     }
 
     public static final @NonNull Creator<MoveToDisplayItem> CREATOR = new Creator<>() {
@@ -126,7 +133,8 @@
         }
         final MoveToDisplayItem other = (MoveToDisplayItem) o;
         return mTargetDisplayId == other.mTargetDisplayId
-                && Objects.equals(mConfiguration, other.mConfiguration);
+                && Objects.equals(mConfiguration, other.mConfiguration)
+                && Objects.equals(mActivityWindowInfo, other.mActivityWindowInfo);
     }
 
     @Override
@@ -135,6 +143,7 @@
         result = 31 * result + super.hashCode();
         result = 31 * result + mTargetDisplayId;
         result = 31 * result + mConfiguration.hashCode();
+        result = 31 * result + Objects.hashCode(mActivityWindowInfo);
         return result;
     }
 
@@ -142,6 +151,7 @@
     public String toString() {
         return "MoveToDisplayItem{" + super.toString()
                 + ",targetDisplayId=" + mTargetDisplayId
-                + ",configuration=" + mConfiguration + "}";
+                + ",configuration=" + mConfiguration
+                + ",activityWindowInfo=" + mActivityWindowInfo + "}";
     }
 }
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index 728c350..b421339 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -169,6 +169,8 @@
  */
 @android.ravenwood.annotation.RavenwoodKeepWholeClass
 public class ClipData implements Parcelable {
+    private static final String TAG = "ClipData";
+
     static final String[] MIMETYPES_TEXT_PLAIN = new String[] {
         ClipDescription.MIMETYPE_TEXT_PLAIN };
     static final String[] MIMETYPES_TEXT_HTML = new String[] {
@@ -476,7 +478,6 @@
          * @return Returns the item's textual representation.
          */
 //BEGIN_INCLUDE(coerceToText)
-        @android.ravenwood.annotation.RavenwoodThrow
         public CharSequence coerceToText(Context context) {
             // If this Item has an explicit textual value, simply return that.
             CharSequence text = getText();
@@ -484,13 +485,20 @@
                 return text;
             }
 
+            // Gracefully handle cases where resolver isn't available
+            ContentResolver resolver = null;
+            try {
+                resolver = context.getContentResolver();
+            } catch (Exception e) {
+                Log.w(TAG, "Failed to obtain ContentResolver: " + e);
+            }
+
             // If this Item has a URI value, try using that.
             Uri uri = getUri();
-            if (uri != null) {
+            if (uri != null && resolver != null) {
                 // First see if the URI can be opened as a plain text stream
                 // (of any sub-type).  If so, this is the best textual
                 // representation for it.
-                final ContentResolver resolver = context.getContentResolver();
                 AssetFileDescriptor descr = null;
                 FileInputStream stream = null;
                 InputStreamReader reader = null;
@@ -499,7 +507,7 @@
                         // Ask for a stream of the desired type.
                         descr = resolver.openTypedAssetFileDescriptor(uri, "text/*", null);
                     } catch (SecurityException e) {
-                        Log.w("ClipData", "Failure opening stream", e);
+                        Log.w(TAG, "Failure opening stream", e);
                     } catch (FileNotFoundException|RuntimeException e) {
                         // Unable to open content URI as text...  not really an
                         // error, just something to ignore.
@@ -519,7 +527,7 @@
                             return builder.toString();
                         } catch (IOException e) {
                             // Something bad has happened.
-                            Log.w("ClipData", "Failure loading text", e);
+                            Log.w(TAG, "Failure loading text", e);
                             return e.toString();
                         }
                     }
@@ -528,7 +536,8 @@
                     IoUtils.closeQuietly(stream);
                     IoUtils.closeQuietly(reader);
                 }
-
+            }
+            if (uri != null) {
                 // If we couldn't open the URI as a stream, use the URI itself as a textual
                 // representation (but not for "content", "android.resource" or "file" schemes).
                 final String scheme = uri.getScheme();
@@ -704,7 +713,7 @@
                         }
 
                     } catch (SecurityException e) {
-                        Log.w("ClipData", "Failure opening stream", e);
+                        Log.w(TAG, "Failure opening stream", e);
 
                     } catch (FileNotFoundException e) {
                         // Unable to open content URI as text...  not really an
@@ -712,7 +721,7 @@
 
                     } catch (IOException e) {
                         // Something bad has happened.
-                        Log.w("ClipData", "Failure loading text", e);
+                        Log.w(TAG, "Failure loading text", e);
                         return Html.escapeHtml(e.toString());
 
                     } finally {
@@ -1123,7 +1132,7 @@
      *
      * @hide
      */
-    @android.ravenwood.annotation.RavenwoodThrow
+    @android.ravenwood.annotation.RavenwoodKeep
     public void prepareToLeaveProcess(boolean leavingPackage) {
         // Assume that callers are going to be granting permissions
         prepareToLeaveProcess(leavingPackage, Intent.FLAG_GRANT_READ_URI_PERMISSION);
@@ -1134,7 +1143,7 @@
      *
      * @hide
      */
-    @android.ravenwood.annotation.RavenwoodThrow
+    @android.ravenwood.annotation.RavenwoodReplace
     public void prepareToLeaveProcess(boolean leavingPackage, int intentFlags) {
         final int size = mItems.size();
         for (int i = 0; i < size; i++) {
@@ -1154,6 +1163,11 @@
         }
     }
 
+    /** @hide */
+    public void prepareToLeaveProcess$ravenwood(boolean leavingPackage, int intentFlags) {
+        // No process boundaries on Ravenwood; ignored
+    }
+
     /** {@hide} */
     @android.ravenwood.annotation.RavenwoodThrow
     public void prepareToEnterProcess(AttributionSource source) {
diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java
index 107f107..2fabcba 100644
--- a/core/java/android/content/ClipboardManager.java
+++ b/core/java/android/content/ClipboardManager.java
@@ -50,6 +50,7 @@
  * </div>
  */
 @SystemService(Context.CLIPBOARD_SERVICE)
+@android.ravenwood.annotation.RavenwoodKeepWholeClass
 public class ClipboardManager extends android.text.ClipboardManager {
 
     /**
@@ -143,6 +144,7 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.MANAGE_CLIPBOARD_ACCESS_NOTIFICATION)
+    @android.ravenwood.annotation.RavenwoodThrow
     public boolean areClipboardAccessNotificationsEnabled() {
         try {
             return mService.areClipboardAccessNotificationsEnabledForUser(mContext.getUserId());
@@ -159,6 +161,7 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.MANAGE_CLIPBOARD_ACCESS_NOTIFICATION)
+    @android.ravenwood.annotation.RavenwoodThrow
     public void setClipboardAccessNotificationsEnabled(boolean enable) {
         try {
             mService.setClipboardAccessNotificationsEnabledForUser(enable, mContext.getUserId());
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 7505372..70d2c7a 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -83,6 +83,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.storage.StorageManager;
+import android.provider.E2eeContactKeysManager;
 import android.provider.MediaStore;
 import android.telephony.TelephonyRegistryManager;
 import android.util.AttributeSet;
@@ -4815,9 +4816,7 @@
      * @see android.net.thread.ThreadNetworkManager
      * @hide
      */
-    // TODO (b/325886480): update the flag to
-    // "com.android.net.thread.platform.flags.Flags.FLAG_THREAD_ENABLED_PLATFORM"
-    @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform")
+    @FlaggedApi(com.android.net.thread.platform.flags.Flags.FLAG_THREAD_ENABLED_PLATFORM)
     @SystemApi
     public static final String THREAD_NETWORK_SERVICE = "thread_network";
 
@@ -5068,7 +5067,6 @@
      * {@link android.hardware.fingerprint.FingerprintManager} for handling management
      * of fingerprints.
      *
-     * @removed See {@link android.hardware.biometrics.BiometricPrompt}
      * @see #getSystemService(String)
      * @see android.hardware.fingerprint.FingerprintManager
      */
@@ -6567,10 +6565,10 @@
 
     /**
      * Use with {@link #getSystemService(String)} to retrieve a
-     * {@link android.provider.ContactKeysManager} to managing contact keys.
+     * {@link E2eeContactKeysManager} to managing contact keys.
      *
      * @see #getSystemService(String)
-     * @see android.provider.ContactKeysManager
+     * @see E2eeContactKeysManager
      */
     @FlaggedApi(android.provider.Flags.FLAG_USER_KEYS)
     public static final String CONTACT_KEYS_SERVICE = "contact_keys";
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 7a015cd..240cff3 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3974,9 +3974,7 @@
      * The device is capable of communicating with other devices via
      * <a href="https://www.threadgroup.org">Thread</a> networking protocol.
      */
-    // TODO (b/325886480): update the flag to
-    // "com.android.net.thread.platform.flags.Flags.FLAG_THREAD_ENABLED_PLATFORM"
-    @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform")
+    @FlaggedApi(com.android.net.thread.platform.flags.Flags.FLAG_THREAD_ENABLED_PLATFORM)
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_THREAD_NETWORK = "android.hardware.thread_network";
 
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index 9c6aab4..5b0cee7 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -163,25 +163,12 @@
      * Because of this, developers must make sure to stop the foreground service even if
      * {@link android.app.Service#onTimeout(int, int)} is not called on such versions.
      *
-     * <p>Apps targeting API level {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} and
-     * later should <b>NOT</b> use this type: calling
-     * {@link android.app.Service#startForeground(int, android.app.Notification, int)} with
-     * this type on devices running {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} is
-     * still allowed, but it may throw an {@link android.app.InvalidForegroundServiceTypeException}
-     * in future platform releases.
-     *
-     * <p class="note">
-     * Use the {@link android.app.job.JobInfo.Builder#setUserInitiated(boolean)} API for
-     * user-initiated, network data transfers.
-     *
-     * @deprecated Use {@link android.app.job.JobInfo.Builder} APIs or alternate FGS types
-     * (like {@link #FOREGROUND_SERVICE_TYPE_MEDIA_PROCESSING}) applicable to your use-case.
+     * @see android.app.Service#onTimeout(int, int)
      */
     @RequiresPermission(
             value = Manifest.permission.FOREGROUND_SERVICE_DATA_SYNC,
             conditional = true
     )
-    @Deprecated
     public static final int FOREGROUND_SERVICE_TYPE_DATA_SYNC = 1 << 0;
 
     /**
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index 22e233a..ac80561 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -177,3 +177,10 @@
     description: "Enable the sensitive notifications toggle to be visible in the Private space settings page"
     bug: "317067050"
 }
+
+flag {
+    name: "enable_private_space_intent_redirection"
+    namespace: "profile_experiences"
+    description: "Enable Private Space telephony and SMS intent redirection to the main user"
+    bug: "325576602"
+}
diff --git a/core/java/android/credentials/GetCandidateCredentialsResponse.java b/core/java/android/credentials/GetCandidateCredentialsResponse.java
index 6e53fd9..3d8ccaa 100644
--- a/core/java/android/credentials/GetCandidateCredentialsResponse.java
+++ b/core/java/android/credentials/GetCandidateCredentialsResponse.java
@@ -18,7 +18,7 @@
 
 import android.annotation.Hide;
 import android.annotation.NonNull;
-import android.app.PendingIntent;
+import android.content.Intent;
 import android.credentials.selection.GetCredentialProviderData;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -39,32 +39,22 @@
     @NonNull
     private final List<GetCredentialProviderData> mCandidateProviderDataList;
 
-    private final PendingIntent mPendingIntent;
+    @NonNull
+    private final Intent mIntent;
 
     /**
      * @hide
      */
     @Hide
     public GetCandidateCredentialsResponse(
-            GetCredentialResponse getCredentialResponse
-    ) {
-        mCandidateProviderDataList = null;
-        mPendingIntent = null;
-    }
-
-    /**
-     * @hide
-     */
-    @Hide
-    public GetCandidateCredentialsResponse(
-            List<GetCredentialProviderData> candidateProviderDataList,
-            PendingIntent pendingIntent
+            @NonNull List<GetCredentialProviderData> candidateProviderDataList,
+            @NonNull Intent intent
     ) {
         Preconditions.checkCollectionNotEmpty(
                 candidateProviderDataList,
                 /*valueName=*/ "candidateProviderDataList");
         mCandidateProviderDataList = new ArrayList<>(candidateProviderDataList);
-        mPendingIntent = pendingIntent;
+        mIntent = intent;
     }
 
     /**
@@ -81,8 +71,9 @@
      *
      * @hide
      */
-    public PendingIntent getPendingIntent() {
-        return mPendingIntent;
+    @NonNull
+    public Intent getIntent() {
+        return mIntent;
     }
 
     protected GetCandidateCredentialsResponse(Parcel in) {
@@ -91,14 +82,13 @@
         mCandidateProviderDataList = candidateProviderDataList;
 
         AnnotationValidations.validate(NonNull.class, null, mCandidateProviderDataList);
-
-        mPendingIntent = in.readTypedObject(PendingIntent.CREATOR);
+        mIntent = in.readTypedObject(Intent.CREATOR);
     }
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeTypedList(mCandidateProviderDataList);
-        dest.writeTypedObject(mPendingIntent, flags);
+        dest.writeTypedObject(mIntent, flags);
     }
 
     @Override
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index b0f69f5..81e321d 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -83,8 +83,7 @@
 
 /**
  * A class that coordinates access to the fingerprint hardware.
- *
- * @removed See {@link BiometricPrompt} which shows a system-provided dialog upon starting
+ * @deprecated See {@link BiometricPrompt} which shows a system-provided dialog upon starting
  * authentication. In a world where devices may have different types of biometric authentication,
  * it's much more realistic to have a system-provided authentication dialog since the method may
  * vary by vendor/device.
@@ -95,6 +94,7 @@
 @RequiresFeature(PackageManager.FEATURE_FINGERPRINT)
 public class FingerprintManager implements BiometricAuthenticator, BiometricFingerprintConstants {
     private static final String TAG = "FingerprintManager";
+    private static final boolean DEBUG = true;
     private static final int MSG_ENROLL_RESULT = 100;
     private static final int MSG_ACQUIRED = 101;
     private static final int MSG_AUTHENTICATION_SUCCEEDED = 102;
@@ -196,7 +196,6 @@
 
     /**
      * Retrieves a test session for FingerprintManager.
-     *
      * @hide
      */
     @TestApi
@@ -255,10 +254,9 @@
     }
 
     /**
-     * A wrapper class for the crypto objects supported by FingerprintManager. Currently, the
+     * A wrapper class for the crypto objects supported by FingerprintManager. Currently the
      * framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects.
-     *
-     * @removed See {@link android.hardware.biometrics.BiometricPrompt.CryptoObject}
+     * @deprecated See {@link android.hardware.biometrics.BiometricPrompt.CryptoObject}
      */
     @Deprecated
     public static final class CryptoObject extends android.hardware.biometrics.CryptoObject {
@@ -332,8 +330,7 @@
     /**
      * Container for callback data from {@link FingerprintManager#authenticate(CryptoObject,
      *     CancellationSignal, int, AuthenticationCallback, Handler)}.
-     *
-     * @removed See {@link android.hardware.biometrics.BiometricPrompt.AuthenticationResult}
+     * @deprecated See {@link android.hardware.biometrics.BiometricPrompt.AuthenticationResult}
      */
     @Deprecated
     public static class AuthenticationResult {
@@ -395,8 +392,7 @@
      * FingerprintManager#authenticate(CryptoObject, CancellationSignal,
      * int, AuthenticationCallback, Handler) } must provide an implementation of this for listening to
      * fingerprint events.
-     *
-     * @removed See {@link android.hardware.biometrics.BiometricPrompt.AuthenticationCallback}
+     * @deprecated See {@link android.hardware.biometrics.BiometricPrompt.AuthenticationCallback}
      */
     @Deprecated
     public static abstract class AuthenticationCallback
@@ -459,7 +455,6 @@
     /**
      * Callback structure provided for {@link #detectFingerprint(CancellationSignal,
      * FingerprintDetectionCallback, int, Surface)}.
-     *
      * @hide
      */
     public interface FingerprintDetectionCallback {
@@ -613,8 +608,7 @@
      *         by <a href="{@docRoot}training/articles/keystore.html">Android Keystore
      *         facility</a>.
      * @throws IllegalStateException if the crypto primitive is not initialized.
-     *
-     * @removed See {@link BiometricPrompt#authenticate(CancellationSignal, Executor,
+     * @deprecated See {@link BiometricPrompt#authenticate(CancellationSignal, Executor,
      * BiometricPrompt.AuthenticationCallback)} and {@link BiometricPrompt#authenticate(
      * BiometricPrompt.CryptoObject, CancellationSignal, Executor,
      * BiometricPrompt.AuthenticationCallback)}
@@ -629,7 +623,6 @@
     /**
      * Per-user version of authenticate.
      * @deprecated use {@link #authenticate(CryptoObject, CancellationSignal, AuthenticationCallback, Handler, FingerprintAuthenticateOptions)}.
-     *
      * @hide
      */
     @Deprecated
@@ -642,7 +635,6 @@
     /**
      * Per-user and per-sensor version of authenticate.
      * @deprecated use {@link #authenticate(CryptoObject, CancellationSignal, AuthenticationCallback, Handler, FingerprintAuthenticateOptions)}.
-     *
      * @hide
      */
     @Deprecated
@@ -659,7 +651,6 @@
 
     /**
      * Version of authenticate with additional options.
-     *
      * @hide
      */
     @RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT})
@@ -707,7 +698,6 @@
     /**
      * Uses the fingerprint hardware to detect for the presence of a finger, without giving details
      * about accept/reject/lockout.
-     *
      * @hide
      */
     @RequiresPermission(USE_BIOMETRIC_INTERNAL)
@@ -750,7 +740,6 @@
      * @param callback an object to receive enrollment events
      * @param shouldLogMetrics a flag that indicates if enrollment failure/success metrics
      * should be logged.
-     *
      * @hide
      */
     @RequiresPermission(MANAGE_FINGERPRINT)
@@ -821,7 +810,6 @@
     /**
      * Same as {@link #generateChallenge(int, GenerateChallengeCallback)}, but assumes the first
      * enumerated sensor.
-     *
      * @hide
      */
     @RequiresPermission(MANAGE_FINGERPRINT)
@@ -836,7 +824,6 @@
 
     /**
      * Revokes the specified challenge.
-     *
      * @hide
      */
     @RequiresPermission(MANAGE_FINGERPRINT)
@@ -862,7 +849,6 @@
      * @param sensorId Sensor ID that this operation takes effect for
      * @param userId User ID that this operation takes effect for.
      * @param hardwareAuthToken An opaque token returned by password confirmation.
-     *
      * @hide
      */
     @RequiresPermission(RESET_FINGERPRINT_LOCKOUT)
@@ -900,7 +886,6 @@
 
     /**
      * Removes all fingerprint templates for the given user.
-     *
      * @hide
      */
     @RequiresPermission(MANAGE_FINGERPRINT)
@@ -1020,7 +1005,6 @@
     /**
      * Forwards BiometricStateListener to FingerprintService
      * @param listener new BiometricStateListener being added
-     *
      * @hide
      */
     public void registerBiometricStateListener(@NonNull BiometricStateListener listener) {
@@ -1172,8 +1156,7 @@
     }
 
     /**
-     * This is triggered by SideFpsEventHandler.
-     *
+     * This is triggered by SideFpsEventHandler
      * @hide
      */
     @RequiresPermission(USE_BIOMETRIC_INTERNAL)
@@ -1186,8 +1169,7 @@
      * Determine if there is at least one fingerprint enrolled.
      *
      * @return true if at least one fingerprint is enrolled, false otherwise
-     *
-     * @removed See {@link BiometricPrompt} and
+     * @deprecated See {@link BiometricPrompt} and
      * {@link FingerprintManager#FINGERPRINT_ERROR_NO_FINGERPRINTS}
      */
     @Deprecated
@@ -1221,8 +1203,7 @@
      * Determine if fingerprint hardware is present and functional.
      *
      * @return true if hardware is present and functional, false otherwise.
-     *
-     * @removed See {@link BiometricPrompt} and
+     * @deprecated See {@link BiometricPrompt} and
      * {@link FingerprintManager#FINGERPRINT_ERROR_HW_UNAVAILABLE}
      */
     @Deprecated
@@ -1248,7 +1229,6 @@
 
     /**
      * Get statically configured sensor properties.
-     *
      * @hide
      */
     @RequiresPermission(USE_BIOMETRIC_INTERNAL)
@@ -1267,7 +1247,6 @@
     /**
      * Returns whether the device has a power button fingerprint sensor.
      * @return boolean indicating whether power button is fingerprint sensor
-     *
      * @hide
      */
     public boolean isPowerbuttonFps() {
diff --git a/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java b/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java
index 510b14e..e28f345 100644
--- a/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java
+++ b/core/java/android/inputmethodservice/navigationbar/NavigationBarView.java
@@ -99,7 +99,11 @@
 
         mDeadZone = new android.inputmethodservice.navigationbar.DeadZone(this);
 
-        getImeSwitchButton().setOnClickListener(view -> view.getContext()
+        getBackButton().setLongClickable(false);
+
+        final ButtonDispatcher imeSwitchButton = getImeSwitchButton();
+        imeSwitchButton.setLongClickable(false);
+        imeSwitchButton.setOnClickListener(view -> view.getContext()
                 .getSystemService(InputMethodManager.class).showInputMethodPicker());
     }
 
diff --git a/core/java/android/net/flags.aconfig b/core/java/android/net/flags.aconfig
index 6efb872..9f9aef8 100644
--- a/core/java/android/net/flags.aconfig
+++ b/core/java/android/net/flags.aconfig
@@ -17,3 +17,9 @@
     bug: "307898240"
 }
 
+flag {
+  name: "register_nsd_offload_engine"
+  namespace: "android_core_networking"
+  description: "Flag for registerOffloadEngine API in NsdManager"
+  bug: "294777050"
+}
diff --git a/core/java/android/os/ExternalVibrationScale.aidl b/core/java/android/os/ExternalVibrationScale.aidl
new file mode 100644
index 0000000..cf6f8ed
--- /dev/null
+++ b/core/java/android/os/ExternalVibrationScale.aidl
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) 2018, 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 android.os;
+
+/**
+ * ExternalVibrationScale holds the vibration scale level and adaptive haptics scale. These
+ * can be used to scale external vibrations.
+ *
+ * @hide
+ */
+parcelable ExternalVibrationScale {
+    @Backing(type="int")
+    enum ScaleLevel {
+        SCALE_MUTE = -100,
+        SCALE_VERY_LOW = -2,
+        SCALE_LOW = -1,
+        SCALE_NONE = 0,
+        SCALE_HIGH = 1,
+        SCALE_VERY_HIGH = 2
+    }
+
+    /**
+     * The scale level that will be applied to external vibrations.
+     */
+    ScaleLevel scaleLevel = ScaleLevel.SCALE_NONE;
+
+    /**
+     * The adaptive haptics scale that will be applied to external vibrations.
+     */
+    float adaptiveHapticsScale = 1f;
+}
diff --git a/core/java/android/os/HandlerThread.java b/core/java/android/os/HandlerThread.java
index 36730cb..f852d3c 100644
--- a/core/java/android/os/HandlerThread.java
+++ b/core/java/android/os/HandlerThread.java
@@ -19,6 +19,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 
+import java.util.concurrent.Executor;
+
 /**
  * A {@link Thread} that has a {@link Looper}.
  * The {@link Looper} can then be used to create {@link Handler}s.
@@ -30,7 +32,8 @@
     int mPriority;
     int mTid = -1;
     Looper mLooper;
-    private @Nullable Handler mHandler;
+    private volatile @Nullable Handler mHandler;
+    private volatile @Nullable Executor mExecutor;
 
     public HandlerThread(String name) {
         super(name);
@@ -131,6 +134,18 @@
     }
 
     /**
+     * @return a shared {@link Executor} associated with this thread
+     * @hide
+     */
+    @NonNull
+    public Executor getThreadExecutor() {
+        if (mExecutor == null) {
+            mExecutor = new HandlerExecutor(getThreadHandler());
+        }
+        return mExecutor;
+    }
+
+    /**
      * Quits the handler thread's looper.
      * <p>
      * Causes the handler thread's looper to terminate without processing any
diff --git a/core/java/android/os/IExternalVibratorService.aidl b/core/java/android/os/IExternalVibratorService.aidl
index 666171f..a9df15a 100644
--- a/core/java/android/os/IExternalVibratorService.aidl
+++ b/core/java/android/os/IExternalVibratorService.aidl
@@ -17,6 +17,7 @@
 package android.os;
 
 import android.os.ExternalVibration;
+import android.os.ExternalVibrationScale;
 
 /**
  * The communication channel by which an external system that wants to control the system
@@ -32,29 +33,24 @@
  * {@hide}
  */
 interface IExternalVibratorService {
-    const int SCALE_MUTE = -100;
-    const int SCALE_VERY_LOW = -2;
-    const int SCALE_LOW = -1;
-    const int SCALE_NONE = 0;
-    const int SCALE_HIGH = 1;
-    const int SCALE_VERY_HIGH = 2;
-
     /**
      * A method called by the external system to start a vibration.
      *
-     * If this returns {@code SCALE_MUTE}, then the vibration should <em>not</em> play. If this
-     * returns any other scale level, then any currently playing vibration controlled by the
-     * requesting system must be muted and this vibration can begin playback.
+     * This returns an {@link ExternalVibrationScale} which includes the vibration scale level and
+     * the adaptive haptics scale.
+     *
+     * If the returned scale level is {@link ExternalVibrationScale.ScaleLevel#SCALE_MUTE}, then
+     * the vibration should <em>not</em> play. If it returns any other scale level, then
+     * any currently playing vibration controlled by the requesting system must be muted and this
+     * vibration can begin playback.
      *
      * Note that the IExternalVibratorService implementation will not call mute on any currently
      * playing external vibrations in order to avoid re-entrancy with the system on the other side.
      *
-     * @param vibration An ExternalVibration
-     *
-     * @return {@code SCALE_MUTE} if the external vibration should not play, and any other scale
-     *         level if it should.
+     * @param vib The external vibration starting.
+     * @return {@link ExternalVibrationScale} including scale level and adaptive haptics scale.
      */
-    int onExternalVibrationStart(in ExternalVibration vib);
+    ExternalVibrationScale onExternalVibrationStart(in ExternalVibration vib);
 
     /**
      * A method called by the external system when a vibration no longer wants to play.
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index be17d7c..ccb534e 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1920,9 +1920,7 @@
      * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
-    // TODO (b/325886480): update the flag to
-    // "com.android.net.thread.platform.flags.Flags.FLAG_THREAD_USER_RESTRICTION_ENABLED"
-    @FlaggedApi("com.android.net.thread.flags.thread_user_restriction_enabled")
+    @FlaggedApi(com.android.net.thread.platform.flags.Flags.FLAG_THREAD_USER_RESTRICTION_ENABLED)
     public static final String DISALLOW_THREAD_NETWORK = "no_thread_network";
 
     /**
diff --git a/core/java/android/os/WakeLockStats.java b/core/java/android/os/WakeLockStats.java
index 69e70a0..3769f38 100644
--- a/core/java/android/os/WakeLockStats.java
+++ b/core/java/android/os/WakeLockStats.java
@@ -23,17 +23,21 @@
 
 /**
  * Snapshot of wake lock stats.
- *  @hide
+ *
+ * @hide
  */
 @android.ravenwood.annotation.RavenwoodKeepWholeClass
 public final class WakeLockStats implements Parcelable {
 
-    /** @hide */
-    public static class WakeLock {
-        public final int uid;
-        @NonNull
-        public final String name;
+    public static class WakeLockData {
+
+        public static final WakeLockData EMPTY = new WakeLockData(
+                /* timesAcquired= */ 0, /* totalTimeHeldMs= */ 0, /* timeHeldMs= */ 0);
+
+        /** How many times this wakelock has been acquired. */
         public final int timesAcquired;
+
+        /** Time in milliseconds that the lock has been held in total. */
         public final long totalTimeHeldMs;
 
         /**
@@ -41,26 +45,34 @@
          */
         public final long timeHeldMs;
 
-        public WakeLock(int uid, @NonNull String name, int timesAcquired, long totalTimeHeldMs,
-                long timeHeldMs) {
-            this.uid = uid;
-            this.name = name;
+        public WakeLockData(int timesAcquired, long totalTimeHeldMs, long timeHeldMs) {
             this.timesAcquired = timesAcquired;
             this.totalTimeHeldMs = totalTimeHeldMs;
             this.timeHeldMs = timeHeldMs;
         }
 
-        private WakeLock(Parcel in) {
-            uid = in.readInt();
-            name = in.readString();
+        /**
+         * Whether the fields are able to construct a valid wakelock.
+         */
+        public boolean isDataValid() {
+            final boolean isDataReasonable = timesAcquired > 0
+                    && totalTimeHeldMs > 0
+                    && timeHeldMs >= 0
+                    && totalTimeHeldMs >= timeHeldMs;
+            return isEmpty() || isDataReasonable;
+        }
+
+        private boolean isEmpty() {
+            return timesAcquired == 0 && totalTimeHeldMs == 0 && timeHeldMs == 0;
+        }
+
+        private WakeLockData(Parcel in) {
             timesAcquired = in.readInt();
             totalTimeHeldMs = in.readLong();
             timeHeldMs = in.readLong();
         }
 
         private void writeToParcel(Parcel out) {
-            out.writeInt(uid);
-            out.writeString(name);
             out.writeInt(timesAcquired);
             out.writeLong(totalTimeHeldMs);
             out.writeLong(timeHeldMs);
@@ -68,21 +80,98 @@
 
         @Override
         public String toString() {
+            return "WakeLockData{"
+                + "timesAcquired="
+                + timesAcquired
+                + ", totalTimeHeldMs="
+                + totalTimeHeldMs
+                + ", timeHeldMs="
+                + timeHeldMs
+                + "}";
+        }
+    }
+
+    /** @hide */
+    public static class WakeLock {
+
+        public static final String NAME_AGGREGATED = "wakelockstats_aggregated";
+
+        public final int uid;
+        @NonNull public final String name;
+        public final boolean isAggregated;
+
+        /** Wakelock data on both foreground and background. */
+        @NonNull public final WakeLockData totalWakeLockData;
+
+        /** Wakelock data on background. */
+        @NonNull public final WakeLockData backgroundWakeLockData;
+
+        public WakeLock(
+                int uid,
+                @NonNull String name,
+                boolean isAggregated,
+                @NonNull WakeLockData totalWakeLockData,
+                @NonNull WakeLockData backgroundWakeLockData) {
+            this.uid = uid;
+            this.name = name;
+            this.isAggregated = isAggregated;
+            this.totalWakeLockData = totalWakeLockData;
+            this.backgroundWakeLockData = backgroundWakeLockData;
+        }
+
+        /** Whether the combination of total and background wakelock data is invalid. */
+        public static boolean isDataValid(
+                WakeLockData totalWakeLockData, WakeLockData backgroundWakeLockData) {
+            return totalWakeLockData.totalTimeHeldMs > 0
+                && totalWakeLockData.isDataValid()
+                && backgroundWakeLockData.isDataValid()
+                && totalWakeLockData.timesAcquired >= backgroundWakeLockData.timesAcquired
+                && totalWakeLockData.totalTimeHeldMs >= backgroundWakeLockData.totalTimeHeldMs
+                && totalWakeLockData.timeHeldMs >= backgroundWakeLockData.timeHeldMs;
+        }
+
+        private WakeLock(Parcel in) {
+            uid = in.readInt();
+            name = in.readString();
+            isAggregated = in.readBoolean();
+            totalWakeLockData = new WakeLockData(in);
+            backgroundWakeLockData = new WakeLockData(in);
+        }
+
+        private void writeToParcel(Parcel out) {
+            out.writeInt(uid);
+            out.writeString(name);
+            out.writeBoolean(isAggregated);
+            totalWakeLockData.writeToParcel(out);
+            backgroundWakeLockData.writeToParcel(out);
+        }
+
+        @Override
+        public String toString() {
             return "WakeLock{"
-                    + "uid=" + uid
-                    + ", name='" + name + '\''
-                    + ", timesAcquired=" + timesAcquired
-                    + ", totalTimeHeldMs=" + totalTimeHeldMs
-                    + ", timeHeldMs=" + timeHeldMs
-                    + '}';
+                + "uid="
+                + uid
+                + ", name='"
+                + name
+                + '\''
+                + ", isAggregated="
+                + isAggregated
+                + ", totalWakeLockData="
+                + totalWakeLockData
+                + ", backgroundWakeLockData="
+                + backgroundWakeLockData
+                + '}';
         }
     }
 
     private final List<WakeLock> mWakeLocks;
+    private final List<WakeLock> mAggregatedWakeLocks;
 
-    /** @hide **/
-    public WakeLockStats(@NonNull List<WakeLock> wakeLocks) {
+    /** @hide */
+    public WakeLockStats(
+            @NonNull List<WakeLock> wakeLocks, @NonNull List<WakeLock> aggregatedWakeLocks) {
         mWakeLocks = wakeLocks;
+        mAggregatedWakeLocks = aggregatedWakeLocks;
     }
 
     @NonNull
@@ -90,22 +179,38 @@
         return mWakeLocks;
     }
 
+    @NonNull
+    public List<WakeLock> getAggregatedWakeLocks() {
+        return mAggregatedWakeLocks;
+    }
+
     private WakeLockStats(Parcel in) {
-        final int size = in.readInt();
-        mWakeLocks = new ArrayList<>(size);
-        for (int i = 0; i < size; i++) {
+        final int wakelockSize = in.readInt();
+        mWakeLocks = new ArrayList<>(wakelockSize);
+        for (int i = 0; i < wakelockSize; i++) {
             mWakeLocks.add(new WakeLock(in));
         }
+        final int aggregatedWakelockSize = in.readInt();
+        mAggregatedWakeLocks = new ArrayList<>(aggregatedWakelockSize);
+        for (int i = 0; i < aggregatedWakelockSize; i++) {
+            mAggregatedWakeLocks.add(new WakeLock(in));
+        }
     }
 
     @Override
     public void writeToParcel(@NonNull Parcel out, int flags) {
-        final int size = mWakeLocks.size();
-        out.writeInt(size);
-        for (int i = 0; i < size; i++) {
+        final int wakelockSize = mWakeLocks.size();
+        out.writeInt(wakelockSize);
+        for (int i = 0; i < wakelockSize; i++) {
             WakeLock stats = mWakeLocks.get(i);
             stats.writeToParcel(out);
         }
+        final int aggregatedWakelockSize = mAggregatedWakeLocks.size();
+        out.writeInt(aggregatedWakelockSize);
+        for (int i = 0; i < aggregatedWakelockSize; i++) {
+            WakeLock stats = mAggregatedWakeLocks.get(i);
+            stats.writeToParcel(out);
+        }
     }
 
     @NonNull
@@ -127,6 +232,13 @@
 
     @Override
     public String toString() {
-        return "WakeLockStats " + mWakeLocks;
+        return "WakeLockStats{"
+            + "mWakeLocks: ["
+            + mWakeLocks
+            + "]"
+            + ", mAggregatedWakeLocks: ["
+            + mAggregatedWakeLocks
+            + "]"
+            + '}';
     }
 }
diff --git a/core/java/android/os/storage/OWNERS b/core/java/android/os/storage/OWNERS
index 2cb16d337b..c21895a 100644
--- a/core/java/android/os/storage/OWNERS
+++ b/core/java/android/os/storage/OWNERS
@@ -3,11 +3,15 @@
 # PLEASE ASSIGN NEW BUGS TO android-storage-triage@, NOT TO INDIVIDUAL PEOPLE
 
 # Android Storage Team
+aibra@google.com
+akgaurav@google.com
 alukin@google.com
 ankitavyas@google.com
 dipankarb@google.com
 gargshivam@google.com
+ishneet@google.com
 krishang@google.com
+oeissa@google.com
 riyaghai@google.com
 sahanas@google.com
 shikhamalhotra@google.com
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index fd52c76..8495f37 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -1944,25 +1944,27 @@
      *
      * @param permissionName The name of the permission you are checking for.
      * @param packageName The name of the package you are checking against.
-     * @param persistentDeviceId The persistent device id you are checking against.
-     * @param userId The user Id associated with context.
+     * @param persistentDeviceId The id of the physical device that you are checking permission
+     *                           against.
      *
      * @return If the package has the permission on the device, PERMISSION_GRANTED is
      * returned.  If it does not have the permission on the device, PERMISSION_DENIED
      * is returned.
      *
+     * @see VirtualDevice#getPersistentDeviceId()
      * @see PackageManager#PERMISSION_GRANTED
      * @see PackageManager#PERMISSION_DENIED
      *
      * @hide
      */
     @SystemApi
+    @PermissionResult
     @FlaggedApi(Flags.FLAG_DEVICE_AWARE_PERMISSION_APIS_ENABLED)
-    public static int checkPermission(@NonNull String permissionName, @NonNull String packageName,
-            @NonNull String persistentDeviceId, @UserIdInt int userId) {
+    public int checkPermission(@NonNull String permissionName, @NonNull String packageName,
+            @NonNull String persistentDeviceId) {
         return sPackageNamePermissionCache.query(
                 new PackageNamePermissionQuery(permissionName, packageName, persistentDeviceId,
-                        userId));
+                        mContext.getUserId()));
     }
 
     /**
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index 460b4dd..141ffc9 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -359,8 +359,7 @@
                         new PermissionGroupUsage(usage.packageName, usage.uid, usage.lastAccessTime,
                                 permGroup,
                                 usage.isRunning, isPhone, usage.attributionTag, attributionLabel,
-                                usagesWithLabels.valueAt(usageNum),
-                                VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT));
+                                usagesWithLabels.valueAt(usageNum), deviceId));
             }
         }
 
diff --git a/core/java/android/provider/ContactKeysManager.java b/core/java/android/provider/E2eeContactKeysManager.java
similarity index 70%
rename from core/java/android/provider/ContactKeysManager.java
rename to core/java/android/provider/E2eeContactKeysManager.java
index 01aaa3d..b694417 100644
--- a/core/java/android/provider/ContactKeysManager.java
+++ b/core/java/android/provider/E2eeContactKeysManager.java
@@ -39,18 +39,18 @@
 import java.util.Objects;
 
 /**
- * ContactKeysManager provides access to the provider of end-to-end encryption contact keys.
- * It manages two types of keys - {@link ContactKey} and {@link SelfKey}.
+ * E2eeContactKeysManager provides access to the provider of end-to-end encryption contact keys.
+ * It manages two types of keys - {@link E2eeContactKey} and {@link E2eeSelfKey}.
  * <ul>
  * <li>
- * A {@link ContactKey} is a public key associated with a contact. It's used to end-to-end
+ * A {@link E2eeContactKey} is a public key associated with a contact. It's used to end-to-end
  * encrypt the communications between a user and the contact. This API allows operations on
- * {@link ContactKey}s to insert/update, remove, change the verification state, and retrieving
+ * {@link E2eeContactKey}s to insert/update, remove, change the verification state, and retrieving
  * keys (either created by or visible to the caller app).
  * </li>
  * <li>
- * A {@link SelfKey} is a key for this device, so the key represents the owner of the device.
- * This API allows operations on {@link SelfKey}s to insert/update, remove, and retrieving
+ * A {@link E2eeSelfKey} is a key for this device, so the key represents the owner of the device.
+ * This API allows operations on {@link E2eeSelfKey}s to insert/update, remove, and retrieving
  * self keys (either created by or visible to the caller app).
  * </li>
  * </ul>
@@ -65,29 +65,30 @@
  * </li>
  * <li>
  * accountId - the app-specified identifier for the account for which the contact key can be used.
- * Usually a phone number.
+ * Using different account IDs allows for multiple key entries representing the same user.
+ * For most apps this would be a phone number.
  * </li>
  * </ul>
  * Contact keys also use lookupKey which is an opaque value used to identify a contact in
  * ContactsProvider.
  */
 @FlaggedApi(Flags.FLAG_USER_KEYS)
-public final class ContactKeysManager {
+public final class E2eeContactKeysManager {
     /**
-     * The authority for the contact keys provider.
+     * The authority for the end-to-end encryption contact keys provider.
      * @hide
      */
     public static final String AUTHORITY = "com.android.contactkeys.contactkeysprovider";
 
     /**
-     * A content:// style uri to the authority for the contact keys provider.
+     * A content:// style uri to the authority for the end-to-end encryption contact keys provider.
      * @hide
      */
     @NonNull
     public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
 
     /**
-     * Maximum size of a contact key.
+     * Maximum size of an end-to-end encryption contact key.
      */
     private static final int MAX_KEY_SIZE_BYTES = 5000;
 
@@ -100,14 +101,15 @@
     private final ContentResolver mContentResolver;
 
     /** @hide */
-    public ContactKeysManager(@NonNull Context context) {
+    public E2eeContactKeysManager(@NonNull Context context) {
         Objects.requireNonNull(context);
         mContentResolver = context.getContentResolver();
     }
 
     /**
-     * Inserts a new entry into the contact keys table or updates one if it already exists.
-     * The inserted/updated contact key is owned by the caller app.
+     * Inserts a new entry into the end-to-end encryption contact keys table or updates one if it
+     * already exists.
+     * The inserted/updated end-to-end encryption contact key is owned by the caller app.
      *
      * @param lookupKey value that references the contact
      * @param deviceId an app-specified identifier for the device
@@ -115,76 +117,77 @@
      * @param keyValue the raw bytes for the key (max size is {@link #getMaxKeySizeBytes} bytes)
      */
     @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
-    public void updateOrInsertContactKey(@NonNull String lookupKey,
+    public void updateOrInsertE2eeContactKey(@NonNull String lookupKey,
             @NonNull String deviceId,
             @NonNull String accountId,
             @NonNull byte[] keyValue) {
         validateKeyLength(keyValue);
 
         Bundle extras = new Bundle();
-        extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
-        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
-        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
-        extras.putByteArray(ContactKeys.KEY_VALUE, Objects.requireNonNull(keyValue));
+        extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+        extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+        extras.putByteArray(E2eeContactKeys.KEY_VALUE, Objects.requireNonNull(keyValue));
 
         nullSafeCall(mContentResolver,
-                ContactKeys.UPDATE_OR_INSERT_CONTACT_KEY_METHOD, extras);
+                E2eeContactKeys.UPDATE_OR_INSERT_CONTACT_KEY_METHOD, extras);
     }
 
     /**
-     * Retrieves a contact key entry given the lookup key, device ID, accountId and inferred
-     * caller package name.
+     * Retrieves an end-to-end encryption contact key entry given the lookup key, device ID,
+     * accountId and inferred caller package name.
      *
      * @param lookupKey the value that references the contact
      * @param deviceId an app-specified identifier for the device
      * @param accountId an app-specified identifier for the account
      *
-     * @return a {@link ContactKey} object containing the contact key information,
+     * @return a {@link E2eeContactKey} object containing the contact key information,
      * or null if no contact key is found.
      */
     @RequiresPermission(android.Manifest.permission.READ_CONTACTS)
     @Nullable
-    public ContactKey getContactKey(
+    public E2eeContactKey getE2eeContactKey(
             @NonNull String lookupKey,
             @NonNull String deviceId,
             @NonNull String accountId) {
         Bundle extras = new Bundle();
-        extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
-        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
-        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+        extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+        extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
 
         Bundle response = nullSafeCall(mContentResolver,
-                ContactKeys.GET_CONTACT_KEY_METHOD, extras);
+                E2eeContactKeys.GET_CONTACT_KEY_METHOD, extras);
 
         if (response == null) {
             return null;
         }
-        return response.getParcelable(ContactKeys.KEY_CONTACT_KEY, ContactKey.class);
+        return response.getParcelable(E2eeContactKeys.KEY_CONTACT_KEY, E2eeContactKey.class);
     }
 
     /**
-     * Retrieves all contact key entries that belong to apps visible to the caller.
+     * Retrieves all end-to-end encryption contact key entries that belong to apps visible to
+     * the caller.
      * The keys will be stripped of deviceId, timeUpdated and keyValue data.
      *
      * @param lookupKey the value that references the contact
      *
-     * @return a list of {@link ContactKey} objects containing the contact key
+     * @return a list of {@link E2eeContactKey} objects containing the contact key
      * information, or an empty list if no keys are found.
      */
     @RequiresPermission(android.Manifest.permission.READ_CONTACTS)
     @NonNull
-    public List<ContactKey> getAllContactKeys(@NonNull String lookupKey) {
+    public List<E2eeContactKey> getAllE2eeContactKeys(@NonNull String lookupKey) {
         Bundle extras = new Bundle();
-        extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+        extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
 
         Bundle response = nullSafeCall(mContentResolver,
-                ContactKeys.GET_ALL_CONTACT_KEYS_METHOD, extras);
+                E2eeContactKeys.GET_ALL_CONTACT_KEYS_METHOD, extras);
 
         if (response == null) {
             return new ArrayList<>();
         }
-        List<ContactKey> value = response.getParcelableArrayList(ContactKeys.KEY_CONTACT_KEYS,
-                ContactKey.class);
+        List<E2eeContactKey> value = response.getParcelableArrayList(
+                E2eeContactKeys.KEY_CONTACT_KEYS, E2eeContactKey.class);
         if (value == null) {
             return new ArrayList<>();
         }
@@ -192,27 +195,28 @@
     }
 
     /**
-     * Retrieves all contact key entries for a given lookupKey that belong to the caller app.
+     * Retrieves all end-to-end encryption contact key entries for a given lookupKey that belong to
+     * the caller app.
      *
      * @param lookupKey the value that references the contact
      *
-     * @return a list of {@link ContactKey} objects containing the contact key
-     * information, or an empty list if no keys are found.
+     * @return a list of {@link E2eeContactKey} objects containing the end-to-end encryption
+     * contact key information, or an empty list if no keys are found.
      */
     @RequiresPermission(android.Manifest.permission.READ_CONTACTS)
     @NonNull
-    public List<ContactKey> getOwnerContactKeys(@NonNull String lookupKey) {
+    public List<E2eeContactKey> getOwnerE2eeContactKeys(@NonNull String lookupKey) {
         Bundle extras = new Bundle();
-        extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+        extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
 
         Bundle response = nullSafeCall(mContentResolver,
-                ContactKeys.GET_OWNER_CONTACT_KEYS_METHOD, extras);
+                E2eeContactKeys.GET_OWNER_CONTACT_KEYS_METHOD, extras);
 
         if (response == null) {
             return new ArrayList<>();
         }
-        List<ContactKey> value = response.getParcelableArrayList(ContactKeys.KEY_CONTACT_KEYS,
-                ContactKey.class);
+        List<E2eeContactKey> value = response.getParcelableArrayList(
+                E2eeContactKeys.KEY_CONTACT_KEYS, E2eeContactKey.class);
         if (value == null) {
             return new ArrayList<>();
         }
@@ -220,7 +224,8 @@
     }
 
     /**
-     * Updates a contact key entry's local verification state that belongs to the caller app.
+     * Updates an end-to-end encryption contact key entry's local verification state that belongs
+     * to the caller app.
      *
      * @param lookupKey the value that references the contact
      * @param deviceId an app-specified identifier for the device
@@ -230,27 +235,27 @@
      * @return true if the entry was updated, false otherwise.
      */
     @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
-    public boolean updateContactKeyLocalVerificationState(@NonNull String lookupKey,
+    public boolean updateE2eeContactKeyLocalVerificationState(@NonNull String lookupKey,
             @NonNull String deviceId,
             @NonNull String accountId,
             @VerificationState int localVerificationState) {
         validateVerificationState(localVerificationState);
 
         Bundle extras = new Bundle();
-        extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
-        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
-        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
-        extras.putInt(ContactKeys.LOCAL_VERIFICATION_STATE, localVerificationState);
+        extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+        extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+        extras.putInt(E2eeContactKeys.LOCAL_VERIFICATION_STATE, localVerificationState);
 
         Bundle response = nullSafeCall(mContentResolver,
-                ContactKeys.UPDATE_CONTACT_KEY_LOCAL_VERIFICATION_STATE_METHOD, extras);
+                E2eeContactKeys.UPDATE_CONTACT_KEY_LOCAL_VERIFICATION_STATE_METHOD, extras);
 
-        return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS);
+        return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS);
     }
 
     /**
-     * Updates a contact key entry's local verification state that belongs to the app identified
-     * by ownerPackageName.
+     * Updates an end-to-end encryption contact key entry's local verification state that belongs
+     * to the app identified by ownerPackageName.
      *
      * @param lookupKey the value that references the contact
      * @param deviceId an app-specified identifier for the device
@@ -266,7 +271,7 @@
     @RequiresPermission(allOf = {
             android.Manifest.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS,
             android.Manifest.permission.WRITE_CONTACTS})
-    public boolean updateContactKeyLocalVerificationState(@NonNull String lookupKey,
+    public boolean updateE2eeContactKeyLocalVerificationState(@NonNull String lookupKey,
             @NonNull String deviceId,
             @NonNull String accountId,
             @NonNull String ownerPackageName,
@@ -274,20 +279,22 @@
         validateVerificationState(localVerificationState);
 
         final Bundle extras = new Bundle();
-        extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
-        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
-        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
-        extras.putString(ContactKeys.OWNER_PACKAGE_NAME, Objects.requireNonNull(ownerPackageName));
-        extras.putInt(ContactKeys.LOCAL_VERIFICATION_STATE, localVerificationState);
+        extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+        extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+        extras.putString(E2eeContactKeys.OWNER_PACKAGE_NAME,
+                Objects.requireNonNull(ownerPackageName));
+        extras.putInt(E2eeContactKeys.LOCAL_VERIFICATION_STATE, localVerificationState);
 
         final Bundle response = nullSafeCall(mContentResolver,
-                ContactKeys.UPDATE_CONTACT_KEY_LOCAL_VERIFICATION_STATE_METHOD, extras);
+                E2eeContactKeys.UPDATE_CONTACT_KEY_LOCAL_VERIFICATION_STATE_METHOD, extras);
 
-        return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS);
+        return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS);
     }
 
     /**
-     * Updates a contact key entry's remote verification state that belongs to the caller app.
+     * Updates an end-to-end encryption contact key entry's remote verification state that belongs
+     * to the caller app.
      *
      * @param lookupKey the value that references the contact
      * @param deviceId an app-specified identifier for the device
@@ -297,27 +304,27 @@
      * @return true if the entry was updated, false otherwise.
      */
     @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
-    public boolean updateContactKeyRemoteVerificationState(@NonNull String lookupKey,
+    public boolean updateE2eeContactKeyRemoteVerificationState(@NonNull String lookupKey,
             @NonNull String deviceId,
             @NonNull String accountId,
             @VerificationState int remoteVerificationState) {
         validateVerificationState(remoteVerificationState);
 
         Bundle extras = new Bundle();
-        extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
-        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
-        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
-        extras.putInt(ContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState);
+        extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+        extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+        extras.putInt(E2eeContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState);
 
         Bundle response = nullSafeCall(mContentResolver,
-                ContactKeys.UPDATE_CONTACT_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras);
+                E2eeContactKeys.UPDATE_CONTACT_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras);
 
-        return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS);
+        return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS);
     }
 
     /**
-     * Updates a contact key entry's remote verification state that belongs to the app identified
-     * by ownerPackageName.
+     * Updates an end-to-end encryption contact key entry's remote verification state that belongs
+     * to the app identified by ownerPackageName.
      *
      * @param lookupKey the value that references the contact
      * @param deviceId an app-specified identifier for the device
@@ -333,7 +340,7 @@
     @RequiresPermission(allOf = {
             android.Manifest.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS,
             android.Manifest.permission.WRITE_CONTACTS})
-    public boolean updateContactKeyRemoteVerificationState(@NonNull String lookupKey,
+    public boolean updateE2eeContactKeyRemoteVerificationState(@NonNull String lookupKey,
             @NonNull String deviceId,
             @NonNull String accountId,
             @NonNull String ownerPackageName,
@@ -341,19 +348,19 @@
         validateVerificationState(remoteVerificationState);
 
         final Bundle extras = new Bundle();
-        extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
-        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
-        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
-        extras.putString(ContactKeys.OWNER_PACKAGE_NAME, Objects.requireNonNull(ownerPackageName));
-        extras.putInt(ContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState);
+        extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+        extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+        extras.putString(E2eeContactKeys.OWNER_PACKAGE_NAME,
+                Objects.requireNonNull(ownerPackageName));
+        extras.putInt(E2eeContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState);
 
         final Bundle response = nullSafeCall(mContentResolver,
-                ContactKeys.UPDATE_CONTACT_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras);
+                E2eeContactKeys.UPDATE_CONTACT_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras);
 
-        return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS);
+        return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS);
     }
 
-
     private static void validateVerificationState(int verificationState) {
         if (verificationState != VERIFICATION_STATE_UNVERIFIED
                 && verificationState != VERIFICATION_STATE_VERIFICATION_FAILED
@@ -364,7 +371,7 @@
     }
 
     /**
-     * Removes a contact key entry that belongs to the caller app.
+     * Removes an end-to-end encryption contact key entry that belongs to the caller app.
      *
      * @param lookupKey the value that references the contact
      * @param deviceId an app-specified identifier for the device
@@ -373,22 +380,23 @@
      * @return true if the entry was removed, false otherwise.
      */
     @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
-    public boolean removeContactKey(@NonNull String lookupKey,
+    public boolean removeE2eeContactKey(@NonNull String lookupKey,
             @NonNull String deviceId,
             @NonNull String accountId) {
         final Bundle extras = new Bundle();
-        extras.putString(ContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
-        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
-        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+        extras.putString(E2eeContactKeys.LOOKUP_KEY, Objects.requireNonNull(lookupKey));
+        extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
 
         final Bundle response = nullSafeCall(mContentResolver,
-                ContactKeys.REMOVE_CONTACT_KEY_METHOD, extras);
+                E2eeContactKeys.REMOVE_CONTACT_KEY_METHOD, extras);
 
-        return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS);
+        return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS);
     }
 
     /**
-     * Inserts a new entry into the self keys table or updates one if it already exists.
+     * Inserts a new entry into the end-to-end encryption self keys table or updates one if it
+     * already exists.
 
      * @param deviceId an app-specified identifier for the device
      * @param accountId an app-specified identifier for the account
@@ -397,20 +405,20 @@
      * @return true if the entry was added or updated, false otherwise.
      */
     @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
-    public boolean updateOrInsertSelfKey(@NonNull String deviceId,
+    public boolean updateOrInsertE2eeSelfKey(@NonNull String deviceId,
             @NonNull String accountId,
             @NonNull byte[] keyValue) {
         validateKeyLength(keyValue);
 
         Bundle extras = new Bundle();
-        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
-        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
-        extras.putByteArray(ContactKeys.KEY_VALUE, Objects.requireNonNull(keyValue));
+        extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+        extras.putByteArray(E2eeContactKeys.KEY_VALUE, Objects.requireNonNull(keyValue));
 
         Bundle response = nullSafeCall(mContentResolver,
-                ContactKeys.UPDATE_OR_INSERT_SELF_KEY_METHOD, extras);
+                E2eeContactKeys.UPDATE_OR_INSERT_SELF_KEY_METHOD, extras);
 
-        return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS);
+        return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS);
     }
 
     private static void validateKeyLength(byte[] keyValue) {
@@ -422,7 +430,7 @@
     }
 
     /**
-     * Updates a self key entry's remote verification state.
+     * Updates an end-to-end encryption self key entry's remote verification state.
      *
      * @param deviceId an app-specified identifier for the device
      * @param accountId an app-specified identifier for the account
@@ -431,25 +439,25 @@
      * @return true if the entry was updated, false otherwise.
      */
     @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
-    public boolean updateSelfKeyRemoteVerificationState(@NonNull String deviceId,
+    public boolean updateE2eeSelfKeyRemoteVerificationState(@NonNull String deviceId,
             @NonNull String accountId,
             @VerificationState int remoteVerificationState) {
         validateVerificationState(remoteVerificationState);
 
         Bundle extras = new Bundle();
-        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
-        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
-        extras.putInt(ContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState);
+        extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+        extras.putInt(E2eeContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState);
 
         Bundle response = nullSafeCall(mContentResolver,
-                ContactKeys.UPDATE_SELF_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras);
+                E2eeContactKeys.UPDATE_SELF_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras);
 
-        return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS);
+        return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS);
     }
 
     /**
-     * Updates a self key entry's remote verification state that belongs to the app identified
-     * by ownerPackageName.
+     * Updates an end-to-end encryption self key entry's remote verification state that belongs to
+     * the app identified by ownerPackageName.
      *
      * @param deviceId an app-specified identifier for the device
      * @param accountId an app-specified identifier for the account
@@ -464,77 +472,79 @@
     @RequiresPermission(allOf = {
             android.Manifest.permission.WRITE_VERIFICATION_STATE_E2EE_CONTACT_KEYS,
             android.Manifest.permission.WRITE_CONTACTS})
-    public boolean updateSelfKeyRemoteVerificationState(@NonNull String deviceId,
+    public boolean updateE2eeSelfKeyRemoteVerificationState(@NonNull String deviceId,
             @NonNull String accountId,
             @NonNull String ownerPackageName,
             @VerificationState int remoteVerificationState) {
         validateVerificationState(remoteVerificationState);
 
         Bundle extras = new Bundle();
-        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
-        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
-        extras.putString(ContactKeys.OWNER_PACKAGE_NAME, Objects.requireNonNull(ownerPackageName));
-        extras.putInt(ContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState);
+        extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+        extras.putString(E2eeContactKeys.OWNER_PACKAGE_NAME,
+                Objects.requireNonNull(ownerPackageName));
+        extras.putInt(E2eeContactKeys.REMOTE_VERIFICATION_STATE, remoteVerificationState);
 
         Bundle response = nullSafeCall(mContentResolver,
-                ContactKeys.UPDATE_SELF_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras);
+                E2eeContactKeys.UPDATE_SELF_KEY_REMOTE_VERIFICATION_STATE_METHOD, extras);
 
-        return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS);
+        return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS);
     }
 
     /**
-     * Maximum size of a contact key.
+     * Maximum size of an end-to-end encryption contact key.
      */
     public static int getMaxKeySizeBytes() {
         return MAX_KEY_SIZE_BYTES;
     }
 
     /**
-     * Returns a self key entry given the deviceId and the inferred package name of the caller.
+     * Returns an end-to-end encryption self key entry given the deviceId and the inferred package
+     * name of the caller.
      *
      * @param deviceId an app-specified identifier for the device
      * @param accountId an app-specified identifier for the account
      *
-     * @return a {@link SelfKey} object containing the self key information, or null if no self key
-     * is found.
+     * @return a {@link E2eeSelfKey} object containing the end-to-end encryption self key
+     * information, or null if no self key is found.
      */
     @RequiresPermission(android.Manifest.permission.READ_CONTACTS)
     @Nullable
-    public SelfKey getSelfKey(@NonNull String deviceId,
+    public E2eeSelfKey getE2eeSelfKey(@NonNull String deviceId,
             @NonNull String accountId) {
         Bundle extras = new Bundle();
-        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
-        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+        extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
 
         Bundle response = nullSafeCall(mContentResolver,
-                ContactKeys.GET_SELF_KEY_METHOD, extras);
+                E2eeContactKeys.GET_SELF_KEY_METHOD, extras);
 
         if (response == null) {
             return null;
         }
-        return response.getParcelable(ContactKeys.KEY_CONTACT_KEY, SelfKey.class);
+        return response.getParcelable(E2eeContactKeys.KEY_CONTACT_KEY, E2eeSelfKey.class);
     }
 
     /**
-     * Returns all self key entries that belong to apps visible to the caller.
+     * Returns all end-to-end encryption self key entries that belong to apps visible to the caller.
      * The keys will be stripped of deviceId, timeUpdated and keyValue data.
      *
-     * @return a list of {@link SelfKey} objects containing the self key information, or
-     * an empty list if no keys are found.
+     * @return a list of {@link E2eeSelfKey} objects containing the end-to-end encryption self key
+     * information, or an empty list if no self keys are found.
      */
     @RequiresPermission(android.Manifest.permission.READ_CONTACTS)
     @NonNull
-    public List<SelfKey> getAllSelfKeys() {
+    public List<E2eeSelfKey> getAllE2eeSelfKeys() {
         Bundle extras = new Bundle();
 
-        Bundle response = nullSafeCall(mContentResolver, ContactKeys.GET_ALL_SELF_KEYS_METHOD,
+        Bundle response = nullSafeCall(mContentResolver, E2eeContactKeys.GET_ALL_SELF_KEYS_METHOD,
                 extras);
 
         if (response == null) {
             return new ArrayList<>();
         }
-        List<SelfKey> value = response.getParcelableArrayList(ContactKeys.KEY_CONTACT_KEYS,
-                SelfKey.class);
+        List<E2eeSelfKey> value = response.getParcelableArrayList(E2eeContactKeys.KEY_CONTACT_KEYS,
+                E2eeSelfKey.class);
         if (value == null) {
             return new ArrayList<>();
         }
@@ -542,24 +552,24 @@
     }
 
     /**
-     * Returns all self key entries that are owned by the caller app.
+     * Returns all end-to-end encryption self key entries that are owned by the caller app.
      *
-     * @return a list of {@link SelfKey} objects containing the self key information, or
-     * an empty list if no keys are found.
+     * @return a list of {@link E2eeSelfKey} objects containing the end-to-end encryption self key
+     * information, or an empty list if no self keys are found.
      */
     @RequiresPermission(android.Manifest.permission.READ_CONTACTS)
     @NonNull
-    public List<SelfKey> getOwnerSelfKeys() {
+    public List<E2eeSelfKey> getOwnerE2eeSelfKeys() {
         Bundle extras = new Bundle();
 
-        Bundle response = nullSafeCall(mContentResolver, ContactKeys.GET_OWNER_SELF_KEYS_METHOD,
+        Bundle response = nullSafeCall(mContentResolver, E2eeContactKeys.GET_OWNER_SELF_KEYS_METHOD,
                 extras);
 
         if (response == null) {
             return new ArrayList<>();
         }
-        List<SelfKey> value = response.getParcelableArrayList(ContactKeys.KEY_CONTACT_KEYS,
-                SelfKey.class);
+        List<E2eeSelfKey> value = response.getParcelableArrayList(E2eeContactKeys.KEY_CONTACT_KEYS,
+                E2eeSelfKey.class);
         if (value == null) {
             return new ArrayList<>();
         }
@@ -567,24 +577,24 @@
     }
 
     /**
-     * Removes a self key entry given the deviceId and the inferred package name of the caller.
-
+     * Removes an end-to-end encryption self key entry given the deviceId and the inferred
+     * package name of the caller.
      * @param deviceId an app-specified identifier for the device
      * @param accountId an app-specified identifier for the account
      *
      * @return true if the entry was removed, false otherwise.
      */
     @RequiresPermission(android.Manifest.permission.WRITE_CONTACTS)
-    public boolean removeSelfKey(@NonNull String deviceId,
+    public boolean removeE2eeSelfKey(@NonNull String deviceId,
             @NonNull String accountId) {
         Bundle extras = new Bundle();
-        extras.putString(ContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
-        extras.putString(ContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
+        extras.putString(E2eeContactKeys.DEVICE_ID, Objects.requireNonNull(deviceId));
+        extras.putString(E2eeContactKeys.ACCOUNT_ID, Objects.requireNonNull(accountId));
 
         Bundle response = nullSafeCall(mContentResolver,
-                ContactKeys.REMOVE_SELF_KEY_METHOD, extras);
+                E2eeContactKeys.REMOVE_SELF_KEY_METHOD, extras);
 
-        return response != null && response.getBoolean(ContactKeys.KEY_UPDATED_ROWS);
+        return response != null && response.getBoolean(E2eeContactKeys.KEY_UPDATED_ROWS);
     }
 
     private Bundle nullSafeCall(@NonNull ContentResolver resolver, @NonNull String method,
@@ -622,9 +632,9 @@
     public static final int VERIFICATION_STATE_VERIFIED = 2;
 
     /** @hide */
-    public static final class ContactKeys {
+    public static final class E2eeContactKeys {
 
-        private ContactKeys() {}
+        private E2eeContactKeys() {}
 
         /**
          * <p>
@@ -636,14 +646,16 @@
 
         /**
          * <p>
-         * An app-specified identifier for the device for which the contact key can be used.
+         * An app-specified identifier for the device for which the end-to-end encryption
+         * contact key can be used.
          * </p>
          */
         public static final String DEVICE_ID = "device_id";
 
         /**
          * <p>
-         * An app-specified identifier for the account for which the contact key can be used.
+         * An app-specified identifier for the account for which the end-to-end encryption
+         * contact key can be used.
          * Usually a phone number.
          * </p>
          */
@@ -718,29 +730,32 @@
         public static final String GET_CONTACT_KEY_METHOD = "getContactKey";
 
         /**
-         * The method to invoke in order to retrieve all contact keys.
+         * The method to invoke in order to retrieve all end-to-end encryption contact keys.
          */
         public static final String GET_ALL_CONTACT_KEYS_METHOD = "getAllContactKeys";
 
         /**
-         * The method to invoke in order to retrieve contact keys that belong to the caller.
+         * The method to invoke in order to retrieve end-to-end encryption contact keys that belong
+         * to the caller.
          */
         public static final String GET_OWNER_CONTACT_KEYS_METHOD = "getOwnerContactKeys";
 
         /**
-         * The method to invoke in order to update a contact key local verification state.
+         * The method to invoke in order to update an end-to-end encryption contact key local
+         * verification state.
          */
         public static final String UPDATE_CONTACT_KEY_LOCAL_VERIFICATION_STATE_METHOD =
                 "updateContactKeyLocalVerificationState";
 
         /**
-         * The method to invoke in order to update a contact key remote verification state.
+         * The method to invoke in order to update an end-to-end encryption contact key remote
+         * verification state.
          */
         public static final String UPDATE_CONTACT_KEY_REMOTE_VERIFICATION_STATE_METHOD =
                 "updateContactKeyRemoteVerificationState";
 
         /**
-         * The method to invoke in order to remove a contact key.
+         * The method to invoke in order to remove a end-to-end encryption contact key.
          */
         public static final String REMOVE_CONTACT_KEY_METHOD = "removeContactKey";
 
@@ -776,12 +791,12 @@
         public static final String REMOVE_SELF_KEY_METHOD = "removeSelfKey";
 
         /**
-         * Key in the incoming Bundle for all the contact keys.
+         * Key in the incoming Bundle for all the end-to-end encryption contact keys.
          */
         public static final String KEY_CONTACT_KEYS = "key_contact_keys";
 
         /**
-         * Key in the incoming Bundle for a single contact key.
+         * Key in the incoming Bundle for a single end-to-end encryption contact key.
          */
         public static final String KEY_CONTACT_KEY = "key_contact_key";
 
@@ -790,18 +805,19 @@
          */
         public static final String KEY_UPDATED_ROWS = "key_updated_rows";
     }
-
     /**
      * A parcelable class encapsulating other users' end to end encrypted contact key.
      */
-    public static final class ContactKey implements Parcelable {
+    public static final class E2eeContactKey implements Parcelable {
         /**
-         * An app-specified identifier for the device for which the contact key can be used.
+         * An app-specified identifier for the device for which the end-to-end encryption
+         * contact key can be used.
          */
         private final String mDeviceId;
 
         /**
-         * An app-specified identifier for the account for which the contact key can be used.
+         * An app-specified identifier for the account for which the end-to-end encryption
+         * contact key can be used.
          * Usually a phone number.
          */
         private final String mAccountId;
@@ -851,7 +867,7 @@
         /**
          * @hide
          */
-        public ContactKey(@Nullable String deviceId, @NonNull String accountId,
+        public E2eeContactKey(@Nullable String deviceId, @NonNull String accountId,
                 @NonNull String ownerPackageName, long timeUpdated, @Nullable byte[] keyValue,
                 @VerificationState int localVerificationState,
                 @VerificationState int remoteVerificationState,
@@ -870,8 +886,10 @@
         }
 
         /**
-         * Gets the app-specified identifier for the device for which the contact key can be used.
-         * Returns null if the app doesn't have the required visibility into the contact key.
+         * Gets the app-specified identifier for the device for which the end-to-end encryption
+         * contact key can be used.
+         * Returns null if the app doesn't have the required visibility into
+         * the end-to-end encryption contact key.
          *
          * @return An app-specified identifier for the device.
          */
@@ -881,7 +899,8 @@
         }
 
         /**
-         * Gets the app-specified identifier for the account for which the contact key can be used.
+         * Gets the app-specified identifier for the account for which the end-to-end encryption
+         * contact key can be used.
          * Usually a phone number.
          *
          * @return An app-specified identifier for the account.
@@ -903,7 +922,7 @@
 
         /**
          * Gets the timestamp at which the key was updated. Returns -1 if the app doesn't have the
-         * required visibility into the contact key.
+         * required visibility into the end-to-end encryption contact key.
          *
          * @return The timestamp at which the key was updated in the System.currentTimeMillis()
          * base.
@@ -914,7 +933,8 @@
 
         /**
          * Gets the raw bytes for the key.
-         * Returns null if the app doesn't have the required visibility into the contact key.
+         * Returns null if the app doesn't have the required visibility into
+         * the end-to-end encryption contact key.
          *
          * @return A copy of the raw bytes for the key.
          */
@@ -984,7 +1004,7 @@
             if (obj == null) return false;
             if (obj == this) return true;
 
-            if (!(obj instanceof ContactKey toCompare)) {
+            if (!(obj instanceof E2eeContactKey toCompare)) {
                 return false;
             }
 
@@ -1023,10 +1043,10 @@
         }
 
         @NonNull
-        public static final Creator<ContactKey> CREATOR =
+        public static final Creator<E2eeContactKey> CREATOR =
                 new Creator<>() {
                     @Override
-                    public ContactKey createFromParcel(Parcel source) {
+                    public E2eeContactKey createFromParcel(Parcel source) {
                         String deviceId = source.readString8();
                         String accountId = source.readString8();
                         String ownerPackageName = source.readString8();
@@ -1044,14 +1064,14 @@
                         String displayName = source.readString8();
                         String number = source.readString8();
                         String address = source.readString8();
-                        return new ContactKey(deviceId, accountId, ownerPackageName,
+                        return new E2eeContactKey(deviceId, accountId, ownerPackageName,
                                 timeUpdated, keyValue, localVerificationState,
                                 remoteVerificationState, displayName, number, address);
                     }
 
                     @Override
-                    public ContactKey[] newArray(int size) {
-                        return new ContactKey[size];
+                    public E2eeContactKey[] newArray(int size) {
+                        return new E2eeContactKey[size];
                     }
                 };
     }
@@ -1059,14 +1079,16 @@
     /**
      * A parcelable class encapsulating self end to end encrypted contact key.
      */
-    public static final class SelfKey implements Parcelable {
+    public static final class E2eeSelfKey implements Parcelable {
         /**
-         * An app-specified identifier for the device for which the contact key can be used.
+         * An app-specified identifier for the device for which the end-to-end encryption
+         * contact key can be used.
          */
         private final String mDeviceId;
 
         /**
-         * An app-specified identifier for the account for which the contact key can be used.
+         * An app-specified identifier for the account for which the end-to-end encryption
+         * contact key can be used.
          * Usually a phone number.
          */
         private final String mAccountId;
@@ -1096,7 +1118,7 @@
         /**
          * @hide
          */
-        public SelfKey(@Nullable String deviceId, @NonNull String accountId,
+        public E2eeSelfKey(@Nullable String deviceId, @NonNull String accountId,
                 @NonNull String ownerPackageName, long timeUpdated, @Nullable byte[] keyValue,
                 @VerificationState int remoteVerificationState) {
             this.mDeviceId = deviceId;
@@ -1108,8 +1130,10 @@
         }
 
         /**
-         * Gets the app-specified identifier for the device for which the contact key can be used.
-         * Returns null if the app doesn't have the required visibility into the contact key.
+         * Gets the app-specified identifier for the device for which the end-to-end encryption
+         * contact key can be used.
+         * Returns null if the app doesn't have the required visibility into
+         * the end-to-end encryption contact key.
          *
          * @return An app-specified identifier for the device.
          */
@@ -1119,7 +1143,8 @@
         }
 
         /**
-         * Gets the app-specified identifier for the account for which the contact key can be used.
+         * Gets the app-specified identifier for the account for which the end-to-end encryption
+         * contact key can be used.
          * Usually a phone number.
          *
          * @return An app-specified identifier for the device.
@@ -1141,7 +1166,7 @@
 
         /**
          * Gets the timestamp at which the key was updated. Returns -1 if the app doesn't have the
-         * required visibility into the contact key.
+         * required visibility into the end-to-end encryption contact key.
          *
          * @return The timestamp at which the key was updated in the System.currentTimeMillis()
          * base.
@@ -1152,7 +1177,8 @@
 
         /**
          * Gets the raw bytes for the key.
-         * Returns null if the app doesn't have the required visibility into the contact key.
+         * Returns null if the app doesn't have the required visibility into
+         * the end-to-end encryption contact key.
          *
          * @return A copy of the raw bytes for the key.
          */
@@ -1182,7 +1208,7 @@
             if (obj == null) return false;
             if (obj == this) return true;
 
-            if (!(obj instanceof SelfKey toCompare)) {
+            if (!(obj instanceof E2eeSelfKey toCompare)) {
                 return false;
             }
 
@@ -1213,10 +1239,10 @@
         }
 
         @NonNull
-        public static final Creator<SelfKey> CREATOR =
+        public static final Creator<E2eeSelfKey> CREATOR =
                 new Creator<>() {
                     @Override
-                    public SelfKey createFromParcel(Parcel source) {
+                    public E2eeSelfKey createFromParcel(Parcel source) {
                         String deviceId = source.readString8();
                         String accountId = source.readString8();
                         String ownerPackageName = source.readString8();
@@ -1230,13 +1256,13 @@
                             keyValue = null;
                         }
                         int remoteVerificationState = source.readInt();
-                        return new SelfKey(deviceId, accountId, ownerPackageName,
+                        return new E2eeSelfKey(deviceId, accountId, ownerPackageName,
                                 timeUpdated, keyValue, remoteVerificationState);
                     }
 
                     @Override
-                    public SelfKey[] newArray(int size) {
-                        return new SelfKey[size];
+                    public E2eeSelfKey[] newArray(int size) {
+                        return new E2eeSelfKey[size];
                     }
                 };
     }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 50adc40..20b4857 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11969,6 +11969,16 @@
                 "accessibility_pinch_to_zoom_anywhere_enabled";
 
         /**
+         * For magnification feature where panning can be controlled with a single finger.
+         *
+         * If true, you can pan using a single finger gesture.
+         *
+         * @hide
+         */
+        public static final String ACCESSIBILITY_SINGLE_FINGER_PANNING_ENABLED =
+                "accessibility_single_finger_panning_enabled";
+
+        /**
          * Controls magnification capability. Accessibility magnification is capable of at least one
          * of the magnification modes.
          *
diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig
index 7631454..5e7edda 100644
--- a/core/java/android/security/flags.aconfig
+++ b/core/java/android/security/flags.aconfig
@@ -31,6 +31,13 @@
 }
 
 flag {
+    name: "keyinfo_unlocked_device_required"
+    namespace: "hardware_backed_security"
+    description: "Add the API android.security.keystore.KeyInfo#isUnlockedDeviceRequired()"
+    bug: "296475382"
+}
+
+flag {
     name: "deprecate_fsv_sig"
     namespace: "hardware_backed_security"
     description: "Feature flag for deprecating .fsv_sig"
diff --git a/core/java/android/service/chooser/flags.aconfig b/core/java/android/service/chooser/flags.aconfig
index 00236df..d72441f 100644
--- a/core/java/android/service/chooser/flags.aconfig
+++ b/core/java/android/service/chooser/flags.aconfig
@@ -27,3 +27,14 @@
   description: "Provides additional callbacks with information about user actions in ChooserResult"
   bug: "263474465"
 }
+
+flag {
+  name: "legacy_chooser_pinning_removal"
+  namespace: "intentresolver"
+  description: "Removing pinning functionality from the legacy chooser (used by partial screenshare)"
+  bug: "301068735"
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
+
diff --git a/core/java/android/tracing/perfetto/DataSource.java b/core/java/android/tracing/perfetto/DataSource.java
index 4e08aee..d0c719b 100644
--- a/core/java/android/tracing/perfetto/DataSource.java
+++ b/core/java/android/tracing/perfetto/DataSource.java
@@ -18,6 +18,8 @@
 
 import android.util.proto.ProtoInputStream;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 /**
  * Templated base class meant to be derived by embedders to create a custom data
  * source.
@@ -87,7 +89,8 @@
      *
      * NOTE: Should only be called from native side.
      */
-    protected TlsStateType createTlsState(CreateTlsStateArgs<DataSourceInstanceType> args) {
+    @VisibleForTesting
+    public TlsStateType createTlsState(CreateTlsStateArgs<DataSourceInstanceType> args) {
         return null;
     }
 
diff --git a/core/java/android/tracing/perfetto/DataSourceInstance.java b/core/java/android/tracing/perfetto/DataSourceInstance.java
index 3710b4d..904cf55 100644
--- a/core/java/android/tracing/perfetto/DataSourceInstance.java
+++ b/core/java/android/tracing/perfetto/DataSourceInstance.java
@@ -16,6 +16,8 @@
 
 package android.tracing.perfetto;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 /**
  * @hide
  */
@@ -66,7 +68,8 @@
      * Only required to be called when instance was retrieved with
      * `DataSource#getDataSourceInstanceLocked`.
      */
-    public final void release() {
+    @VisibleForTesting
+    public void release() {
         mDataSource.releaseDataSourceInstance(mInstanceIndex);
     }
 
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index b33214d..8358b9a 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -72,8 +72,11 @@
  * a positive value may be considered as a successful invocation.
  */
 @android.ravenwood.annotation.RavenwoodKeepWholeClass
-@android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
-        "com.android.platform.test.ravenwood.nativesubstitution.Log_host")
+@android.ravenwood.annotation.RavenwoodClassLoadHook(
+        "com.android.platform.test.ravenwood.runtimehelper.ClassLoadHook.onClassLoaded")
+// Uncomment the following annotation to switch to the Java substitution version.
+//@android.ravenwood.annotation.RavenwoodNativeSubstitutionClass(
+//        "com.android.platform.test.ravenwood.nativesubstitution.Log_host")
 public final class Log {
     /** @hide */
     @IntDef({ASSERT, ERROR, WARN, INFO, DEBUG, VERBOSE})
diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS
index ad326e4..a2f767d 100644
--- a/core/java/android/view/OWNERS
+++ b/core/java/android/view/OWNERS
@@ -102,6 +102,7 @@
 per-file IWindow*.aidl = file:/services/core/java/com/android/server/wm/OWNERS
 per-file RemoteAnimation*.java = file:/services/core/java/com/android/server/wm/OWNERS
 per-file RemoteAnimation*.aidl = file:/services/core/java/com/android/server/wm/OWNERS
+per-file ScreenRecordingCallbacks.java = file:/services/core/java/com/android/server/wm/OWNERS
 per-file *SurfaceControl*.java = file:/services/core/java/com/android/server/wm/OWNERS
 per-file SurfaceControl*.aidl = file:/services/core/java/com/android/server/wm/OWNERS
 per-file SurfaceSession.java = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index 13b9c45..f5f4fd9 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -480,11 +480,19 @@
                 mBitmapFrames = new Bitmap[frames - 1];
                 final int width = drawable.getIntrinsicWidth();
                 final int height = drawable.getIntrinsicHeight();
+                final boolean isVectorAnimation = drawable instanceof VectorDrawable;
+                mDrawNativeDropShadow = isVectorAnimation;
                 for (int i = 1; i < frames; ++i) {
                     Drawable drawableFrame = animationDrawable.getFrame(i);
-                    if (!(drawableFrame instanceof BitmapDrawable)) {
+                    if (!(drawableFrame instanceof BitmapDrawable)
+                            && !(drawableFrame instanceof VectorDrawable)) {
                         throw new IllegalArgumentException("Frame of an animated pointer icon "
-                                + "must refer to a bitmap drawable.");
+                                + "must refer to a bitmap drawable or vector drawable.");
+                    }
+                    if (isVectorAnimation != (drawableFrame instanceof VectorDrawable)) {
+                        throw new IllegalArgumentException("The drawable of the " + i + "-th frame "
+                                + "is a different type from the others. All frames should be the "
+                                + "same type.");
                     }
                     if (drawableFrame.getIntrinsicWidth() != width ||
                         drawableFrame.getIntrinsicHeight() != height) {
@@ -492,8 +500,11 @@
                                 + "is different. All frames should have the exact same size and "
                                 + "share the same hotspot.");
                     }
-                    BitmapDrawable bitmapDrawableFrame = (BitmapDrawable) drawableFrame;
-                    mBitmapFrames[i - 1] = getBitmapFromDrawable(bitmapDrawableFrame);
+                    if (isVectorAnimation) {
+                        drawableFrame = getBitmapDrawableFromVectorDrawable(resources,
+                                (VectorDrawable) drawableFrame);
+                    }
+                    mBitmapFrames[i - 1] = getBitmapFromDrawable((BitmapDrawable) drawableFrame);
                 }
             }
         }
diff --git a/core/java/android/view/RoundedCorners.java b/core/java/android/view/RoundedCorners.java
index f68cc69..1f841bf 100644
--- a/core/java/android/view/RoundedCorners.java
+++ b/core/java/android/view/RoundedCorners.java
@@ -198,6 +198,12 @@
             radius = res.getDimensionPixelSize(R.dimen.rounded_corner_radius);
         }
         array.recycle();
+        // For devices with round displays (e.g. watches) that don't otherwise provide the rounded
+        // corner radius via resource overlays, we can infer the corner radius directly from the
+        // display size.
+        if (radius == 0 && res.getConfiguration().isScreenRound()) {
+            radius = res.getDisplayMetrics().widthPixels / 2;
+        }
         return radius;
     }
 
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 896b3f4..124aece 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -16,6 +16,8 @@
 
 package android.view;
 
+import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -883,6 +885,17 @@
         mListener = listener;
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    protected int calculateFrameRateCategory(float sizePercentage) {
+        if (mMinusTwoFrameIntervalMillis > 15 && mMinusOneFrameIntervalMillis > 15) {
+            return FRAME_RATE_CATEGORY_NORMAL;
+        }
+        return super.calculateFrameRateCategory(sizePercentage);
+    }
+
     @UnsupportedAppUsage
     private final SurfaceTexture.OnFrameAvailableListener mUpdateListener =
             surfaceTexture -> {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 383d631..042af1f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -36,6 +36,7 @@
 import static android.view.flags.Flags.FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY;
 import static android.view.flags.Flags.FLAG_VIEW_VELOCITY_API;
 import static android.view.flags.Flags.enableUseMeasureCacheDuringForceLayout;
+import static android.view.flags.Flags.sensitiveContentAppProtection;
 import static android.view.flags.Flags.toolkitMetricsForFrameRateDecision;
 import static android.view.flags.Flags.toolkitSetFrameRateReadOnly;
 import static android.view.flags.Flags.viewVelocityApi;
@@ -135,6 +136,7 @@
 import android.sysprop.DisplayProperties;
 import android.text.InputType;
 import android.text.TextUtils;
+import android.util.ArraySet;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.FloatProperty;
@@ -3701,6 +3703,7 @@
      *          1                       PFLAG4_ROTARY_HAPTICS_SCROLL_SINCE_LAST_ROTARY_INPUT
      *         1                        PFLAG4_ROTARY_HAPTICS_WAITING_FOR_SCROLL_EVENT
      *       11                         PFLAG4_CONTENT_SENSITIVITY_MASK
+     *      1                           PFLAG4_IS_COUNTED_AS_SENSITIVE
      * |-------|-------|-------|-------|
      */
 
@@ -3826,6 +3829,13 @@
     private static final int PFLAG4_CONTENT_SENSITIVITY_MASK =
             (CONTENT_SENSITIVITY_AUTO | CONTENT_SENSITIVITY_SENSITIVE
                     | CONTENT_SENSITIVITY_NOT_SENSITIVE) << PFLAG4_CONTENT_SENSITIVITY_SHIFT;
+
+    /**
+     * Whether this view has been counted as a sensitive view or not.
+     *
+     * @see AttachInfo#mSensitiveViewsCount
+     */
+    private static final int PFLAG4_IS_COUNTED_AS_SENSITIVE = 0x4000000;
     /* End of masks for mPrivateFlags4 */
 
     /** @hide */
@@ -5639,9 +5649,15 @@
 
     private int mInfrequentUpdateCount = 0;
     private long mLastUpdateTimeMillis = 0;
-    private long mMinusOneFrameIntervalMillis = 0;
-    private long mMinusTwoFrameIntervalMillis = 0;
-    private int mLastFrameRateCategory = FRAME_RATE_CATEGORY_HIGH;
+    /**
+     * @hide
+     */
+    protected long mMinusOneFrameIntervalMillis = 0;
+    /**
+     * @hide
+     */
+    protected long mMinusTwoFrameIntervalMillis = 0;
+    private int mLastFrameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE;
 
     @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
     public static final float REQUESTED_FRAME_RATE_CATEGORY_DEFAULT = Float.NaN;
@@ -9942,6 +9958,17 @@
     }
 
     /**
+     * @hide
+     */
+    public void onGetCredentialException(String errorType, String errorMsg) {
+        if (getCredentialManagerCallback() == null) {
+            Log.w(AUTOFILL_LOG_TAG, "onGetCredentialException called but no callback found");
+            return;
+        }
+        getCredentialManagerCallback().onError(new GetCredentialException(errorType, errorMsg));
+    }
+
+    /**
      * Gets the unique, logical identifier of this view in the activity, for autofill purposes.
      *
      * <p>The autofill id is created on demand, unless it is explicitly set by
@@ -10387,6 +10414,9 @@
         mPrivateFlags4 &= ~PFLAG4_CONTENT_SENSITIVITY_MASK;
         mPrivateFlags4 |= ((mode << PFLAG4_CONTENT_SENSITIVITY_SHIFT)
                 & PFLAG4_CONTENT_SENSITIVITY_MASK);
+        if (sensitiveContentAppProtection()) {
+            updateSensitiveViewsCountIfNeeded(isAggregatedVisible());
+        }
     }
 
     /**
@@ -10418,13 +10448,44 @@
      */
     @FlaggedApi(FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API)
     public final boolean isContentSensitive() {
-        if (getContentSensitivity() == CONTENT_SENSITIVITY_SENSITIVE) {
+        final int contentSensitivity = getContentSensitivity();
+        if (contentSensitivity == CONTENT_SENSITIVITY_SENSITIVE) {
             return true;
+        } else if (contentSensitivity == CONTENT_SENSITIVITY_NOT_SENSITIVE) {
+            return false;
+        } else if (sensitiveContentAppProtection()) {
+            return SensitiveAutofillHintsHelper
+                    .containsSensitiveAutofillHint(getAutofillHints());
         }
         return false;
     }
 
     /**
+     * Helper used to track sensitive views when they are added or removed from the window
+     * based on whether it's laid out and visible.
+     *
+     * <p>This method is called from many places (visibility changed, view laid out, view attached
+     * or detached to/from window, etc...)
+     */
+    private void updateSensitiveViewsCountIfNeeded(boolean appeared) {
+        if (!sensitiveContentAppProtection() || mAttachInfo == null) {
+            return;
+        }
+
+        if (appeared && isContentSensitive()) {
+            if ((mPrivateFlags4 & PFLAG4_IS_COUNTED_AS_SENSITIVE) == 0) {
+                mPrivateFlags4 |= PFLAG4_IS_COUNTED_AS_SENSITIVE;
+                mAttachInfo.increaseSensitiveViewsCount();
+            }
+        } else {
+            if ((mPrivateFlags4 & PFLAG4_IS_COUNTED_AS_SENSITIVE) != 0) {
+                mPrivateFlags4 &= ~PFLAG4_IS_COUNTED_AS_SENSITIVE;
+                mAttachInfo.decreaseSensitiveViewsCount();
+            }
+        }
+    }
+
+    /**
      * Gets the mode for determining whether this view is important for content capture.
      *
      * <p>See {@link #setImportantForContentCapture(int)} and
@@ -10893,8 +10954,11 @@
             structure.setAutofillId(new AutofillId(getAutofillId(),
                     AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId())));
         }
-        structure.setCredentialManagerRequest(getCredentialManagerRequest(),
-                getCredentialManagerCallback());
+        if (getViewCredentialHandler() != null) {
+            structure.setCredentialManagerRequest(
+                    getViewCredentialHandler().getRequest(),
+                    getViewCredentialHandler().getCallback());
+        }
         CharSequence cname = info.getClassName();
         structure.setClassName(cname != null ? cname.toString() : null);
         structure.setContentDescription(info.getContentDescription());
@@ -13454,6 +13518,11 @@
         } else {
             mAutofillHints = autofillHints;
         }
+        if (sensitiveContentAppProtection()) {
+            if (getContentSensitivity() == CONTENT_SENSITIVITY_AUTO) {
+                updateSensitiveViewsCountIfNeeded(isAggregatedVisible());
+            }
+        }
     }
 
     /**
@@ -15245,6 +15314,7 @@
      * {@link #isLongClickable()}, {@link #isContextClickable()},
      * {@link #isScreenReaderFocusable()}, or {@link #isFocusable()}
      * <li>Has an {@link AccessibilityDelegate}
+     * <li>Has an {@link AccessibilityNodeProvider}
      * <li>Has an interaction listener, e.g. {@link OnTouchListener},
      * {@link OnKeyListener}, etc.
      * <li>Is an accessibility live region, e.g.
@@ -15277,7 +15347,8 @@
         }
 
         return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility()
-                || hasListenersForAccessibility() || mAccessibilityDelegate != null
+                || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null
+                || getAccessibilityDelegate() != null
                 || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE
                 || isAccessibilityPane() || isAccessibilityHeading();
     }
@@ -16678,6 +16749,7 @@
             }
 
             notifyAppearedOrDisappearedForContentCaptureIfNeeded(isVisible);
+            updateSensitiveViewsCountIfNeeded(isVisible);
 
             if (!getSystemGestureExclusionRects().isEmpty()) {
                 postUpdate(this::updateSystemGestureExclusionRects);
@@ -22667,6 +22739,7 @@
         }
 
         notifyAppearedOrDisappearedForContentCaptureIfNeeded(false);
+        updateSensitiveViewsCountIfNeeded(false);
 
         mAttachInfo = null;
         if (mOverlay != null) {
@@ -31814,6 +31887,11 @@
         ScrollCaptureInternal mScrollCaptureInternal;
 
         /**
+         * sensitive views attached to the window
+         */
+        int mSensitiveViewsCount;
+
+        /**
          * Creates a new set of attachment information with the specified
          * events handler and thread.
          *
@@ -31832,6 +31910,24 @@
             mTreeObserver = new ViewTreeObserver(context);
         }
 
+        void increaseSensitiveViewsCount() {
+            if (mSensitiveViewsCount == 0) {
+                mViewRootImpl.notifySensitiveContentAppProtection(true);
+            }
+            mSensitiveViewsCount++;
+        }
+
+        void decreaseSensitiveViewsCount() {
+            mSensitiveViewsCount--;
+            if (mSensitiveViewsCount == 0) {
+                mViewRootImpl.notifySensitiveContentAppProtection(false);
+            }
+            if (mSensitiveViewsCount < 0) {
+                Log.wtf(VIEW_LOG_TAG, "mSensitiveViewsCount is negative" + mSensitiveViewsCount);
+                mSensitiveViewsCount = 0;
+            }
+        }
+
         @Nullable
         ContentCaptureManager getContentCaptureManager(@NonNull Context context) {
             if (mContentCaptureManager != null) {
@@ -32445,6 +32541,36 @@
         }
     }
 
+    private static class SensitiveAutofillHintsHelper {
+        /**
+         * List of autofill hints deemed sensitive for screen protection during screen share.
+         */
+        private static final ArraySet<String> SENSITIVE_CONTENT_AUTOFILL_HINTS = new ArraySet<>();
+        static {
+            SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_USERNAME);
+            SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_PASSWORD_AUTO);
+            SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_PASSWORD);
+        }
+
+        /**
+         * Whether View's autofill hints contains a sensitive autofill hint.
+         *
+         * @see #SENSITIVE_CONTENT_AUTOFILL_HINTS
+         */
+        static boolean containsSensitiveAutofillHint(@Nullable String[] autofillHints) {
+            if (autofillHints == null) {
+                return false;
+            }
+
+            int size = autofillHints.length;
+            for (int i = 0; i < size; i++) {
+                if (SENSITIVE_CONTENT_AUTOFILL_HINTS.contains(autofillHints[i])) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
 
     /**
      * Returns the current scroll capture hint for this view.
@@ -33505,7 +33631,12 @@
         return (float) viewSize / screenSize;
     }
 
-    private int calculateFrameRateCategory(float sizePercentage) {
+    /**
+     * Used to calculate the frame rate category of a View.
+     *
+     * @hide
+     */
+    protected int calculateFrameRateCategory(float sizePercentage) {
         if (mMinusTwoFrameIntervalMillis + mMinusOneFrameIntervalMillis
                 < INFREQUENT_UPDATE_INTERVAL_MILLIS) {
             if (sizePercentage <= FRAME_RATE_SIZE_PERCENTAGE_THRESHOLD) {
@@ -33639,7 +33770,10 @@
         mMinusTwoFrameIntervalMillis = mMinusOneFrameIntervalMillis;
         mMinusOneFrameIntervalMillis = timeIntervalMillis;
 
-        mLastUpdateTimeMillis = currentTimeMillis;
+        if (mMinusOneFrameIntervalMillis - mMinusTwoFrameIntervalMillis >= 30
+                && timeIntervalMillis < 2) {
+            return;
+        }
         if (timeIntervalMillis >= INFREQUENT_UPDATE_INTERVAL_MILLIS) {
             mInfrequentUpdateCount = mInfrequentUpdateCount == INFREQUENT_UPDATE_COUNTS
                         ? mInfrequentUpdateCount : mInfrequentUpdateCount + 1;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 94260b2..333cbb3 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -58,6 +58,7 @@
 import static android.view.ViewRootImplProto.WINDOW_ATTRIBUTES;
 import static android.view.ViewRootImplProto.WIN_FRAME;
 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
+import static android.view.flags.Flags.sensitiveContentAppProtection;
 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
 import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
@@ -94,12 +95,14 @@
 import static android.view.accessibility.Flags.fixMergedContentChangeEvent;
 import static android.view.accessibility.Flags.forceInvertColor;
 import static android.view.accessibility.Flags.reduceWindowContentChangedEventThrottle;
+import static android.view.flags.Flags.toolkitFrameRateTypingReadOnly;
 import static android.view.flags.Flags.toolkitMetricsForFrameRateDecision;
 import static android.view.flags.Flags.toolkitSetFrameRateReadOnly;
 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.IME_FOCUS_CONTROLLER;
 import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodClientsTraceProto.ClientSideProto.INSETS_CONTROLLER;
 
 import static com.android.input.flags.Flags.enablePointerChoreographer;
+import static com.android.window.flags.Flags.enableBufferTransformHintFromDisplay;
 
 import android.Manifest;
 import android.accessibilityservice.AccessibilityService;
@@ -166,6 +169,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.Trace;
@@ -924,6 +928,8 @@
 
     private IAccessibilityEmbeddedConnection mAccessibilityEmbeddedConnection;
 
+    private final ISensitiveContentProtectionManager mSensitiveContentProtectionService;
+
     static final class SystemUiVisibilityInfo {
         int globalVisibility;
         int localValue;
@@ -993,8 +999,6 @@
      */
     private final boolean mViewBoundsSandboxingEnabled;
 
-    private int mLastTransformHint = Integer.MIN_VALUE;
-
     private AccessibilityWindowAttributes mAccessibilityWindowAttributes;
 
     /*
@@ -1040,7 +1044,7 @@
     // time for checking idle status periodically.
     private static final int FRAME_RATE_IDLENESS_CHECK_TIME_MILLIS = 500;
     // time for revaluating the idle status before lowering the frame rate.
-    private static final int FRAME_RATE_IDLENESS_REEVALUATE_TIME = 500;
+    private static final int FRAME_RATE_IDLENESS_REEVALUATE_TIME = 1000;
     // time for evaluating the interval between current time and
     // the time when frame rate was set previously.
     private static final int FRAME_RATE_SETTING_REEVALUATE_TIME = 100;
@@ -1058,9 +1062,6 @@
      * the variables below are used to determine whther a dVRR feature should be enabled
      */
 
-    // Used to determine whether to suppress boost on typing
-    private boolean mShouldSuppressBoostOnTyping = false;
-
     /**
      * A temporary object used so relayoutWindow can return the latest SyncSeqId
      * system. The SyncSeqId system was designed to work without synchronous relayout
@@ -1114,10 +1115,12 @@
 
     private static boolean sToolkitSetFrameRateReadOnlyFlagValue;
     private static boolean sToolkitMetricsForFrameRateDecisionFlagValue;
+    private static boolean sToolkitFrameRateTypingReadOnlyFlagValue;
 
     static {
         sToolkitSetFrameRateReadOnlyFlagValue = toolkitSetFrameRateReadOnly();
         sToolkitMetricsForFrameRateDecisionFlagValue = toolkitMetricsForFrameRateDecision();
+        sToolkitFrameRateTypingReadOnlyFlagValue = toolkitFrameRateTypingReadOnly();
     }
 
     // The latest input event from the gesture that was used to resolve the pointer icon.
@@ -1203,6 +1206,13 @@
 
         mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS;
         mOnBackInvokedDispatcher = new WindowOnBackInvokedDispatcher(context);
+        if (sensitiveContentAppProtection()) {
+            mSensitiveContentProtectionService =
+                    ISensitiveContentProtectionManager.Stub.asInterface(
+                        ServiceManager.getService(Context.SENSITIVE_CONTENT_PROTECTION_SERVICE));
+        } else {
+            mSensitiveContentProtectionService = null;
+        }
     }
 
     public static void addFirstDrawHandler(Runnable callback) {
@@ -4154,6 +4164,29 @@
         mWmsRequestSyncGroup.add(this, null /* runnable */);
     }
 
+    /**
+     * Helper used to notify the service to block projection when a sensitive
+     * view (the view displays sensitive content) is attached to the window.
+     * The window manager service is also notified to unblock projection when
+     * no attached view (to the window) displays sensitive content.
+     *
+     * <ol>
+     *   <li>It should only notify service to block projection when first sensitive view is
+     *   attached to the window.
+     *   <li>It should only notify service to unblock projection when all sensitive view are
+     *   removed from the window.
+     * </ol>
+     */
+    void notifySensitiveContentAppProtection(boolean showSensitiveContent) {
+        try {
+            // The window would be blocked during screen share if it shows sensitive content.
+            mSensitiveContentProtectionService.setSensitiveContentProtection(
+                    getWindowToken(), mContext.getPackageName(), showSensitiveContent);
+        } catch (RemoteException ex) {
+            Log.e(TAG, "Unable to protect sensitive content during screen share", ex);
+        }
+    }
+
     private void notifyContentCaptureEvents() {
         if (!isContentCaptureEnabled()) {
             if (DEBUG_CONTENT_CAPTURE) {
@@ -6507,6 +6540,7 @@
                         mHasInvalidation = false;
                         mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE,
                                 FRAME_RATE_IDLENESS_REEVALUATE_TIME);
+                        mHasIdledMessage = true;
                     }
                     break;
                 case MSG_REFRESH_POINTER_ICON:
@@ -8884,11 +8918,13 @@
 
         final int transformHint = SurfaceControl.rotationToBufferTransform(
                 (mDisplay.getInstallOrientation() + mDisplay.getRotation()) % 4);
+        final boolean transformHintChanged = transformHint != mPreviousTransformHint;
+        mPreviousTransformHint = transformHint;
+        mSurfaceControl.setTransformHint(transformHint);
 
         WindowLayout.computeSurfaceSize(mWindowAttributes, winConfig.getMaxBounds(), requestedWidth,
                 requestedHeight, mWinFrameInScreen, mPendingDragResizing, mSurfaceSize);
 
-        final boolean transformHintChanged = transformHint != mLastTransformHint;
         final boolean sizeChanged = !mLastSurfaceSize.equals(mSurfaceSize);
         final boolean surfaceControlChanged =
                 (relayoutResult & RELAYOUT_RES_SURFACE_CHANGED) == RELAYOUT_RES_SURFACE_CHANGED;
@@ -8917,10 +8953,6 @@
             }
         }
 
-        mLastTransformHint = transformHint;
-
-        mSurfaceControl.setTransformHint(transformHint);
-
         if (mAttachInfo.mContentCaptureManager != null) {
             ContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager
                     .getMainContentCaptureSession();
@@ -8934,8 +8966,7 @@
                 mAttachInfo.mThreadedRenderer.setSurfaceControl(mSurfaceControl, mBlastBufferQueue);
             }
             mHdrRenderState.forceUpdateHdrSdrRatio();
-            if (mPreviousTransformHint != transformHint) {
-                mPreviousTransformHint = transformHint;
+            if (transformHintChanged) {
                 dispatchTransformHintChanged(transformHint);
             }
         } else {
@@ -11899,6 +11930,14 @@
 
     @Override
     public @SurfaceControl.BufferTransform int getBufferTransformHint() {
+        // TODO(b/326482114) We use mPreviousTransformHint (calculated using mDisplay's rotation)
+        // instead of mSurfaceControl#getTransformHint because there's a race where SurfaceFlinger
+        // can set an incorrect transform hint for a few frames before it is aware of the updated
+        // display rotation.
+        if (enableBufferTransformHintFromDisplay()) {
+            return mPreviousTransformHint;
+        }
+
         if (mSurfaceControl.isValid()) {
             return mSurfaceControl.getTransformHint();
         } else {
@@ -12330,14 +12369,6 @@
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
         }
-
-        if (mPreferredFrameRateCategory != FRAME_RATE_CATEGORY_NO_PREFERENCE && !mHasIdledMessage) {
-            // Check where the display is idled periodically.
-            // If so, set the frame rate category to NO_PREFERENCE
-            mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE,
-                    FRAME_RATE_IDLENESS_CHECK_TIME_MILLIS);
-            mHasIdledMessage = true;
-        }
     }
 
     private void setPreferredFrameRate(float preferredFrameRate) {
@@ -12351,7 +12382,8 @@
                 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
                     Trace.traceBegin(
                             Trace.TRACE_TAG_VIEW, "ViewRootImpl#setFrameRate "
-                                + preferredFrameRate);
+                                + preferredFrameRate + " compatibility "
+                                + mFrameRateCompatibility);
                 }
                 mFrameRateTransaction.setFrameRate(mSurfaceControl, preferredFrameRate,
                     mFrameRateCompatibility).applyAsyncUnsafe();
@@ -12377,7 +12409,7 @@
 
     private boolean shouldSetFrameRate() {
         // use toolkitSetFrameRate flag to gate the change
-        return mSurface.isValid() && mPreferredFrameRate > 0
+        return mSurface.isValid() && mPreferredFrameRate >= 0
                 && shouldEnableDvrr() && !mIsFrameRateConflicted;
     }
 
@@ -12385,7 +12417,8 @@
         boolean desiredAction = motionEventAction == MotionEvent.ACTION_DOWN
                 || motionEventAction == MotionEvent.ACTION_MOVE
                 || motionEventAction == MotionEvent.ACTION_UP;
-        boolean undesiredType = windowType == TYPE_INPUT_METHOD && mShouldSuppressBoostOnTyping;
+        boolean undesiredType = windowType == TYPE_INPUT_METHOD
+                && sToolkitFrameRateTypingReadOnlyFlagValue;
         // use toolkitSetFrameRate flag to gate the change
         return desiredAction && !undesiredType && shouldEnableDvrr()
                 && getFrameRateBoostOnTouchEnabled();
@@ -12418,6 +12451,7 @@
             mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_LOW;
         }
         mHasInvalidation = true;
+        checkIdleness();
     }
 
     /**
@@ -12460,6 +12494,7 @@
             mHandler.sendEmptyMessageDelayed(MSG_FRAME_RATE_SETTING,
                     FRAME_RATE_SETTING_REEVALUATE_TIME);
         }
+        checkIdleness();
     }
 
     /**
@@ -12565,4 +12600,14 @@
     private boolean shouldEnableDvrr() {
         return sToolkitSetFrameRateReadOnlyFlagValue && mIsFrameRatePowerSavingsBalanced;
     }
+
+    private void checkIdleness() {
+        if (!mHasIdledMessage) {
+            // Check where the display is idled periodically.
+            // If so, set the frame rate category to NO_PREFERENCE
+            mHandler.sendEmptyMessageDelayed(MSG_CHECK_INVALIDATION_IDLE,
+                    FRAME_RATE_IDLENESS_CHECK_TIME_MILLIS);
+            mHasIdledMessage = true;
+        }
+    }
 }
diff --git a/core/java/android/view/accessibility/IMagnificationConnection.aidl b/core/java/android/view/accessibility/IMagnificationConnection.aidl
index aae51ab..450cf755 100644
--- a/core/java/android/view/accessibility/IMagnificationConnection.aidl
+++ b/core/java/android/view/accessibility/IMagnificationConnection.aidl
@@ -124,4 +124,9 @@
      * @param scale magnification scale.
      */
     void onUserMagnificationScaleChanged(int userId, int displayId, float scale);
+
+    /**
+     * Notify the changes of fullscreen magnification activation on the specified display
+     */
+    void onFullscreenMagnificationActivationChanged(int displayId, boolean activated);
 }
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 364c94f..64e5a5b 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -50,6 +50,7 @@
 import android.content.IntentSender;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.credentials.GetCredentialException;
 import android.credentials.GetCredentialResponse;
 import android.graphics.Rect;
 import android.metrics.LogMaker;
@@ -105,6 +106,7 @@
 
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.io.Serializable;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
@@ -2400,6 +2402,13 @@
 
             final Bundle responseData = new Bundle();
             responseData.putParcelable(EXTRA_AUTHENTICATION_RESULT, result);
+            Serializable exception = data.getSerializableExtra(
+                    CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION,
+                    GetCredentialException.class);
+            if (exception != null && Flags.autofillCredmanIntegration()) {
+                responseData.putSerializable(
+                        CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION, exception);
+            }
             final Bundle newClientState = data.getBundleExtra(EXTRA_CLIENT_STATE);
             if (newClientState != null) {
                 responseData.putBundle(EXTRA_CLIENT_STATE, newClientState);
@@ -2926,6 +2935,48 @@
         }
     }
 
+    private void onGetCredentialException(int sessionId, AutofillId id, String errorType,
+            String errorMsg) {
+        synchronized (mLock) {
+            if (sessionId != mSessionId) {
+                Log.w(TAG, "onGetCredentialException afm sessionIds don't match");
+                return;
+            }
+
+            final AutofillClient client = getClient();
+            if (client == null) {
+                Log.w(TAG, "onGetCredentialException afm client id null");
+                return;
+            }
+            ArrayList<AutofillId> failedIds = new ArrayList<>();
+            final View[] views = client.autofillClientFindViewsByAutofillIdTraversal(
+                    Helper.toArray(new ArrayList<>(Collections.singleton(id))));
+            if (views == null || views.length == 0) {
+                Log.w(TAG, "onGetCredentialException afm client view not found");
+                return;
+            }
+
+            final View view = views[0];
+            if (view == null) {
+                Log.i(TAG, "onGetCredentialException View is null");
+
+                // Most likely view has been removed after the initial request was sent to the
+                // the service; this is fine, but we need to update the view status in the
+                // server side so it can be triggered again.
+                Log.d(TAG, "onGetCredentialException(): no View with id " + id);
+                failedIds.add(id);
+            }
+            if (id.isVirtualInt()) {
+                Log.i(TAG, "onGetCredentialException afm client id is virtual");
+                // TODO(b/326314286): Handle virtual views
+            } else {
+                Log.i(TAG, "onGetCredentialException afm client id is NOT virtual");
+                view.onGetCredentialException(errorType, errorMsg);
+            }
+            handleFailedIdsLocked(failedIds);
+        }
+    }
+
     private void onGetCredentialResponse(int sessionId, AutofillId id,
             GetCredentialResponse response) {
         synchronized (mLock) {
@@ -4382,6 +4433,15 @@
         }
 
         @Override
+        public void onGetCredentialException(int sessionId, AutofillId id,
+                String errorType, String errorMsg) {
+            final AutofillManager afm = mAfm.get();
+            if (afm != null) {
+                afm.post(() -> afm.onGetCredentialException(sessionId, id, errorType, errorMsg));
+            }
+        }
+
+        @Override
         public void autofillContent(int sessionId, AutofillId id, ClipData content) {
             final AutofillManager afm = mAfm.get();
             if (afm != null) {
diff --git a/core/java/android/view/autofill/IAutoFillManagerClient.aidl b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
index e838027..904a7e0 100644
--- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl
+++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
@@ -49,9 +49,12 @@
     void autofill(int sessionId, in List<AutofillId> ids, in List<AutofillValue> values,
             boolean hideHighlight);
 
-     void onGetCredentialResponse(int sessionId, in AutofillId id,
+    void onGetCredentialResponse(int sessionId, in AutofillId id,
                  in GetCredentialResponse response);
 
+    void onGetCredentialException(int sessionId, in AutofillId id,
+                     in String errorType, in String errorMsg);
+
     /**
      * Autofills the activity with rich content data (e.g. an image) from a dataset.
      */
diff --git a/core/java/android/view/flags/refresh_rate_flags.aconfig b/core/java/android/view/flags/refresh_rate_flags.aconfig
index 9d613bc..05cabd5 100644
--- a/core/java/android/view/flags/refresh_rate_flags.aconfig
+++ b/core/java/android/view/flags/refresh_rate_flags.aconfig
@@ -74,4 +74,12 @@
     description: "Feature flag for setting frame rate based on velocity"
     bug: "239979904"
     is_fixed_read_only: true
+}
+
+flag {
+    name: "toolkit_frame_rate_typing_read_only"
+    namespace: "toolkit"
+    description: "Feature flag for suppressing boost on typing"
+    bug: "239979904"
+    is_fixed_read_only: true
 }
\ No newline at end of file
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 7c9678f..16fecc1 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -497,6 +497,25 @@
      * @hide
      */
     @TestApi
+    public InputMethodInfo(@NonNull String packageName, @NonNull String className,
+            @NonNull CharSequence label, @NonNull String settingsActivity,
+            @NonNull String languageSettingsActivity, boolean supportStylusHandwriting,
+            @NonNull String stylusHandwritingSettingsActivityAttr) {
+        this(buildFakeResolveInfo(packageName, className, label), false /* isAuxIme */,
+                settingsActivity, languageSettingsActivity, null /* subtypes */,
+                0 /* isDefaultResId */, false /* forceDefault */,
+                true /* supportsSwitchingToNextInputMethod */,
+                false /* inlineSuggestionsEnabled */, false /* isVrOnly */,
+                false /* isVirtualDeviceOnly */, 0 /* handledConfigChanges */,
+                supportStylusHandwriting, false /* supportConnectionlessStylusHandwriting */,
+                stylusHandwritingSettingsActivityAttr, false /* inlineSuggestionsEnabled */);
+    }
+
+    /**
+     * Test API for creating a built-in input method to verify stylus handwriting.
+     * @hide
+     */
+    @TestApi
     @FlaggedApi(Flags.FLAG_CONNECTIONLESS_HANDWRITING)
     public InputMethodInfo(@NonNull String packageName, @NonNull String className,
             @NonNull CharSequence label, @NonNull String settingsActivity,
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 3bce155..f349ae9 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -3490,8 +3490,7 @@
             return false;
         }
         mServedView = mNextServedView;
-        if (initiationWithoutInputConnection() && mServedView.onCheckIsTextEditor()
-                && mServedView.isHandwritingDelegate()) {
+        if (initiationWithoutInputConnection() && mServedView.isHandwritingDelegate()) {
             mServedView.getViewRootImpl().getHandwritingInitiator().onDelegateViewFocused(
                     mServedView);
         }
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 13dc4ef..0e5747d 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -3874,7 +3874,7 @@
         }
     }
 
-    private static class SetDrawInstructionAction extends Action {
+    private class SetDrawInstructionAction extends Action {
 
         @Nullable
         private final DrawInstructions mInstructions;
@@ -3909,6 +3909,15 @@
                 }
                 try (ByteArrayInputStream is = new ByteArrayInputStream(bytes.get(0))) {
                     player.setDocument(new RemoteComposeDocument(is));
+                    player.addClickListener((viewId, metadata) -> {
+                        mActions.forEach(action -> {
+                            if (viewId == action.mViewId
+                                    && action instanceof SetOnClickResponse setOnClickResponse) {
+                                setOnClickResponse.mResponse.handleViewInteraction(
+                                        player, params.handler);
+                            }
+                        });
+                    });
                 } catch (IOException e) {
                     Log.e(LOG_TAG, "Failed to render draw instructions", e);
                 }
@@ -6051,16 +6060,6 @@
         RemoteViews rvToApply = getRemoteViewsToApply(context, size);
         View result = inflateView(context, rvToApply, directParent,
                 params.applyThemeResId, params.colorResources);
-        if (result instanceof RemoteComposePlayer player) {
-            player.addClickListener((viewId, metadata) -> {
-                mActions.forEach(action -> {
-                    if (viewId == action.mViewId
-                            && action instanceof SetOnClickResponse setOnClickResponse) {
-                        setOnClickResponse.mResponse.handleViewInteraction(player, params.handler);
-                    }
-                });
-            });
-        }
         rvToApply.performApply(result, rootParent, params);
         return result;
     }
diff --git a/core/java/android/window/flags/OWNERS b/core/java/android/window/flags/OWNERS
index 3fa3760..fd73d35 100644
--- a/core/java/android/window/flags/OWNERS
+++ b/core/java/android/window/flags/OWNERS
@@ -1,2 +1,3 @@
 per-file responsible_apis.aconfig = file:/BAL_OWNERS
 per-file large_screen_experiences_app_compat.aconfig = file:/LSE_APP_COMPAT_OWNERS
+per-file accessibility.aconfig = file:/core/java/android/view/accessibility/OWNERS
diff --git a/core/java/android/window/flags/accessibility.aconfig b/core/java/android/window/flags/accessibility.aconfig
index d467be6..814c620 100644
--- a/core/java/android/window/flags/accessibility.aconfig
+++ b/core/java/android/window/flags/accessibility.aconfig
@@ -5,4 +5,11 @@
   namespace: "accessibility"
   description: "The flag controls whether the intersection check for non-magnifiable windows is needed when onWindowTransition,"
   bug: "312624253"
+}
+
+flag {
+  name: "magnification_always_draw_fullscreen_border"
+  namespace: "accessibility"
+  description: "Always draw fullscreen orange border in fullscreen magnification"
+  bug: "291891390"
 }
\ No newline at end of file
diff --git a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
index 82067de..254f4f7 100644
--- a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
+++ b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
@@ -77,3 +77,10 @@
   bug: "309593314"
   is_fixed_read_only: true
 }
+
+flag {
+  name: "letterbox_background_wallpaper"
+  namespace: "large_screen_experiences_app_compat"
+  description: "Whether the blurred letterbox wallpaper background is enabled by default"
+  bug: "297195682"
+}
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
new file mode 100644
index 0000000..63a2474
--- /dev/null
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -0,0 +1,16 @@
+package: "com.android.window.flags"
+
+flag {
+    name: "enable_scaled_resizing"
+    namespace: "lse_desktop_experience"
+    description: "Enable the resizing of un-resizable apps through scaling their bounds up/down"
+    bug: "320350734"
+    is_fixed_read_only: true
+}
+
+flag {
+    name: "enable_desktop_windowing_mode"
+    namespace: "lse_desktop_experience"
+    description: "Enables desktop windowing"
+    bug: "304778354"
+}
diff --git a/core/java/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig
index 8b3bd97..3f48341 100644
--- a/core/java/android/window/flags/window_surfaces.aconfig
+++ b/core/java/android/window/flags/window_surfaces.aconfig
@@ -81,3 +81,14 @@
     is_fixed_read_only: true
     bug: "321263247"
 }
+
+flag {
+    namespace: "window_surfaces"
+    name: "enable_buffer_transform_hint_from_display"
+    description: "Always use display info to determine VRI's buffer transform hint"
+    is_fixed_read_only: true
+    bug: "301238858"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java
index 51a5ddf..3d3db47 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java
@@ -111,8 +111,9 @@
      * @param context The context of the application.
      * @param shortcutType The shortcut type.
      * @return The list of {@link AccessibilityTarget}.
+     * @hide
      */
-    static List<AccessibilityTarget> getInstalledTargets(Context context,
+    public static List<AccessibilityTarget> getInstalledTargets(Context context,
             @ShortcutType int shortcutType) {
         final List<AccessibilityTarget> targets = new ArrayList<>();
         targets.addAll(getAccessibilityFilteredTargets(context, shortcutType));
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 86d3037..29669d3 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -96,6 +96,7 @@
 import android.provider.OpenableColumns;
 import android.provider.Settings;
 import android.service.chooser.ChooserTarget;
+import android.service.chooser.Flags;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.HashedStringCache;
@@ -2543,6 +2544,9 @@
 
         @Override
         public boolean isComponentPinned(ComponentName name) {
+            if (Flags.legacyChooserPinningRemoval()) {
+                return false;
+            }
             return mPinnedSharedPrefs.getBoolean(name.flattenToString(), false);
         }
 
@@ -3147,6 +3151,10 @@
     }
 
     private boolean shouldShowTargetDetails(TargetInfo ti) {
+        if (Flags.legacyChooserPinningRemoval()) {
+            // Never show the long press menu if we've removed pinning.
+            return false;
+        }
         ComponentName nearbyShare = getNearbySharingComponent();
         //  Suppress target details for nearby share to hide pin/unpin action
         boolean isNearbyShare = nearbyShare != null && nearbyShare.equals(
diff --git a/core/java/com/android/internal/app/UnlaunchableAppActivity.java b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
index 73914a2..4ef0a1b 100644
--- a/core/java/com/android/internal/app/UnlaunchableAppActivity.java
+++ b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
@@ -67,6 +67,8 @@
         mUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
         mTarget = intent.getParcelableExtra(Intent.EXTRA_INTENT,
                 android.content.IntentSender.class);
+        String targetPackageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
+        final UserManager userManager = UserManager.get(this);
 
         if (mUserId == UserHandle.USER_NULL) {
             Log.wtf(TAG, "Invalid user id: " + mUserId + ". Stopping.");
@@ -74,13 +76,20 @@
             return;
         }
 
+        if (android.os.Flags.allowPrivateProfile()
+                && !userManager.isManagedProfile(mUserId)) {
+            Log.e(TAG, "Unlaunchable activity for target package " + targetPackageName
+                    + " called for a non-managed-profile " + mUserId);
+            finish();
+            return;
+        }
+
         if (mReason != UNLAUNCHABLE_REASON_QUIET_MODE) {
             Log.wtf(TAG, "Invalid unlaunchable type: " + mReason);
             finish();
             return;
         }
 
-        String targetPackageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
         boolean showEmergencyCallButton =
                 (targetPackageName != null && targetPackageName.equals(
                         mTelecomManager.getDefaultDialerPackage(UserHandle.of(mUserId))));
diff --git a/core/java/com/android/internal/display/RefreshRateSettingsUtils.java b/core/java/com/android/internal/display/RefreshRateSettingsUtils.java
index fab8984..c23a501 100644
--- a/core/java/com/android/internal/display/RefreshRateSettingsUtils.java
+++ b/core/java/com/android/internal/display/RefreshRateSettingsUtils.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.display;
 
+import static android.hardware.display.DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED;
+
 import android.content.Context;
 import android.hardware.display.DisplayManager;
 import android.util.Log;
@@ -54,4 +56,31 @@
         }
         return maxRefreshRate;
     }
+
+    /**
+     * Find the highest refresh rate among all the modes of all the displays.
+     *
+     * This method will acquire DisplayManager.mLock, so calling it while holding other locks
+     * should be done with care.
+     * @param context The context
+     * @return The highest refresh rate
+     */
+    public static float findHighestRefreshRateAmongAllDisplays(Context context) {
+        final DisplayManager dm = context.getSystemService(DisplayManager.class);
+        final Display[] displays = dm.getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED);
+        if (displays.length == 0) {
+            Log.w(TAG, "No valid display devices");
+            return DEFAULT_REFRESH_RATE;
+        }
+
+        float maxRefreshRate = DEFAULT_REFRESH_RATE;
+        for (Display display : displays) {
+            for (Display.Mode mode : display.getSupportedModes()) {
+                if (mode.getRefreshRate() > maxRefreshRate) {
+                    maxRefreshRate = mode.getRefreshRate();
+                }
+            }
+        }
+        return maxRefreshRate;
+    }
 }
diff --git a/core/java/com/android/internal/os/BatteryStatsHistory.java b/core/java/com/android/internal/os/BatteryStatsHistory.java
index c5c17cf..2a522645 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistory.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistory.java
@@ -136,10 +136,8 @@
     private final Parcel mHistoryBuffer;
     private final File mSystemDir;
     private final HistoryStepDetailsCalculator mStepDetailsCalculator;
-    private final File mHistoryDir;
     private final Clock mClock;
 
-    private int mMaxHistoryFiles;
     private int mMaxHistoryBufferSize;
 
     /**
@@ -150,7 +148,7 @@
     /**
      * A list of history files with increasing timestamps.
      */
-    private final List<BatteryHistoryFile> mHistoryFiles = new ArrayList<>();
+    private final BatteryHistoryDirectory mHistoryDir;
 
     /**
      * A list of small history parcels, used when BatteryStatsImpl object is created from
@@ -161,7 +159,8 @@
     /**
      * When iterating history files, the current file index.
      */
-    private int mCurrentFileIndex;
+    private BatteryHistoryFile mCurrentFile;
+
     /**
      * When iterating history files, the current file parcel.
      */
@@ -203,7 +202,6 @@
     private byte mLastHistoryStepLevel = 0;
     private boolean mMutable = true;
     private final BatteryStatsHistory mWritableHistory;
-    private boolean mCleanupEnabled = true;
 
     private static class BatteryHistoryFile implements Comparable<BatteryHistoryFile> {
         public final long monotonicTimeMs;
@@ -235,6 +233,271 @@
         }
     }
 
+    private static class BatteryHistoryDirectory {
+        private final File mDirectory;
+        private final MonotonicClock mMonotonicClock;
+        private int mMaxHistoryFiles;
+        private final List<BatteryHistoryFile> mHistoryFiles = new ArrayList<>();
+        private final ReentrantLock mLock = new ReentrantLock();
+        private boolean mCleanupNeeded;
+
+        BatteryHistoryDirectory(File directory, MonotonicClock monotonicClock,
+                int maxHistoryFiles) {
+            mDirectory = directory;
+            mMonotonicClock = monotonicClock;
+            mMaxHistoryFiles = maxHistoryFiles;
+            if (mMaxHistoryFiles == 0) {
+                Slog.wtf(TAG, "mMaxHistoryFiles should not be zero when writing history");
+            }
+        }
+
+        void setMaxHistoryFiles(int maxHistoryFiles) {
+            mMaxHistoryFiles = maxHistoryFiles;
+            cleanup();
+        }
+
+        void lock() {
+            mLock.lock();
+        }
+
+        void unlock() {
+            mLock.unlock();
+            if (mCleanupNeeded) {
+                cleanup();
+            }
+        }
+
+        boolean isLocked() {
+            return mLock.isLocked();
+        }
+
+        void load() {
+            mDirectory.mkdirs();
+            if (!mDirectory.exists()) {
+                Slog.wtf(TAG, "HistoryDir does not exist:" + mDirectory.getPath());
+            }
+
+            final List<File> toRemove = new ArrayList<>();
+            final Set<BatteryHistoryFile> dedup = new ArraySet<>();
+            mDirectory.listFiles((dir, name) -> {
+                final int b = name.lastIndexOf(FILE_SUFFIX);
+                if (b <= 0) {
+                    toRemove.add(new File(dir, name));
+                    return false;
+                }
+                try {
+                    long monotonicTime = Long.parseLong(name.substring(0, b));
+                    dedup.add(new BatteryHistoryFile(mDirectory, monotonicTime));
+                } catch (NumberFormatException e) {
+                    toRemove.add(new File(dir, name));
+                    return false;
+                }
+                return true;
+            });
+            if (!dedup.isEmpty()) {
+                mHistoryFiles.addAll(dedup);
+                Collections.sort(mHistoryFiles);
+            }
+            if (!toRemove.isEmpty()) {
+                // Clear out legacy history files, which did not follow the X-Y.bin naming format.
+                BackgroundThread.getHandler().post(() -> {
+                    lock();
+                    try {
+                        for (File file : toRemove) {
+                            file.delete();
+                        }
+                    } finally {
+                        unlock();
+                    }
+                });
+            }
+        }
+
+        List<String> getFileNames() {
+            lock();
+            try {
+                List<String> names = new ArrayList<>();
+                for (BatteryHistoryFile historyFile : mHistoryFiles) {
+                    names.add(historyFile.atomicFile.getBaseFile().getName());
+                }
+                return names;
+            } finally {
+                unlock();
+            }
+        }
+
+        @Nullable
+        BatteryHistoryFile getFirstFile() {
+            lock();
+            try {
+                if (!mHistoryFiles.isEmpty()) {
+                    return mHistoryFiles.get(0);
+                }
+                return null;
+            } finally {
+                unlock();
+            }
+        }
+
+        @Nullable
+        BatteryHistoryFile getLastFile() {
+            lock();
+            try {
+                if (!mHistoryFiles.isEmpty()) {
+                    return mHistoryFiles.get(mHistoryFiles.size() - 1);
+                }
+                return null;
+            } finally {
+                unlock();
+            }
+        }
+
+        @Nullable
+        BatteryHistoryFile getNextFile(BatteryHistoryFile current, long startTimeMs,
+                long endTimeMs) {
+            if (!mLock.isHeldByCurrentThread()) {
+                throw new IllegalStateException("Iterating battery history without a lock");
+            }
+
+            int nextFileIndex = 0;
+            int firstFileIndex = 0;
+            // skip the last file because its data is in history buffer.
+            int lastFileIndex = mHistoryFiles.size() - 2;
+            for (int i = lastFileIndex; i >= 0; i--) {
+                BatteryHistoryFile file = mHistoryFiles.get(i);
+                if (current != null && file.monotonicTimeMs == current.monotonicTimeMs) {
+                    nextFileIndex = i + 1;
+                }
+                if (file.monotonicTimeMs > endTimeMs) {
+                    lastFileIndex = i - 1;
+                }
+                if (file.monotonicTimeMs <= startTimeMs) {
+                    firstFileIndex = i;
+                    break;
+                }
+            }
+
+            if (nextFileIndex < firstFileIndex) {
+                nextFileIndex = firstFileIndex;
+            }
+
+            if (nextFileIndex <= lastFileIndex) {
+                return mHistoryFiles.get(nextFileIndex);
+            }
+
+            return null;
+        }
+
+        BatteryHistoryFile makeBatteryHistoryFile() {
+            BatteryHistoryFile file = new BatteryHistoryFile(mDirectory,
+                    mMonotonicClock.monotonicTime());
+            lock();
+            try {
+                mHistoryFiles.add(file);
+            } finally {
+                unlock();
+            }
+            return file;
+        }
+
+        void writeToParcel(Parcel out, boolean useBlobs) {
+            lock();
+            try {
+                final long start = SystemClock.uptimeMillis();
+                out.writeInt(mHistoryFiles.size() - 1);
+                for (int i = 0; i < mHistoryFiles.size() - 1; i++) {
+                    AtomicFile file = mHistoryFiles.get(i).atomicFile;
+                    byte[] raw = new byte[0];
+                    try {
+                        raw = file.readFully();
+                    } catch (Exception e) {
+                        Slog.e(TAG, "Error reading file " + file.getBaseFile().getPath(), e);
+                    }
+                    if (useBlobs) {
+                        out.writeBlob(raw);
+                    } else {
+                        // Avoiding blobs in the check-in file for compatibility
+                        out.writeByteArray(raw);
+                    }
+                }
+                if (DEBUG) {
+                    Slog.d(TAG,
+                            "writeToParcel duration ms:" + (SystemClock.uptimeMillis() - start));
+                }
+            } finally {
+                unlock();
+            }
+        }
+
+        int getFileCount() {
+            lock();
+            try {
+                return mHistoryFiles.size();
+            } finally {
+                unlock();
+            }
+        }
+
+        int getSize() {
+            lock();
+            try {
+                int ret = 0;
+                for (int i = 0; i < mHistoryFiles.size() - 1; i++) {
+                    ret += (int) mHistoryFiles.get(i).atomicFile.getBaseFile().length();
+                }
+                return ret;
+            } finally {
+                unlock();
+            }
+        }
+
+        void reset() {
+            lock();
+            try {
+                if (DEBUG) Slog.i(TAG, "********** CLEARING HISTORY!");
+                for (BatteryHistoryFile file : mHistoryFiles) {
+                    file.atomicFile.delete();
+                }
+                mHistoryFiles.clear();
+            } finally {
+                unlock();
+            }
+        }
+
+        private void cleanup() {
+            if (mDirectory == null) {
+                return;
+            }
+
+            if (isLocked()) {
+                mCleanupNeeded = true;
+                return;
+            }
+
+            mCleanupNeeded = false;
+
+            lock();
+            try {
+                // if free disk space is less than 100MB, delete oldest history file.
+                if (!hasFreeDiskSpace(mDirectory)) {
+                    BatteryHistoryFile oldest = mHistoryFiles.remove(0);
+                    oldest.atomicFile.delete();
+                }
+
+                // if there are more history files than allowed, delete oldest history files.
+                // mMaxHistoryFiles comes from Constants.MAX_HISTORY_FILES and
+                // can be updated by DeviceConfig at run time.
+                while (mHistoryFiles.size() > mMaxHistoryFiles) {
+                    BatteryHistoryFile oldest = mHistoryFiles.get(0);
+                    oldest.atomicFile.delete();
+                    mHistoryFiles.remove(0);
+                }
+            } finally {
+                unlock();
+            }
+        }
+    }
+
     /**
      * A delegate responsible for computing additional details for a step in battery history.
      */
@@ -351,7 +614,6 @@
             BatteryStatsHistory writableHistory) {
         mHistoryBuffer = historyBuffer;
         mSystemDir = systemDir;
-        mMaxHistoryFiles = maxHistoryFiles;
         mMaxHistoryBufferSize = maxHistoryBufferSize;
         mStepDetailsCalculator = stepDetailsCalculator;
         mTracer = tracer;
@@ -363,66 +625,32 @@
             mMutable = false;
         }
 
-        mHistoryDir = new File(systemDir, HISTORY_DIR);
-        mHistoryDir.mkdirs();
-        if (!mHistoryDir.exists()) {
-            Slog.wtf(TAG, "HistoryDir does not exist:" + mHistoryDir.getPath());
-        }
-
-        final List<File> toRemove = new ArrayList<>();
-        final Set<BatteryHistoryFile> dedup = new ArraySet<>();
-        mHistoryDir.listFiles((dir, name) -> {
-            final int b = name.lastIndexOf(FILE_SUFFIX);
-            if (b <= 0) {
-                toRemove.add(new File(dir, name));
-                return false;
+        if (writableHistory != null) {
+            mHistoryDir = writableHistory.mHistoryDir;
+        } else {
+            mHistoryDir = new BatteryHistoryDirectory(new File(systemDir, HISTORY_DIR),
+                    monotonicClock, maxHistoryFiles);
+            mHistoryDir.load();
+            BatteryHistoryFile activeFile = mHistoryDir.getLastFile();
+            if (activeFile == null) {
+                activeFile = mHistoryDir.makeBatteryHistoryFile();
             }
-            try {
-                long monotonicTime = Long.parseLong(name.substring(0, b));
-                dedup.add(new BatteryHistoryFile(mHistoryDir, monotonicTime));
-            } catch (NumberFormatException e) {
-                toRemove.add(new File(dir, name));
-                return false;
-            }
-            return true;
-        });
-        if (!dedup.isEmpty()) {
-            mHistoryFiles.addAll(dedup);
-            Collections.sort(mHistoryFiles);
-            setActiveFile(mHistoryFiles.get(mHistoryFiles.size() - 1));
-        } else if (mMutable) {
-            // No file found, default to have the initial file.
-            BatteryHistoryFile name = makeBatteryHistoryFile();
-            mHistoryFiles.add(name);
-            setActiveFile(name);
-        }
-        if (!toRemove.isEmpty()) {
-            // Clear out legacy history files, which did not follow the X-Y.bin naming format.
-            BackgroundThread.getHandler().post(() -> {
-                for (File file : toRemove) {
-                    file.delete();
-                }
-            });
+            setActiveFile(activeFile);
         }
     }
 
-    private BatteryHistoryFile makeBatteryHistoryFile() {
-        return new BatteryHistoryFile(mHistoryDir, mMonotonicClock.monotonicTime());
-    }
-
-    public BatteryStatsHistory(int maxHistoryFiles, int maxHistoryBufferSize,
+    public BatteryStatsHistory(int maxHistoryBufferSize,
             HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock,
             MonotonicClock monotonicClock) {
-        this(maxHistoryFiles, maxHistoryBufferSize, stepDetailsCalculator, clock, monotonicClock,
+        this(maxHistoryBufferSize, stepDetailsCalculator, clock, monotonicClock,
                 new TraceDelegate(), new EventLogger());
     }
 
     @VisibleForTesting
-    public BatteryStatsHistory(int maxHistoryFiles, int maxHistoryBufferSize,
+    public BatteryStatsHistory(int maxHistoryBufferSize,
             HistoryStepDetailsCalculator stepDetailsCalculator, Clock clock,
             MonotonicClock monotonicClock, TraceDelegate traceDelegate,
             EventLogger eventLogger) {
-        mMaxHistoryFiles = maxHistoryFiles;
         mMaxHistoryBufferSize = maxHistoryBufferSize;
         mStepDetailsCalculator = stepDetailsCalculator;
         mTracer = traceDelegate;
@@ -484,7 +712,9 @@
      * Changes the maximum number of history files to be kept.
      */
     public void setMaxHistoryFiles(int maxHistoryFiles) {
-        mMaxHistoryFiles = maxHistoryFiles;
+        if (mHistoryDir != null) {
+            mHistoryDir.setMaxHistoryFiles(maxHistoryFiles);
+        }
     }
 
     /**
@@ -513,7 +743,7 @@
      * Returns true if this instance only supports reading history.
      */
     public boolean isReadOnly() {
-        return !mMutable || mActiveFile == null || mHistoryDir == null;
+        return !mMutable || mActiveFile == null/* || mHistoryDir == null*/;
     }
 
     /**
@@ -538,25 +768,13 @@
 
     @GuardedBy("this")
     private void startNextFileLocked(long elapsedRealtimeMs) {
-        if (mMaxHistoryFiles == 0) {
-            Slog.wtf(TAG, "mMaxHistoryFiles should not be zero when writing history");
-            return;
-        }
-
-        if (mHistoryFiles.isEmpty()) {
-            Slog.wtf(TAG, "mFileNumbers should never be empty");
-            return;
-        }
-
         final long start = SystemClock.uptimeMillis();
         writeHistory();
         if (DEBUG) {
             Slog.d(TAG, "writeHistory took ms:" + (SystemClock.uptimeMillis() - start));
         }
 
-        final BatteryHistoryFile next = makeBatteryHistoryFile();
-        mHistoryFiles.add(next);
-        setActiveFile(next);
+        setActiveFile(mHistoryDir.makeBatteryHistoryFile());
         try {
             mActiveFile.getBaseFile().createNewFile();
         } catch (IOException e) {
@@ -578,37 +796,7 @@
         }
 
         mWrittenPowerStatsDescriptors.clear();
-        cleanupLocked();
-    }
-
-    @GuardedBy("this")
-    private void setCleanupEnabledLocked(boolean enabled) {
-        mCleanupEnabled = enabled;
-        if (mCleanupEnabled) {
-            cleanupLocked();
-        }
-    }
-
-    @GuardedBy("this")
-    private void cleanupLocked() {
-        if (!mCleanupEnabled || mHistoryDir == null) {
-            return;
-        }
-
-        // if free disk space is less than 100MB, delete oldest history file.
-        if (!hasFreeDiskSpace()) {
-            BatteryHistoryFile oldest = mHistoryFiles.remove(0);
-            oldest.atomicFile.delete();
-        }
-
-        // if there are more history files than allowed, delete oldest history files.
-        // mMaxHistoryFiles comes from Constants.MAX_HISTORY_FILES and can be updated by GService
-        // config at run time.
-        while (mHistoryFiles.size() > mMaxHistoryFiles) {
-            BatteryHistoryFile oldest = mHistoryFiles.get(0);
-            oldest.atomicFile.delete();
-            mHistoryFiles.remove(0);
-        }
+        mHistoryDir.cleanup();
     }
 
     /**
@@ -616,9 +804,7 @@
      * currently being read.
      */
     public boolean isResetEnabled() {
-        synchronized (this) {
-            return mCleanupEnabled;
-        }
+        return mHistoryDir == null || !mHistoryDir.isLocked();
     }
 
     /**
@@ -627,16 +813,10 @@
      */
     public void reset() {
         synchronized (this) {
-            if (DEBUG) Slog.i(TAG, "********** CLEARING HISTORY!");
-            for (BatteryHistoryFile file : mHistoryFiles) {
-                file.atomicFile.delete();
+            if (mHistoryDir != null) {
+                mHistoryDir.reset();
+                setActiveFile(mHistoryDir.makeBatteryHistoryFile());
             }
-            mHistoryFiles.clear();
-
-            BatteryHistoryFile name = makeBatteryHistoryFile();
-            mHistoryFiles.add(name);
-            setActiveFile(name);
-
             initHistoryBuffer();
         }
     }
@@ -646,8 +826,9 @@
      */
     public long getStartTime() {
         synchronized (this) {
-            if (!mHistoryFiles.isEmpty()) {
-                return mHistoryFiles.get(0).monotonicTimeMs;
+            BatteryHistoryFile file = mHistoryDir.getFirstFile();
+            if (file != null) {
+                return file.monotonicTimeMs;
             } else {
                 return mHistoryBufferStartTime;
             }
@@ -668,15 +849,13 @@
             return copy().iterate(startTimeMs, endTimeMs);
         }
 
-        mCurrentFileIndex = 0;
+        if (mHistoryDir != null) {
+            mHistoryDir.lock();
+        }
+        mCurrentFile = null;
         mCurrentParcel = null;
         mCurrentParcelEnd = 0;
         mParcelIndex = 0;
-        if (mWritableHistory != null) {
-            synchronized (mWritableHistory) {
-                mWritableHistory.setCleanupEnabledLocked(false);
-            }
-        }
         return new BatteryStatsHistoryIterator(this, startTimeMs, endTimeMs);
     }
 
@@ -685,10 +864,8 @@
      */
     void iteratorFinished() {
         mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
-        if (mWritableHistory != null) {
-            synchronized (mWritableHistory) {
-                mWritableHistory.setCleanupEnabledLocked(true);
-            }
+        if (mHistoryDir != null) {
+            mHistoryDir.unlock();
         }
     }
 
@@ -719,39 +896,27 @@
             }
         }
 
-        int firstFileIndex = 0;
-        // skip the last file because its data is in history buffer.
-        int lastFileIndex = mHistoryFiles.size() - 1;
-        for (int i = mHistoryFiles.size() - 1; i >= 0; i--) {
-            BatteryHistoryFile file = mHistoryFiles.get(i);
-            if (file.monotonicTimeMs >= endTimeMs) {
-                lastFileIndex = i;
-            }
-            if (file.monotonicTimeMs <= startTimeMs) {
-                firstFileIndex = i;
-                break;
-            }
-        }
-
-        if (mCurrentFileIndex < firstFileIndex) {
-            mCurrentFileIndex = firstFileIndex;
-        }
-
-        while (mCurrentFileIndex < lastFileIndex) {
-            mCurrentParcel = null;
-            mCurrentParcelEnd = 0;
-            final Parcel p = Parcel.obtain();
-            AtomicFile file = mHistoryFiles.get(mCurrentFileIndex++).atomicFile;
-            if (readFileToParcel(p, file)) {
-                int bufSize = p.readInt();
-                int curPos = p.dataPosition();
-                mCurrentParcelEnd = curPos + bufSize;
-                mCurrentParcel = p;
-                if (curPos < mCurrentParcelEnd) {
-                    return mCurrentParcel;
+        if (mHistoryDir != null) {
+            BatteryHistoryFile nextFile = mHistoryDir.getNextFile(mCurrentFile, startTimeMs,
+                    endTimeMs);
+            while (nextFile != null) {
+                mCurrentParcel = null;
+                mCurrentParcelEnd = 0;
+                final Parcel p = Parcel.obtain();
+                AtomicFile file = nextFile.atomicFile;
+                if (readFileToParcel(p, file)) {
+                    int bufSize = p.readInt();
+                    int curPos = p.dataPosition();
+                    mCurrentParcelEnd = curPos + bufSize;
+                    mCurrentParcel = p;
+                    if (curPos < mCurrentParcelEnd) {
+                        mCurrentFile = nextFile;
+                        return mCurrentParcel;
+                    }
+                } else {
+                    p.recycle();
                 }
-            } else {
-                p.recycle();
+                nextFile = mHistoryDir.getNextFile(nextFile, startTimeMs, endTimeMs);
             }
         }
 
@@ -922,25 +1087,8 @@
     }
 
     private void writeToParcel(Parcel out, boolean useBlobs) {
-        final long start = SystemClock.uptimeMillis();
-        out.writeInt(mHistoryFiles.size() - 1);
-        for (int i = 0; i < mHistoryFiles.size() - 1; i++) {
-            AtomicFile file = mHistoryFiles.get(i).atomicFile;
-            byte[] raw = new byte[0];
-            try {
-                raw = file.readFully();
-            } catch (Exception e) {
-                Slog.e(TAG, "Error reading file " + file.getBaseFile().getPath(), e);
-            }
-            if (useBlobs) {
-                out.writeBlob(raw);
-            } else {
-                // Avoiding blobs in the check-in file for compatibility
-                out.writeByteArray(raw);
-            }
-        }
-        if (DEBUG) {
-            Slog.d(TAG, "writeToParcel duration ms:" + (SystemClock.uptimeMillis() - start));
+        if (mHistoryDir != null) {
+            mHistoryDir.writeToParcel(out, useBlobs);
         }
     }
 
@@ -1021,22 +1169,18 @@
      * @return true if there is more than 100MB free disk space left.
      */
     @android.ravenwood.annotation.RavenwoodReplace
-    private boolean hasFreeDiskSpace() {
-        final StatFs stats = new StatFs(mHistoryDir.getAbsolutePath());
+    private static boolean hasFreeDiskSpace(File systemDir) {
+        final StatFs stats = new StatFs(systemDir.getAbsolutePath());
         return stats.getAvailableBytes() > MIN_FREE_SPACE;
     }
 
-    private boolean hasFreeDiskSpace$ravenwood() {
+    private static boolean hasFreeDiskSpace$ravenwood(File systemDir) {
         return true;
     }
 
     @VisibleForTesting
     public List<String> getFilesNames() {
-        List<String> names = new ArrayList<>();
-        for (BatteryHistoryFile historyFile : mHistoryFiles) {
-            names.add(historyFile.atomicFile.getBaseFile().getName());
-        }
-        return names;
+        return mHistoryDir.getFileNames();
     }
 
     @VisibleForTesting
@@ -1048,10 +1192,7 @@
      * @return the total size of all history files and history buffer.
      */
     public int getHistoryUsedSize() {
-        int ret = 0;
-        for (int i = 0; i < mHistoryFiles.size() - 1; i++) {
-            ret += mHistoryFiles.get(i).atomicFile.getBaseFile().length();
-        }
+        int ret = mHistoryDir.getSize();
         ret += mHistoryBuffer.dataSize();
         if (mHistoryParcels != null) {
             for (int i = 0; i < mHistoryParcels.size(); i++) {
@@ -1109,7 +1250,7 @@
      */
     public void continueRecordingHistory() {
         synchronized (this) {
-            if (mHistoryBuffer.dataPosition() <= 0 && mHistoryFiles.size() <= 1) {
+            if (mHistoryBuffer.dataPosition() <= 0 && mHistoryDir.getFileCount() <= 1) {
                 return;
             }
 
diff --git a/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java b/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java
index b2a6a93..83e9407 100644
--- a/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java
+++ b/core/java/com/android/internal/os/BatteryStatsHistoryIterator.java
@@ -44,6 +44,7 @@
     private BatteryStats.HistoryItem mHistoryItem = new BatteryStats.HistoryItem();
     private boolean mNextItemReady;
     private boolean mTimeInitialized;
+    private boolean mClosed;
 
     public BatteryStatsHistoryIterator(@NonNull BatteryStatsHistory history, long startTimeMs,
             long endTimeMs) {
@@ -322,6 +323,9 @@
      */
     @Override
     public void close() {
-        mBatteryStatsHistory.iteratorFinished();
+        if (!mClosed) {
+            mClosed = true;
+            mBatteryStatsHistory.iteratorFinished();
+        }
     }
 }
diff --git a/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
index 73df5e8..5e89d06 100644
--- a/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
+++ b/core/java/com/android/internal/pm/parsing/pkg/PackageImpl.java
@@ -421,6 +421,8 @@
     @NonNull
     private String[] mUsesStaticLibrariesSorted;
 
+    private boolean mAppMetadataFileInApk = false;
+
     @NonNull
     public static PackageImpl forParsing(@NonNull String packageName, @NonNull String baseCodePath,
             @NonNull String codePath, @NonNull TypedArray manifestArray, boolean isCoreApp,
@@ -1063,6 +1065,11 @@
         return memtagMode;
     }
 
+    @Override
+    public boolean isAppMetadataFileInApk() {
+        return mAppMetadataFileInApk;
+    }
+
     @Nullable
     @Override
     public Bundle getMetaData() {
@@ -2151,6 +2158,12 @@
     }
 
     @Override
+    public PackageImpl setAppMetadataFileInApk(boolean fileInApk) {
+        mAppMetadataFileInApk = fileInApk;
+        return this;
+    }
+
+    @Override
     public PackageImpl setMetaData(@Nullable Bundle value) {
         metaData = value;
         return this;
@@ -3264,6 +3277,7 @@
         dest.writeLong(this.mBooleans);
         dest.writeLong(this.mBooleans2);
         dest.writeBoolean(this.mAllowCrossUidActivitySwitchFromBelow);
+        dest.writeBoolean(this.mAppMetadataFileInApk);
     }
 
     public PackageImpl(Parcel in) {
@@ -3426,6 +3440,7 @@
         this.mBooleans = in.readLong();
         this.mBooleans2 = in.readLong();
         this.mAllowCrossUidActivitySwitchFromBelow = in.readBoolean();
+        this.mAppMetadataFileInApk = in.readBoolean();
 
         assignDerivedFields();
         assignDerivedFields2();
diff --git a/core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java b/core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java
index 66cfb69..3c26a7c 100644
--- a/core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java
+++ b/core/java/com/android/internal/pm/parsing/pkg/ParsedPackage.java
@@ -127,4 +127,7 @@
     ParsedPackage setDirectBootAware(boolean directBootAware);
 
     ParsedPackage setPersistent(boolean persistent);
+
+    /** Retrieves whether the apk contains a app metadata file. */
+    boolean isAppMetadataFileInApk();
 }
diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
index 5d185af..5ab17a6 100644
--- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackage.java
@@ -133,6 +133,9 @@
             @Nullable SparseArray<int[]> splitDependencies
     );
 
+    /** Sets whether the apk contains a app metadata file. */
+    ParsingPackage setAppMetadataFileInApk(boolean fileInApk);
+
     ParsingPackage setMetaData(Bundle metaData);
 
     ParsingPackage setForceQueryable(boolean forceQueryable);
diff --git a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
index 2e6053d..00c4827 100644
--- a/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
@@ -46,6 +46,7 @@
 import android.content.pm.ConfigurationInfo;
 import android.content.pm.FeatureGroupInfo;
 import android.content.pm.FeatureInfo;
+import android.content.pm.Flags;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.Property;
@@ -163,6 +164,8 @@
      */
     public static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
 
+    public static final String APP_METADATA_FILE_NAME = "app.metadata";
+
     /**
      * Path prefix for apps on expanded storage
      */
@@ -636,6 +639,11 @@
                 pkg.setSigningDetails(SigningDetails.UNKNOWN);
             }
 
+            if (Flags.aslInApkAppMetadataSource()
+                    && ArrayUtils.contains(assets.list(""), APP_METADATA_FILE_NAME)) {
+                pkg.setAppMetadataFileInApk(true);
+            }
+
             return input.success(pkg);
         } catch (Exception e) {
             return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
@@ -686,7 +694,8 @@
      */
     private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, String apkPath,
             String codePath, Resources res, XmlResourceParser parser, int flags,
-            boolean shouldSkipComponents) throws XmlPullParserException, IOException {
+            boolean shouldSkipComponents)
+            throws XmlPullParserException, IOException {
         final String splitName;
         final String pkgName;
 
diff --git a/core/java/com/android/internal/protolog/BaseProtoLogImpl.java b/core/java/com/android/internal/protolog/LegacyProtoLogImpl.java
similarity index 81%
rename from core/java/com/android/internal/protolog/BaseProtoLogImpl.java
rename to core/java/com/android/internal/protolog/LegacyProtoLogImpl.java
index abe6c7c..d9ac5a9 100644
--- a/core/java/com/android/internal/protolog/BaseProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/LegacyProtoLogImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -37,8 +37,11 @@
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ILogger;
+import com.android.internal.protolog.common.IProtoLog;
 import com.android.internal.protolog.common.IProtoLogGroup;
 import com.android.internal.protolog.common.LogDataType;
+import com.android.internal.protolog.common.LogLevel;
 import com.android.internal.util.TraceBuffer;
 
 import java.io.File;
@@ -48,52 +51,49 @@
 import java.util.TreeMap;
 import java.util.stream.Collectors;
 
-
 /**
  * A service for the ProtoLog logging system.
  */
-public class BaseProtoLogImpl {
-    protected static final TreeMap<String, IProtoLogGroup> LOG_GROUPS = new TreeMap<>();
+public class LegacyProtoLogImpl implements IProtoLog {
+    private final TreeMap<String, IProtoLogGroup> mLogGroups = new TreeMap<>();
 
-    /**
-     * A runnable to update the cached output of {@link #isEnabled}.
-     *
-     * Must be invoked after every action that could change the result of {@link #isEnabled}, eg.
-     * starting / stopping proto log, or enabling / disabling log groups.
-     */
-    public static Runnable sCacheUpdater = () -> { };
-
-    protected static void addLogGroupEnum(IProtoLogGroup[] config) {
-        for (IProtoLogGroup group : config) {
-            LOG_GROUPS.put(group.name(), group);
-        }
-    }
-
+    private static final int BUFFER_CAPACITY = 1024 * 1024;
+    private static final int PER_CHUNK_SIZE = 1024;
     private static final String TAG = "ProtoLog";
     private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
     static final String PROTOLOG_VERSION = "1.0.0";
     private static final int DEFAULT_PER_CHUNK_SIZE = 0;
 
     private final File mLogFile;
-    private final String mViewerConfigFilename;
+    private final String mLegacyViewerConfigFilename;
     private final TraceBuffer mBuffer;
-    protected final ProtoLogViewerConfigReader mViewerConfig;
+    private final LegacyProtoLogViewerConfigReader mViewerConfig;
     private final int mPerChunkSize;
 
     private boolean mProtoLogEnabled;
     private boolean mProtoLogEnabledLockFree;
     private final Object mProtoLogEnabledLock = new Object();
 
-    @VisibleForTesting
-    public enum LogLevel {
-        DEBUG, VERBOSE, INFO, WARN, ERROR, WTF
+    public LegacyProtoLogImpl(String outputFile, String viewerConfigFilename) {
+        this(new File(outputFile), viewerConfigFilename, BUFFER_CAPACITY,
+                new LegacyProtoLogViewerConfigReader(), PER_CHUNK_SIZE);
+    }
+
+    public LegacyProtoLogImpl(File file, String viewerConfigFilename, int bufferCapacity,
+            LegacyProtoLogViewerConfigReader viewerConfig, int perChunkSize) {
+        mLogFile = file;
+        mBuffer = new TraceBuffer(bufferCapacity);
+        mLegacyViewerConfigFilename = viewerConfigFilename;
+        mViewerConfig = viewerConfig;
+        mPerChunkSize = perChunkSize;
     }
 
     /**
      * Main log method, do not call directly.
      */
     @VisibleForTesting
-    public void log(LogLevel level, IProtoLogGroup group, int messageHash, int paramsMask,
+    @Override
+    public void log(LogLevel level, IProtoLogGroup group, long messageHash, int paramsMask,
             @Nullable String messageString, Object[] args) {
         if (group.isLogToProto()) {
             logToProto(messageHash, paramsMask, args);
@@ -103,7 +103,7 @@
         }
     }
 
-    private void logToLogcat(String tag, LogLevel level, int messageHash,
+    private void logToLogcat(String tag, LogLevel level, long messageHash,
             @Nullable String messageString, Object[] args) {
         String message = null;
         if (messageString == null) {
@@ -157,7 +157,7 @@
         }
     }
 
-    private void logToProto(int messageHash, int paramsMask, Object[] args) {
+    private void logToProto(long messageHash, int paramsMask, Object[] args) {
         if (!isProtoEnabled()) {
             return;
         }
@@ -219,20 +219,6 @@
         }
     }
 
-    public BaseProtoLogImpl(File file, String viewerConfigFilename, int bufferCapacity,
-            ProtoLogViewerConfigReader viewerConfig) {
-        this(file, viewerConfigFilename, bufferCapacity, viewerConfig, DEFAULT_PER_CHUNK_SIZE);
-    }
-
-    public BaseProtoLogImpl(File file, String viewerConfigFilename, int bufferCapacity,
-            ProtoLogViewerConfigReader viewerConfig, int perChunkSize) {
-        mLogFile = file;
-        mBuffer = new TraceBuffer(bufferCapacity);
-        mViewerConfigFilename = viewerConfigFilename;
-        mViewerConfig = viewerConfig;
-        mPerChunkSize = perChunkSize;
-    }
-
     /**
      * Starts the logging a circular proto buffer.
      *
@@ -248,7 +234,6 @@
             mProtoLogEnabled = true;
             mProtoLogEnabledLockFree = true;
         }
-        sCacheUpdater.run();
     }
 
     /**
@@ -274,7 +259,6 @@
                 throw new IllegalStateException("logging enabled while waiting for flush.");
             }
         }
-        sCacheUpdater.run();
     }
 
     /**
@@ -284,11 +268,11 @@
         return mProtoLogEnabledLockFree;
     }
 
-    protected int setLogging(boolean setTextLogging, boolean value, PrintWriter pw,
+    private int setLogging(boolean setTextLogging, boolean value, ILogger logger,
             String... groups) {
         for (int i = 0; i < groups.length; i++) {
             String group = groups[i];
-            IProtoLogGroup g = LOG_GROUPS.get(group);
+            IProtoLogGroup g = mLogGroups.get(group);
             if (g != null) {
                 if (setTextLogging) {
                     g.setLogToLogcat(value);
@@ -296,11 +280,10 @@
                     g.setLogToProto(value);
                 }
             } else {
-                logAndPrintln(pw, "No IProtoLogGroup named " + group);
+                logger.log("No IProtoLogGroup named " + group);
                 return -1;
             }
         }
-        sCacheUpdater.run();
         return 0;
     }
 
@@ -330,6 +313,7 @@
         while ((arg = shell.getNextArg()) != null) {
             args.add(arg);
         }
+        final ILogger logger = (msg) -> logAndPrintln(pw, msg);
         String[] groups = args.toArray(new String[args.size()]);
         switch (cmd) {
             case "start":
@@ -342,14 +326,14 @@
                 logAndPrintln(pw, getStatus());
                 return 0;
             case "enable":
-                return setLogging(false, true, pw, groups);
+                return setLogging(false, true, logger, groups);
             case "enable-text":
-                mViewerConfig.loadViewerConfig(pw, mViewerConfigFilename);
-                return setLogging(true, true, pw, groups);
+                mViewerConfig.loadViewerConfig(logger, mLegacyViewerConfigFilename);
+                return setLogging(true, true, logger, groups);
             case "disable":
-                return setLogging(false, false, pw, groups);
+                return setLogging(false, false, logger, groups);
             case "disable-text":
-                return setLogging(true, false, pw, groups);
+                return setLogging(true, false, logger, groups);
             default:
                 return unknownCommand(pw);
         }
@@ -362,12 +346,12 @@
         return "ProtoLog status: "
                 + ((isProtoEnabled()) ? "Enabled" : "Disabled")
                 + "\nEnabled log groups: \n  Proto: "
-                + LOG_GROUPS.values().stream().filter(
-                    it -> it.isEnabled() && it.isLogToProto())
+                + mLogGroups.values().stream().filter(
+                        it -> it.isEnabled() && it.isLogToProto())
                 .map(IProtoLogGroup::name).collect(Collectors.joining(" "))
                 + "\n  Logcat: "
-                + LOG_GROUPS.values().stream().filter(
-                    it -> it.isEnabled() && it.isLogToLogcat())
+                + mLogGroups.values().stream().filter(
+                        it -> it.isEnabled() && it.isLogToLogcat())
                 .map(IProtoLogGroup::name).collect(Collectors.joining(" "))
                 + "\nLogging definitions loaded: " + mViewerConfig.knownViewerStringsNumber();
     }
@@ -393,5 +377,26 @@
             pw.flush();
         }
     }
+
+    /**
+     * Start text logging
+     * @param groups Groups to start text logging for
+     * @param logger A logger to write status updates to
+     * @return status code
+     */
+    public int startLoggingToLogcat(String[] groups, ILogger logger) {
+        mViewerConfig.loadViewerConfig(logger, mLegacyViewerConfigFilename);
+        return setLogging(true /* setTextLogging */, true, logger, groups);
+    }
+
+    /**
+     * Stop text logging
+     * @param groups Groups to start text logging for
+     * @param logger A logger to write status updates to
+     * @return status code
+     */
+    public int stopLoggingToLogcat(String[] groups, ILogger logger) {
+        return setLogging(true /* setTextLogging */, false, logger, groups);
+    }
 }
 
diff --git a/core/java/com/android/internal/protolog/LegacyProtoLogViewerConfigReader.java b/core/java/com/android/internal/protolog/LegacyProtoLogViewerConfigReader.java
new file mode 100644
index 0000000..1833410
--- /dev/null
+++ b/core/java/com/android/internal/protolog/LegacyProtoLogViewerConfigReader.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2020 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.internal.protolog;
+
+import com.android.internal.protolog.common.ILogger;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.zip.GZIPInputStream;
+
+/**
+ * Handles loading and parsing of ProtoLog viewer configuration.
+ */
+public class LegacyProtoLogViewerConfigReader {
+
+    private static final String TAG = "ProtoLogViewerConfigReader";
+    private Map<Long, String> mLogMessageMap = null;
+
+    /** Returns message format string for its hash or null if unavailable. */
+    public synchronized String getViewerString(long messageHash) {
+        if (mLogMessageMap != null) {
+            return mLogMessageMap.get(messageHash);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Reads the specified viewer configuration file. Does nothing if the config is already loaded.
+     */
+    public synchronized void loadViewerConfig(ILogger logger, String viewerConfigFilename) {
+        try {
+            loadViewerConfig(new GZIPInputStream(new FileInputStream(viewerConfigFilename)));
+            logger.log("Loaded " + mLogMessageMap.size()
+                    + " log definitions from " + viewerConfigFilename);
+        } catch (FileNotFoundException e) {
+            logger.log("Unable to load log definitions: File "
+                    + viewerConfigFilename + " not found." + e);
+        } catch (IOException e) {
+            logger.log("Unable to load log definitions: IOException while reading "
+                    + viewerConfigFilename + ". " + e);
+        } catch (JSONException e) {
+            logger.log("Unable to load log definitions: JSON parsing exception while reading "
+                    + viewerConfigFilename + ". " + e);
+        }
+    }
+
+    /**
+     * Reads the specified viewer configuration input stream.
+     * Does nothing if the config is already loaded.
+     */
+    public synchronized void loadViewerConfig(InputStream viewerConfigInputStream)
+            throws IOException, JSONException {
+        if (mLogMessageMap != null) {
+            return;
+        }
+        InputStreamReader config = new InputStreamReader(viewerConfigInputStream);
+        BufferedReader reader = new BufferedReader(config);
+        StringBuilder builder = new StringBuilder();
+        String line;
+        while ((line = reader.readLine()) != null) {
+            builder.append(line).append('\n');
+        }
+        reader.close();
+        JSONObject json = new JSONObject(builder.toString());
+        JSONObject messages = json.getJSONObject("messages");
+
+        mLogMessageMap = new TreeMap<>();
+        Iterator it = messages.keys();
+        while (it.hasNext()) {
+            String key = (String) it.next();
+            try {
+                long hash = Long.parseLong(key);
+                JSONObject val = messages.getJSONObject(key);
+                String msg = val.getString("message");
+                mLogMessageMap.put(hash, msg);
+            } catch (NumberFormatException expected) {
+                // Not a messageHash - skip it
+            }
+        }
+    }
+
+    /**
+     * Returns the number of loaded log definitions kept in memory.
+     */
+    public synchronized int knownViewerStringsNumber() {
+        if (mLogMessageMap != null) {
+            return mLogMessageMap.size();
+        }
+        return 0;
+    }
+
+}
diff --git a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
new file mode 100644
index 0000000..53062d8
--- /dev/null
+++ b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java
@@ -0,0 +1,559 @@
+/*
+ * Copyright (C) 2024 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.internal.protolog;
+
+import static perfetto.protos.PerfettoTrace.InternedData.PROTOLOG_STACKTRACE;
+import static perfetto.protos.PerfettoTrace.InternedData.PROTOLOG_STRING_ARGS;
+import static perfetto.protos.PerfettoTrace.InternedString.IID;
+import static perfetto.protos.PerfettoTrace.InternedString.STR;
+import static perfetto.protos.PerfettoTrace.ProtoLogMessage.BOOLEAN_PARAMS;
+import static perfetto.protos.PerfettoTrace.ProtoLogMessage.DOUBLE_PARAMS;
+import static perfetto.protos.PerfettoTrace.ProtoLogMessage.STACKTRACE_IID;
+import static perfetto.protos.PerfettoTrace.ProtoLogMessage.MESSAGE_ID;
+import static perfetto.protos.PerfettoTrace.ProtoLogMessage.SINT64_PARAMS;
+import static perfetto.protos.PerfettoTrace.ProtoLogMessage.STR_PARAM_IIDS;
+import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.GROUPS;
+import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.Group.ID;
+import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.Group.NAME;
+import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.Group.TAG;
+import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.MESSAGES;
+import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.MessageData.GROUP_ID;
+import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.MessageData.LEVEL;
+import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.MessageData.MESSAGE;
+import static perfetto.protos.PerfettoTrace.TracePacket.INTERNED_DATA;
+import static perfetto.protos.PerfettoTrace.TracePacket.PROTOLOG_MESSAGE;
+import static perfetto.protos.PerfettoTrace.TracePacket.PROTOLOG_VIEWER_CONFIG;
+import static perfetto.protos.PerfettoTrace.TracePacket.SEQUENCE_FLAGS;
+import static perfetto.protos.PerfettoTrace.TracePacket.SEQ_INCREMENTAL_STATE_CLEARED;
+import static perfetto.protos.PerfettoTrace.TracePacket.SEQ_NEEDS_INCREMENTAL_STATE;
+import static perfetto.protos.PerfettoTrace.TracePacket.TIMESTAMP;
+
+import android.annotation.Nullable;
+import android.os.ShellCommand;
+import android.os.SystemClock;
+import android.os.Trace;
+import android.text.TextUtils;
+import android.tracing.perfetto.DataSourceParams;
+import android.tracing.perfetto.InitArguments;
+import android.tracing.perfetto.Producer;
+import android.tracing.perfetto.TracingContext;
+import android.util.LongArray;
+import android.util.Slog;
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.ILogger;
+import com.android.internal.protolog.common.IProtoLog;
+import com.android.internal.protolog.common.IProtoLogGroup;
+import com.android.internal.protolog.common.LogDataType;
+import com.android.internal.protolog.common.LogLevel;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.MessageData;
+
+/**
+ * A service for the ProtoLog logging system.
+ */
+public class PerfettoProtoLogImpl implements IProtoLog {
+    private final TreeMap<String, IProtoLogGroup> mLogGroups = new TreeMap<>();
+    private static final String LOG_TAG = "ProtoLog";
+    private final AtomicInteger mTracingInstances = new AtomicInteger();
+
+    private final ProtoLogDataSource mDataSource = new ProtoLogDataSource(
+            this.mTracingInstances::incrementAndGet,
+            this::dumpTransitionTraceConfig,
+            this.mTracingInstances::decrementAndGet
+    );
+    private final ProtoLogViewerConfigReader mViewerConfigReader;
+    private final ViewerConfigInputStreamProvider mViewerConfigInputStreamProvider;
+
+    public PerfettoProtoLogImpl(String viewerConfigFilePath) {
+        this(() -> {
+            try {
+                return new ProtoInputStream(new FileInputStream(viewerConfigFilePath));
+            } catch (FileNotFoundException e) {
+                Slog.w(LOG_TAG, "Failed to load viewer config file " + viewerConfigFilePath, e);
+                return null;
+            }
+        });
+    }
+
+    public PerfettoProtoLogImpl(ViewerConfigInputStreamProvider viewerConfigInputStreamProvider) {
+        this(viewerConfigInputStreamProvider,
+                new ProtoLogViewerConfigReader(viewerConfigInputStreamProvider));
+    }
+
+    @VisibleForTesting
+    public PerfettoProtoLogImpl(
+            ViewerConfigInputStreamProvider viewerConfigInputStreamProvider,
+            ProtoLogViewerConfigReader viewerConfigReader
+    ) {
+        Producer.init(InitArguments.DEFAULTS);
+        mDataSource.register(DataSourceParams.DEFAULTS);
+        this.mViewerConfigInputStreamProvider = viewerConfigInputStreamProvider;
+        this.mViewerConfigReader = viewerConfigReader;
+    }
+
+    /**
+     * Main log method, do not call directly.
+     */
+    @VisibleForTesting
+    @Override
+    public void log(LogLevel level, IProtoLogGroup group, long messageHash, int paramsMask,
+            @Nullable String messageString, Object[] args) {
+        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "log");
+
+        long tsNanos = SystemClock.elapsedRealtimeNanos();
+        try {
+            logToProto(level, group.name(), messageHash, paramsMask, args, tsNanos);
+            if (group.isLogToLogcat()) {
+                logToLogcat(group.getTag(), level, messageHash, messageString, args);
+            }
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+        }
+    }
+
+    private void dumpTransitionTraceConfig() {
+        ProtoInputStream pis = mViewerConfigInputStreamProvider.getInputStream();
+
+        if (pis == null) {
+            Slog.w(LOG_TAG, "Failed to get viewer input stream.");
+            return;
+        }
+
+        mDataSource.trace(ctx -> {
+            final ProtoOutputStream os = ctx.newTracePacket();
+
+            os.write(TIMESTAMP, SystemClock.elapsedRealtimeNanos());
+
+            final long outProtologViewerConfigToken = os.start(PROTOLOG_VIEWER_CONFIG);
+            while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+                if (pis.getFieldNumber() == (int) MESSAGES) {
+                    final long inMessageToken = pis.start(MESSAGES);
+                    final long outMessagesToken = os.start(MESSAGES);
+
+                    while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+                        switch (pis.getFieldNumber()) {
+                            case (int) MessageData.MESSAGE_ID:
+                                os.write(MessageData.MESSAGE_ID,
+                                        pis.readLong(MessageData.MESSAGE_ID));
+                                break;
+                            case (int) MESSAGE:
+                                os.write(MESSAGE, pis.readString(MESSAGE));
+                                break;
+                            case (int) LEVEL:
+                                os.write(LEVEL, pis.readInt(LEVEL));
+                                break;
+                            case (int) GROUP_ID:
+                                os.write(GROUP_ID, pis.readInt(GROUP_ID));
+                                break;
+                            default:
+                                throw new RuntimeException(
+                                        "Unexpected field id " + pis.getFieldNumber());
+                        }
+                    }
+
+                    pis.end(inMessageToken);
+                    os.end(outMessagesToken);
+                }
+
+                if (pis.getFieldNumber() == (int) GROUPS) {
+                    final long inGroupToken = pis.start(GROUPS);
+                    final long outGroupToken = os.start(GROUPS);
+
+                    while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+                        switch (pis.getFieldNumber()) {
+                            case (int) ID:
+                                int id = pis.readInt(ID);
+                                os.write(ID, id);
+                                break;
+                            case (int) NAME:
+                                String name = pis.readString(NAME);
+                                os.write(NAME, name);
+                                break;
+                            case (int) TAG:
+                                String tag = pis.readString(TAG);
+                                os.write(TAG, tag);
+                                break;
+                            default:
+                                throw new RuntimeException(
+                                        "Unexpected field id " + pis.getFieldNumber());
+                        }
+                    }
+
+                    pis.end(inGroupToken);
+                    os.end(outGroupToken);
+                }
+            }
+
+            os.end(outProtologViewerConfigToken);
+
+            ctx.flush();
+        });
+
+        mDataSource.flush();
+    }
+
+    private void logToLogcat(String tag, LogLevel level, long messageHash,
+            @Nullable String messageString, Object[] args) {
+        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "logToLogcat");
+        try {
+            doLogToLogcat(tag, level, messageHash, messageString, args);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+        }
+    }
+
+    private void doLogToLogcat(String tag, LogLevel level, long messageHash,
+            @androidx.annotation.Nullable String messageString, Object[] args) {
+        String message = null;
+        if (messageString == null) {
+            messageString = mViewerConfigReader.getViewerString(messageHash);
+        }
+        if (messageString != null) {
+            if (args != null) {
+                try {
+                    message = TextUtils.formatSimple(messageString, args);
+                } catch (Exception ex) {
+                    Slog.w(LOG_TAG, "Invalid ProtoLog format string.", ex);
+                }
+            } else {
+                message = messageString;
+            }
+        }
+        if (message == null) {
+            StringBuilder builder = new StringBuilder("UNKNOWN MESSAGE (" + messageHash + ")");
+            for (Object o : args) {
+                builder.append(" ").append(o);
+            }
+            message = builder.toString();
+        }
+        passToLogcat(tag, level, message);
+    }
+
+    /**
+     * SLog wrapper.
+     */
+    @VisibleForTesting
+    public void passToLogcat(String tag, LogLevel level, String message) {
+        switch (level) {
+            case DEBUG:
+                Slog.d(tag, message);
+                break;
+            case VERBOSE:
+                Slog.v(tag, message);
+                break;
+            case INFO:
+                Slog.i(tag, message);
+                break;
+            case WARN:
+                Slog.w(tag, message);
+                break;
+            case ERROR:
+                Slog.e(tag, message);
+                break;
+            case WTF:
+                Slog.wtf(tag, message);
+                break;
+        }
+    }
+
+    private void logToProto(LogLevel level, String groupName, long messageHash, int paramsMask,
+            Object[] args, long tsNanos) {
+        if (!isProtoEnabled()) {
+            return;
+        }
+
+        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "logToProto");
+        try {
+            doLogToProto(level, groupName, messageHash, paramsMask, args, tsNanos);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+        }
+    }
+
+    private void doLogToProto(LogLevel level, String groupName, long messageHash, int paramsMask,
+            Object[] args, long tsNanos) {
+        mDataSource.trace(ctx -> {
+            final ProtoLogDataSource.TlsState tlsState = ctx.getCustomTlsState();
+            final LogLevel logFrom = tlsState.getLogFromLevel(groupName);
+
+            if (level.ordinal() < logFrom.ordinal()) {
+                return;
+            }
+
+            if (args != null) {
+                // Intern all string params before creating the trace packet for the proto
+                // message so that the interned strings appear before in the trace to make the
+                // trace processing easier.
+                int argIndex = 0;
+                for (Object o : args) {
+                    int type = LogDataType.bitmaskToLogDataType(paramsMask, argIndex);
+                    if (type == LogDataType.STRING) {
+                        internStringArg(ctx, o.toString());
+                    }
+                    argIndex++;
+                }
+            }
+
+            int internedStacktrace = 0;
+            if (tlsState.getShouldCollectStacktrace(groupName)) {
+                // Intern stackstraces before creating the trace packet for the proto message so
+                // that the interned stacktrace strings appear before in the trace to make the
+                // trace processing easier.
+                String stacktrace = collectStackTrace();
+                internedStacktrace = internStacktraceString(ctx, stacktrace);
+            }
+
+            final ProtoOutputStream os = ctx.newTracePacket();
+            os.write(TIMESTAMP, tsNanos);
+            long token = os.start(PROTOLOG_MESSAGE);
+            os.write(MESSAGE_ID, messageHash);
+
+            boolean needsIncrementalState = false;
+
+            if (args != null) {
+
+                int argIndex = 0;
+                LongArray longParams = new LongArray();
+                ArrayList<Double> doubleParams = new ArrayList<>();
+                ArrayList<Boolean> booleanParams = new ArrayList<>();
+                for (Object o : args) {
+                    int type = LogDataType.bitmaskToLogDataType(paramsMask, argIndex);
+                    try {
+                        switch (type) {
+                            case LogDataType.STRING:
+                                final int internedStringId = internStringArg(ctx, o.toString());
+                                os.write(STR_PARAM_IIDS, internedStringId);
+                                needsIncrementalState = true;
+                                break;
+                            case LogDataType.LONG:
+                                longParams.add(((Number) o).longValue());
+                                break;
+                            case LogDataType.DOUBLE:
+                                doubleParams.add(((Number) o).doubleValue());
+                                break;
+                            case LogDataType.BOOLEAN:
+                                booleanParams.add((boolean) o);
+                                break;
+                        }
+                    } catch (ClassCastException ex) {
+                        Slog.e(LOG_TAG, "Invalid ProtoLog paramsMask", ex);
+                    }
+                    argIndex++;
+                }
+
+                for (int i = 0; i < longParams.size(); ++i) {
+                    os.write(SINT64_PARAMS, longParams.get(i));
+                }
+                doubleParams.forEach(it -> os.write(DOUBLE_PARAMS, it));
+                // Converting booleans to int because Perfetto doesn't yet support repeated
+                // booleans, so we use a repeated integers instead (b/313651412).
+                booleanParams.forEach(it -> os.write(BOOLEAN_PARAMS, it ? 1 : 0));
+            }
+
+            if (tlsState.getShouldCollectStacktrace(groupName)) {
+                os.write(STACKTRACE_IID, internedStacktrace);
+            }
+
+            os.end(token);
+
+            if (needsIncrementalState) {
+                os.write(SEQUENCE_FLAGS, SEQ_NEEDS_INCREMENTAL_STATE);
+            }
+
+        });
+    }
+
+    private static final int STACK_SIZE_TO_PROTO_LOG_ENTRY_CALL = 12;
+
+    private String collectStackTrace() {
+        StackTraceElement[] stackTrace =  Thread.currentThread().getStackTrace();
+        StringWriter sw = new StringWriter();
+        try (PrintWriter pw = new PrintWriter(sw)) {
+            for (int i = STACK_SIZE_TO_PROTO_LOG_ENTRY_CALL; i < stackTrace.length; ++i) {
+                pw.println("\tat " + stackTrace[i]);
+            }
+        }
+
+        return sw.toString();
+    }
+
+    private int internStacktraceString(TracingContext<ProtoLogDataSource.Instance,
+            ProtoLogDataSource.TlsState,
+            ProtoLogDataSource.IncrementalState> ctx,
+            String stacktrace) {
+        final ProtoLogDataSource.IncrementalState incrementalState = ctx.getIncrementalState();
+        return internString(ctx, incrementalState.stacktraceInterningMap,
+                PROTOLOG_STACKTRACE, stacktrace);
+    }
+
+    private int internStringArg(
+            TracingContext<ProtoLogDataSource.Instance,
+            ProtoLogDataSource.TlsState,
+            ProtoLogDataSource.IncrementalState> ctx,
+            String string
+    ) {
+        final ProtoLogDataSource.IncrementalState incrementalState = ctx.getIncrementalState();
+        return internString(ctx, incrementalState.argumentInterningMap,
+                PROTOLOG_STRING_ARGS, string);
+    }
+
+    private int internString(
+            TracingContext<ProtoLogDataSource.Instance,
+                ProtoLogDataSource.TlsState,
+                ProtoLogDataSource.IncrementalState> ctx,
+            Map<String, Integer> internMap,
+            long fieldId,
+            String string
+    ) {
+        final ProtoLogDataSource.IncrementalState incrementalState = ctx.getIncrementalState();
+
+        if (!incrementalState.clearReported) {
+            final ProtoOutputStream os = ctx.newTracePacket();
+            os.write(SEQUENCE_FLAGS, SEQ_INCREMENTAL_STATE_CLEARED);
+            incrementalState.clearReported = true;
+        }
+
+        if (!internMap.containsKey(string)) {
+            final int internedIndex = internMap.size() + 1;
+            internMap.put(string, internedIndex);
+
+            final ProtoOutputStream os = ctx.newTracePacket();
+            final long token = os.start(INTERNED_DATA);
+            final long innerToken = os.start(fieldId);
+            os.write(IID, internedIndex);
+            os.write(STR, string.getBytes());
+            os.end(innerToken);
+            os.end(token);
+        }
+
+        return internMap.get(string);
+    }
+
+    /**
+     * Responds to a shell command.
+     */
+    public int onShellCommand(ShellCommand shell) {
+        PrintWriter pw = shell.getOutPrintWriter();
+        String cmd = shell.getNextArg();
+        if (cmd == null) {
+            return unknownCommand(pw);
+        }
+        ArrayList<String> args = new ArrayList<>();
+        String arg;
+        while ((arg = shell.getNextArg()) != null) {
+            args.add(arg);
+        }
+        final ILogger logger = (msg) -> logAndPrintln(pw, msg);
+        String[] groups = args.toArray(new String[args.size()]);
+        switch (cmd) {
+            case "enable-text":
+                return this.startLoggingToLogcat(groups, logger);
+            case "disable-text":
+                return this.stopLoggingToLogcat(groups, logger);
+            default:
+                return unknownCommand(pw);
+        }
+    }
+
+    private int unknownCommand(PrintWriter pw) {
+        pw.println("Unknown command");
+        pw.println("Window manager logging options:");
+        pw.println("  enable-text [group...]: Enable logcat logging for given groups");
+        pw.println("  disable-text [group...]: Disable logcat logging for given groups");
+        return -1;
+    }
+
+    /**
+     * Returns {@code true} iff logging to proto is enabled.
+     */
+    public boolean isProtoEnabled() {
+        return mTracingInstances.get() > 0;
+    }
+
+    /**
+     * Start text logging
+     * @param groups Groups to start text logging for
+     * @param logger A logger to write status updates to
+     * @return status code
+     */
+    public int startLoggingToLogcat(String[] groups, ILogger logger) {
+        mViewerConfigReader.loadViewerConfig(logger);
+        return setTextLogging(true, logger, groups);
+    }
+
+    /**
+     * Stop text logging
+     * @param groups Groups to start text logging for
+     * @param logger A logger to write status updates to
+     * @return status code
+     */
+    public int stopLoggingToLogcat(String[] groups, ILogger logger) {
+        mViewerConfigReader.unloadViewerConfig();
+        return setTextLogging(false, logger, groups);
+    }
+
+    /**
+     * Start logging the stack trace of the when the log message happened for target groups
+     * @return status code
+     */
+    public int startLoggingStackTrace(String[] groups, ILogger logger) {
+        return -1;
+    }
+
+    /**
+     * Stop logging the stack trace of the when the log message happened for target groups
+     * @return status code
+     */
+    public int stopLoggingStackTrace() {
+        return -1;
+    }
+
+    private int setTextLogging(boolean value, ILogger logger, String... groups) {
+        for (int i = 0; i < groups.length; i++) {
+            String group = groups[i];
+            IProtoLogGroup g = mLogGroups.get(group);
+            if (g != null) {
+                g.setLogToLogcat(value);
+            } else {
+                logger.log("No IProtoLogGroup named " + group);
+                return -1;
+            }
+        }
+        return 0;
+    }
+
+    static void logAndPrintln(@Nullable PrintWriter pw, String msg) {
+        Slog.i(LOG_TAG, msg);
+        if (pw != null) {
+            pw.println(msg);
+            pw.flush();
+        }
+    }
+}
+
diff --git a/core/java/com/android/internal/protolog/ProtoLogDataSource.java b/core/java/com/android/internal/protolog/ProtoLogDataSource.java
new file mode 100644
index 0000000..a8ff75d
--- /dev/null
+++ b/core/java/com/android/internal/protolog/ProtoLogDataSource.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.protolog;
+
+import static perfetto.protos.PerfettoTrace.DataSourceConfig.PROTOLOG_CONFIG;
+import static perfetto.protos.PerfettoTrace.ProtoLogConfig.GROUP_OVERRIDES;
+import static perfetto.protos.PerfettoTrace.ProtoLogConfig.TRACING_MODE;
+import static perfetto.protos.PerfettoTrace.ProtoLogGroup.COLLECT_STACKTRACE;
+import static perfetto.protos.PerfettoTrace.ProtoLogGroup.LOG_FROM;
+import static perfetto.protos.PerfettoTrace.ProtoLogGroup.GROUP_NAME;
+
+import android.tracing.perfetto.CreateIncrementalStateArgs;
+import android.tracing.perfetto.CreateTlsStateArgs;
+import android.tracing.perfetto.DataSource;
+import android.tracing.perfetto.DataSourceInstance;
+import android.tracing.perfetto.FlushCallbackArguments;
+import android.tracing.perfetto.StartCallbackArguments;
+import android.tracing.perfetto.StopCallbackArguments;
+import android.util.proto.ProtoInputStream;
+import android.util.proto.WireTypeMismatchException;
+
+import com.android.internal.protolog.common.LogLevel;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import perfetto.protos.PerfettoTrace;
+
+public class ProtoLogDataSource extends DataSource<ProtoLogDataSource.Instance,
+        ProtoLogDataSource.TlsState,
+        ProtoLogDataSource.IncrementalState> {
+
+    private final Runnable mOnStart;
+    private final Runnable mOnFlush;
+    private final Runnable mOnStop;
+
+    public ProtoLogDataSource(Runnable onStart, Runnable onFlush, Runnable onStop) {
+        super("android.protolog");
+        this.mOnStart = onStart;
+        this.mOnFlush = onFlush;
+        this.mOnStop = onStop;
+    }
+
+    @Override
+    public Instance createInstance(ProtoInputStream configStream, int instanceIndex) {
+        ProtoLogConfig config = null;
+
+        try {
+            while (configStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+                try {
+                    if (configStream.getFieldNumber() == (int) PROTOLOG_CONFIG) {
+                        if (config != null) {
+                            throw new RuntimeException("ProtoLog config already set in loop");
+                        }
+                        config = readProtoLogConfig(configStream);
+                    }
+                } catch (WireTypeMismatchException e) {
+                    throw new RuntimeException("Failed to parse ProtoLog DataSource config", e);
+                }
+            }
+        } catch (IOException e) {
+            throw new RuntimeException("Failed to read ProtoLog DataSource config", e);
+        }
+
+        if (config == null) {
+            // No config found
+            config = ProtoLogConfig.DEFAULT;
+        }
+
+        return new Instance(
+                this, instanceIndex, config, mOnStart, mOnFlush, mOnStop);
+    }
+
+    @Override
+    public TlsState createTlsState(CreateTlsStateArgs<Instance> args) {
+        try (Instance dsInstance = args.getDataSourceInstanceLocked()) {
+            if (dsInstance == null) {
+                // Datasource instance has been removed
+                return new TlsState(ProtoLogConfig.DEFAULT);
+            }
+            return new TlsState(dsInstance.mConfig);
+        }
+    }
+
+    @Override
+    public IncrementalState createIncrementalState(CreateIncrementalStateArgs<Instance> args) {
+        return new IncrementalState();
+    }
+
+    public static class TlsState {
+        private final ProtoLogConfig mConfig;
+
+        private TlsState(ProtoLogConfig config) {
+            this.mConfig = config;
+        }
+
+        /**
+         * Get the log from level for a group.
+         * @param groupTag The tag of the group to get the log from level.
+         * @return The lowest LogLevel (inclusive) to log message from.
+         */
+        public LogLevel getLogFromLevel(String groupTag) {
+            return getConfigFor(groupTag).logFrom;
+        }
+
+        /**
+         * Get if the stacktrace for the log message should be collected for this group.
+         * @param groupTag The tag of the group to get whether or not a stacktrace was requested.
+         * @return True iff a stacktrace was requested to be collected from this group in the
+         *         tracing config.
+         */
+        public boolean getShouldCollectStacktrace(String groupTag) {
+            return getConfigFor(groupTag).collectStackTrace;
+        }
+
+        private GroupConfig getConfigFor(String groupTag) {
+            return mConfig.getConfigFor(groupTag);
+        }
+    }
+
+    public static class IncrementalState {
+        public final Map<String, Integer> argumentInterningMap = new HashMap<>();
+        public final Map<String, Integer> stacktraceInterningMap = new HashMap<>();
+        public boolean clearReported = false;
+    }
+
+    private static class ProtoLogConfig {
+        private final LogLevel mDefaultLogFromLevel;
+        private final Map<String, GroupConfig> mGroupConfigs;
+
+        private static final ProtoLogConfig DEFAULT =
+                new ProtoLogConfig(LogLevel.WTF, new HashMap<>());
+
+        private ProtoLogConfig(
+                LogLevel defaultLogFromLevel, Map<String, GroupConfig> groupConfigs) {
+            this.mDefaultLogFromLevel = defaultLogFromLevel;
+            this.mGroupConfigs = groupConfigs;
+        }
+
+        private GroupConfig getConfigFor(String groupTag) {
+            return mGroupConfigs.getOrDefault(groupTag, getDefaultGroupConfig());
+        }
+
+        private GroupConfig getDefaultGroupConfig() {
+            return new GroupConfig(mDefaultLogFromLevel, false);
+        }
+    }
+
+    public static class GroupConfig {
+        public final LogLevel logFrom;
+        public final boolean collectStackTrace;
+
+        public GroupConfig(LogLevel logFromLevel, boolean collectStackTrace) {
+            this.logFrom = logFromLevel;
+            this.collectStackTrace = collectStackTrace;
+        }
+    }
+
+    private ProtoLogConfig readProtoLogConfig(ProtoInputStream configStream)
+            throws IOException {
+        final long config_token = configStream.start(PROTOLOG_CONFIG);
+
+        LogLevel defaultLogFromLevel = LogLevel.WTF;
+        final Map<String, GroupConfig> groupConfigs = new HashMap<>();
+
+        while (configStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            if (configStream.getFieldNumber() == (int) TRACING_MODE) {
+                int tracingMode = configStream.readInt(TRACING_MODE);
+                switch (tracingMode) {
+                    case PerfettoTrace.ProtoLogConfig.DEFAULT:
+                        break;
+                    case PerfettoTrace.ProtoLogConfig.ENABLE_ALL:
+                        defaultLogFromLevel = LogLevel.DEBUG;
+                        break;
+                    default:
+                        throw new RuntimeException("Unhandled ProtoLog tracing mode type");
+                }
+            }
+            if (configStream.getFieldNumber() == (int) GROUP_OVERRIDES) {
+                final long group_overrides_token  = configStream.start(GROUP_OVERRIDES);
+
+                String tag = null;
+                LogLevel logFromLevel = defaultLogFromLevel;
+                boolean collectStackTrace = false;
+                while (configStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+                    if (configStream.getFieldNumber() == (int) GROUP_NAME) {
+                        tag = configStream.readString(GROUP_NAME);
+                    }
+                    if (configStream.getFieldNumber() == (int) LOG_FROM) {
+                        final int logFromInt = configStream.readInt(LOG_FROM);
+                        switch (logFromInt) {
+                            case (PerfettoTrace.PROTOLOG_LEVEL_DEBUG): {
+                                logFromLevel = LogLevel.DEBUG;
+                                break;
+                            }
+                            case (PerfettoTrace.PROTOLOG_LEVEL_VERBOSE): {
+                                logFromLevel = LogLevel.VERBOSE;
+                                break;
+                            }
+                            case (PerfettoTrace.PROTOLOG_LEVEL_INFO): {
+                                logFromLevel = LogLevel.INFO;
+                                break;
+                            }
+                            case (PerfettoTrace.PROTOLOG_LEVEL_WARN): {
+                                logFromLevel = LogLevel.WARN;
+                                break;
+                            }
+                            case (PerfettoTrace.PROTOLOG_LEVEL_ERROR): {
+                                logFromLevel = LogLevel.ERROR;
+                                break;
+                            }
+                            case (PerfettoTrace.PROTOLOG_LEVEL_WTF): {
+                                logFromLevel = LogLevel.WTF;
+                                break;
+                            }
+                            default: {
+                                throw new RuntimeException("Unhandled log level");
+                            }
+                        }
+                    }
+                    if (configStream.getFieldNumber() == (int) COLLECT_STACKTRACE) {
+                        collectStackTrace = configStream.readBoolean(COLLECT_STACKTRACE);
+                    }
+                }
+
+                if (tag == null) {
+                    throw new RuntimeException("Failed to decode proto config. "
+                            + "Got a group override without a group tag.");
+                }
+
+                groupConfigs.put(tag, new GroupConfig(logFromLevel, collectStackTrace));
+
+                configStream.end(group_overrides_token);
+            }
+        }
+
+        configStream.end(config_token);
+
+        return new ProtoLogConfig(defaultLogFromLevel, groupConfigs);
+    }
+
+    public static class Instance extends DataSourceInstance {
+
+        private final Runnable mOnStart;
+        private final Runnable mOnFlush;
+        private final Runnable mOnStop;
+        private final ProtoLogConfig mConfig;
+
+        public Instance(
+                DataSource<Instance, TlsState, IncrementalState> dataSource,
+                int instanceIdx,
+                ProtoLogConfig config,
+                Runnable onStart,
+                Runnable onFlush,
+                Runnable onStop
+        ) {
+            super(dataSource, instanceIdx);
+            this.mOnStart = onStart;
+            this.mOnFlush = onFlush;
+            this.mOnStop = onStop;
+            this.mConfig = config;
+        }
+
+        @Override
+        public void onStart(StartCallbackArguments args) {
+            this.mOnStart.run();
+        }
+
+        @Override
+        public void onFlush(FlushCallbackArguments args) {
+            this.mOnFlush.run();
+        }
+
+        @Override
+        public void onStop(StopCallbackArguments args) {
+            this.mOnStop.run();
+        }
+    }
+}
diff --git a/core/java/com/android/internal/protolog/ProtoLogImpl.java b/core/java/com/android/internal/protolog/ProtoLogImpl.java
index 527cfdd..78bed94 100644
--- a/core/java/com/android/internal/protolog/ProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/ProtoLogImpl.java
@@ -16,30 +16,35 @@
 
 package com.android.internal.protolog;
 
+import static com.android.internal.protolog.common.ProtoLogToolInjected.Value.LEGACY_OUTPUT_FILE_PATH;
+import static com.android.internal.protolog.common.ProtoLogToolInjected.Value.LEGACY_VIEWER_CONFIG_PATH;
+import static com.android.internal.protolog.common.ProtoLogToolInjected.Value.VIEWER_CONFIG_PATH;
+
 import android.annotation.Nullable;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.protolog.common.IProtoLog;
 import com.android.internal.protolog.common.IProtoLogGroup;
-
-import java.io.File;
+import com.android.internal.protolog.common.LogLevel;
+import com.android.internal.protolog.common.ProtoLogToolInjected;
 
 /**
  * A service for the ProtoLog logging system.
  */
-public class ProtoLogImpl extends BaseProtoLogImpl {
-    private static final int BUFFER_CAPACITY = 1024 * 1024;
-    private static final String LOG_FILENAME = "/data/misc/wmtrace/wm_log.winscope";
-    private static final String VIEWER_CONFIG_FILENAME = "/system/etc/protolog.conf.json.gz";
-    private static final int PER_CHUNK_SIZE = 1024;
+public class ProtoLogImpl {
+    private static IProtoLog sServiceInstance = null;
 
-    private static ProtoLogImpl sServiceInstance = null;
+    @ProtoLogToolInjected(VIEWER_CONFIG_PATH)
+    private static String sViewerConfigPath;
 
-    static {
-        addLogGroupEnum(ProtoLogGroup.values());
-    }
+    @ProtoLogToolInjected(LEGACY_VIEWER_CONFIG_PATH)
+    private static String sLegacyViewerConfigPath;
+
+    @ProtoLogToolInjected(LEGACY_OUTPUT_FILE_PATH)
+    private static String sLegacyOutputFilePath;
 
     /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
-    public static void d(IProtoLogGroup group, int messageHash, int paramsMask,
+    public static void d(IProtoLogGroup group, long messageHash, int paramsMask,
             @Nullable String messageString,
             Object... args) {
         getSingleInstance()
@@ -47,7 +52,7 @@
     }
 
     /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
-    public static void v(IProtoLogGroup group, int messageHash, int paramsMask,
+    public static void v(IProtoLogGroup group, long messageHash, int paramsMask,
             @Nullable String messageString,
             Object... args) {
         getSingleInstance().log(LogLevel.VERBOSE, group, messageHash, paramsMask, messageString,
@@ -55,21 +60,21 @@
     }
 
     /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
-    public static void i(IProtoLogGroup group, int messageHash, int paramsMask,
+    public static void i(IProtoLogGroup group, long messageHash, int paramsMask,
             @Nullable String messageString,
             Object... args) {
         getSingleInstance().log(LogLevel.INFO, group, messageHash, paramsMask, messageString, args);
     }
 
     /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
-    public static void w(IProtoLogGroup group, int messageHash, int paramsMask,
+    public static void w(IProtoLogGroup group, long messageHash, int paramsMask,
             @Nullable String messageString,
             Object... args) {
         getSingleInstance().log(LogLevel.WARN, group, messageHash, paramsMask, messageString, args);
     }
 
     /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
-    public static void e(IProtoLogGroup group, int messageHash, int paramsMask,
+    public static void e(IProtoLogGroup group, long messageHash, int paramsMask,
             @Nullable String messageString,
             Object... args) {
         getSingleInstance()
@@ -77,40 +82,36 @@
     }
 
     /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
-    public static void wtf(IProtoLogGroup group, int messageHash, int paramsMask,
+    public static void wtf(IProtoLogGroup group, long messageHash, int paramsMask,
             @Nullable String messageString,
             Object... args) {
         getSingleInstance().log(LogLevel.WTF, group, messageHash, paramsMask, messageString, args);
     }
 
-    /** Returns true iff logging is enabled for the given {@code IProtoLogGroup}. */
     public static boolean isEnabled(IProtoLogGroup group) {
-        return group.isLogToLogcat()
-                || (group.isLogToProto() && getSingleInstance().isProtoEnabled());
+        // TODO: Implement for performance reasons, with optional level parameter?
+        return true;
     }
 
     /**
      * Returns the single instance of the ProtoLogImpl singleton class.
      */
-    public static synchronized ProtoLogImpl getSingleInstance() {
+    public static synchronized IProtoLog getSingleInstance() {
         if (sServiceInstance == null) {
-            sServiceInstance = new ProtoLogImpl(
-                    new File(LOG_FILENAME)
-                    , BUFFER_CAPACITY
-                    , new ProtoLogViewerConfigReader()
-                    , PER_CHUNK_SIZE);
+            if (android.tracing.Flags.perfettoProtolog()) {
+                sServiceInstance =
+                        new PerfettoProtoLogImpl(sViewerConfigPath);
+            } else {
+                sServiceInstance =
+                        new LegacyProtoLogImpl(sLegacyOutputFilePath, sLegacyViewerConfigPath);
+            }
         }
         return sServiceInstance;
     }
 
     @VisibleForTesting
-    public static synchronized void setSingleInstance(@Nullable ProtoLogImpl instance) {
+    public static synchronized void setSingleInstance(@Nullable IProtoLog instance) {
         sServiceInstance = instance;
     }
-
-    public ProtoLogImpl(File logFile, int bufferCapacity,
-            ProtoLogViewerConfigReader viewConfigReader, int perChunkSize) {
-        super(logFile, VIEWER_CONFIG_FILENAME, bufferCapacity, viewConfigReader, perChunkSize);
-  }
 }
 
diff --git a/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java b/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java
index aa30a77..3c206ac 100644
--- a/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java
+++ b/core/java/com/android/internal/protolog/ProtoLogViewerConfigReader.java
@@ -1,48 +1,30 @@
-/*
- * Copyright (C) 2020 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.internal.protolog;
 
-import android.annotation.Nullable;
-import android.util.Slog;
+import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.MESSAGES;
+import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.MessageData.MESSAGE;
+import static perfetto.protos.PerfettoTrace.ProtoLogViewerConfig.MessageData.MESSAGE_ID;
 
-import org.json.JSONException;
-import org.json.JSONObject;
+import android.util.proto.ProtoInputStream;
 
-import java.io.BufferedReader;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
+import com.android.internal.protolog.common.ILogger;
+
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.PrintWriter;
-import java.util.Iterator;
 import java.util.Map;
-import java.util.TreeMap;
-import java.util.zip.GZIPInputStream;
 
-/**
- * Handles loading and parsing of ProtoLog viewer configuration.
- */
 public class ProtoLogViewerConfigReader {
-    private static final String TAG = "ProtoLogViewerConfigReader";
-    private Map<Integer, String> mLogMessageMap = null;
+    private final ViewerConfigInputStreamProvider mViewerConfigInputStreamProvider;
+    private Map<Long, String> mLogMessageMap = null;
 
-    /** Returns message format string for its hash or null if unavailable. */
-    public synchronized String getViewerString(int messageHash) {
+    public ProtoLogViewerConfigReader(
+            ViewerConfigInputStreamProvider viewerConfigInputStreamProvider) {
+        this.mViewerConfigInputStreamProvider = viewerConfigInputStreamProvider;
+    }
+
+    /**
+     * Returns message format string for its hash or null if unavailable
+     * or the viewer config is not loaded into memory.
+     */
+    public synchronized String getViewerString(long messageHash) {
         if (mLogMessageMap != null) {
             return mLogMessageMap.get(messageHash);
         } else {
@@ -51,75 +33,61 @@
     }
 
     /**
-     * Reads the specified viewer configuration file. Does nothing if the config is already loaded.
+     * Loads the viewer config into memory. No-op if already loaded in memory.
      */
-    public synchronized void loadViewerConfig(PrintWriter pw, String viewerConfigFilename) {
-        try {
-            loadViewerConfig(new GZIPInputStream(new FileInputStream(viewerConfigFilename)));
-            logAndPrintln(pw, "Loaded " + mLogMessageMap.size()
-                    + " log definitions from " + viewerConfigFilename);
-        } catch (FileNotFoundException e) {
-            logAndPrintln(pw, "Unable to load log definitions: File "
-                    + viewerConfigFilename + " not found." + e);
-        } catch (IOException e) {
-            logAndPrintln(pw, "Unable to load log definitions: IOException while reading "
-                    + viewerConfigFilename + ". " + e);
-        } catch (JSONException e) {
-            logAndPrintln(pw, "Unable to load log definitions: JSON parsing exception while reading "
-                    + viewerConfigFilename + ". " + e);
-        }
-    }
-
-    /**
-     * Reads the specified viewer configuration input stream.
-     * Does nothing if the config is already loaded.
-     */
-    public synchronized void loadViewerConfig(InputStream viewerConfigInputStream)
-            throws IOException, JSONException {
+    public synchronized void loadViewerConfig(ILogger logger) {
         if (mLogMessageMap != null) {
             return;
         }
-        InputStreamReader config = new InputStreamReader(viewerConfigInputStream);
-        BufferedReader reader = new BufferedReader(config);
-        StringBuilder builder = new StringBuilder();
-        String line;
-        while ((line = reader.readLine()) != null) {
-            builder.append(line).append('\n');
-        }
-        reader.close();
-        JSONObject json = new JSONObject(builder.toString());
-        JSONObject messages = json.getJSONObject("messages");
 
-        mLogMessageMap = new TreeMap<>();
-        Iterator it = messages.keys();
-        while (it.hasNext()) {
-            String key = (String) it.next();
-            try {
-                int hash = Integer.parseInt(key);
-                JSONObject val = messages.getJSONObject(key);
-                String msg = val.getString("message");
-                mLogMessageMap.put(hash, msg);
-            } catch (NumberFormatException expected) {
-                // Not a messageHash - skip it
-            }
+        try {
+            doLoadViewerConfig();
+            logger.log("Loaded " + mLogMessageMap.size() + " log definitions");
+        } catch (IOException e) {
+            logger.log("Unable to load log definitions: "
+                    + "IOException while processing viewer config" + e);
         }
     }
 
     /**
-     * Returns the number of loaded log definitions kept in memory.
+     * Unload the viewer config from memory.
      */
-    public synchronized int knownViewerStringsNumber() {
-        if (mLogMessageMap != null) {
-            return mLogMessageMap.size();
-        }
-        return 0;
+    public synchronized void unloadViewerConfig() {
+        mLogMessageMap = null;
     }
 
-    static void logAndPrintln(@Nullable PrintWriter pw, String msg) {
-        Slog.i(TAG, msg);
-        if (pw != null) {
-            pw.println(msg);
-            pw.flush();
+    private void doLoadViewerConfig() throws IOException {
+        final ProtoInputStream pis = mViewerConfigInputStreamProvider.getInputStream();
+
+        while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            if (pis.getFieldNumber() == (int) MESSAGES) {
+                final long inMessageToken = pis.start(MESSAGES);
+
+                long messageId = 0;
+                String message = null;
+                while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+                    switch (pis.getFieldNumber()) {
+                        case (int) MESSAGE_ID:
+                            messageId = pis.readLong(MESSAGE_ID);
+                            break;
+                        case (int) MESSAGE:
+                            message = pis.readString(MESSAGE);
+                            break;
+                    }
+                }
+
+                if (messageId == 0) {
+                    throw new IOException("Failed to get message id");
+                }
+
+                if (message == null) {
+                    throw new IOException("Failed to get message string");
+                }
+
+                mLogMessageMap.put(messageId, message);
+
+                pis.end(inMessageToken);
+            }
         }
     }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/core/java/com/android/internal/protolog/ViewerConfigInputStreamProvider.java
similarity index 61%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
copy to core/java/com/android/internal/protolog/ViewerConfigInputStreamProvider.java
index b370859..334f548 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/core/java/com/android/internal/protolog/ViewerConfigInputStreamProvider.java
@@ -14,14 +14,13 @@
  * limitations under the License.
  */
 
-package com.android.systemui.keyguard.ui.viewmodel
+package com.android.internal.protolog;
 
-import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
-import com.android.systemui.kosmos.Kosmos
+import android.util.proto.ProtoInputStream;
 
-val Kosmos.dreamingToGlanceableHubTransitionViewModel by
-    Kosmos.Fixture {
-        DreamingToGlanceableHubTransitionViewModel(
-            animationFlow = keyguardTransitionAnimationFlow,
-        )
-    }
+public interface ViewerConfigInputStreamProvider {
+    /**
+     * @return a ProtoInputStream.
+     */
+    ProtoInputStream getInputStream();
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/core/java/com/android/internal/protolog/common/ILogger.java
similarity index 61%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
copy to core/java/com/android/internal/protolog/common/ILogger.java
index b370859..cc6fa5e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/core/java/com/android/internal/protolog/common/ILogger.java
@@ -14,14 +14,12 @@
  * limitations under the License.
  */
 
-package com.android.systemui.keyguard.ui.viewmodel
+package com.android.internal.protolog.common;
 
-import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
-import com.android.systemui.kosmos.Kosmos
-
-val Kosmos.dreamingToGlanceableHubTransitionViewModel by
-    Kosmos.Fixture {
-        DreamingToGlanceableHubTransitionViewModel(
-            animationFlow = keyguardTransitionAnimationFlow,
-        )
-    }
+public interface ILogger {
+    /**
+     * Log a message.
+     * @param message The log message.
+     */
+    void log(String message);
+}
diff --git a/core/java/com/android/internal/protolog/common/IProtoLog.java b/core/java/com/android/internal/protolog/common/IProtoLog.java
new file mode 100644
index 0000000..c06d14b
--- /dev/null
+++ b/core/java/com/android/internal/protolog/common/IProtoLog.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.protolog.common;
+
+/**
+ * Interface for ProtoLog implementations.
+ */
+public interface IProtoLog {
+
+    /**
+     * Log a ProtoLog message
+     * @param logLevel Log level of the proto message.
+     * @param group The group this message belongs to.
+     * @param messageHash The hash of the message.
+     * @param paramsMask The parameters mask of the message.
+     * @param messageString The message string.
+     * @param args The arguments of the message.
+     */
+    void log(LogLevel logLevel, IProtoLogGroup group, long messageHash, int paramsMask,
+             String messageString, Object[] args);
+
+    /**
+     * Check if ProtoLog is tracing.
+     * @return true iff a ProtoLog tracing session is active.
+     */
+    boolean isProtoEnabled();
+
+    /**
+     * Start logging log groups to logcat
+     * @param groups Groups to start text logging for
+     * @return status code
+     */
+    int startLoggingToLogcat(String[] groups, ILogger logger);
+
+    /**
+     * Stop logging log groups to logcat
+     * @param groups Groups to start text logging for
+     * @return status code
+     */
+    int stopLoggingToLogcat(String[] groups, ILogger logger);
+}
diff --git a/core/java/com/android/internal/protolog/common/IProtoLogGroup.java b/core/java/com/android/internal/protolog/common/IProtoLogGroup.java
index e3db468..4e9686f99 100644
--- a/core/java/com/android/internal/protolog/common/IProtoLogGroup.java
+++ b/core/java/com/android/internal/protolog/common/IProtoLogGroup.java
@@ -26,6 +26,7 @@
     boolean isEnabled();
 
     /**
+     * @deprecated TODO(b/324128613) remove once we migrate fully to Perfetto
      * is binary logging enabled for the group.
      */
     boolean isLogToProto();
diff --git a/core/java/com/android/internal/protolog/common/ProtoLog.java b/core/java/com/android/internal/protolog/common/ProtoLog.java
index 8870096..18e3f66 100644
--- a/core/java/com/android/internal/protolog/common/ProtoLog.java
+++ b/core/java/com/android/internal/protolog/common/ProtoLog.java
@@ -16,8 +16,6 @@
 
 package com.android.internal.protolog.common;
 
-import android.util.Log;
-
 /**
  * ProtoLog API - exposes static logging methods. Usage of this API is similar
  * to {@code android.utils.Log} class. Instead of plain text log messages each call consists of
@@ -55,9 +53,6 @@
             throw new UnsupportedOperationException(
                     "ProtoLog calls MUST be processed with ProtoLogTool");
         }
-        if (group.isLogToLogcat()) {
-            Log.d(group.getTag(), String.format(messageString, args));
-        }
     }
 
     /**
@@ -73,9 +68,6 @@
             throw new UnsupportedOperationException(
                     "ProtoLog calls MUST be processed with ProtoLogTool");
         }
-        if (group.isLogToLogcat()) {
-            Log.v(group.getTag(), String.format(messageString, args));
-        }
     }
 
     /**
@@ -91,9 +83,6 @@
             throw new UnsupportedOperationException(
                     "ProtoLog calls MUST be processed with ProtoLogTool");
         }
-        if (group.isLogToLogcat()) {
-            Log.i(group.getTag(), String.format(messageString, args));
-        }
     }
 
     /**
@@ -109,9 +98,6 @@
             throw new UnsupportedOperationException(
                     "ProtoLog calls MUST be processed with ProtoLogTool");
         }
-        if (group.isLogToLogcat()) {
-            Log.w(group.getTag(), String.format(messageString, args));
-        }
     }
 
     /**
@@ -127,9 +113,6 @@
             throw new UnsupportedOperationException(
                     "ProtoLog calls MUST be processed with ProtoLogTool");
         }
-        if (group.isLogToLogcat()) {
-            Log.e(group.getTag(), String.format(messageString, args));
-        }
     }
 
     /**
@@ -145,8 +128,30 @@
             throw new UnsupportedOperationException(
                     "ProtoLog calls MUST be processed with ProtoLogTool");
         }
-        if (group.isLogToLogcat()) {
-            Log.wtf(group.getTag(), String.format(messageString, args));
+    }
+
+    /**
+     * Check if ProtoLog isEnabled for a target group.
+     * @param group Group to check enable status of.
+     * @return true iff this is being logged.
+     */
+    public static boolean isEnabled(IProtoLogGroup group) {
+        if (REQUIRE_PROTOLOGTOOL) {
+            throw new UnsupportedOperationException(
+                    "ProtoLog calls MUST be processed with ProtoLogTool");
         }
+        return false;
+    }
+
+    /**
+     * Get the single ProtoLog instance.
+     * @return A singleton instance of ProtoLog.
+     */
+    public static IProtoLog getSingleInstance() {
+        if (REQUIRE_PROTOLOGTOOL) {
+            throw new UnsupportedOperationException(
+                    "ProtoLog calls MUST be processed with ProtoLogTool");
+        }
+        return null;
     }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/core/java/com/android/internal/protolog/common/ProtoLogToolInjected.java
similarity index 61%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
copy to core/java/com/android/internal/protolog/common/ProtoLogToolInjected.java
index b370859..ffd0d76 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/core/java/com/android/internal/protolog/common/ProtoLogToolInjected.java
@@ -14,14 +14,15 @@
  * limitations under the License.
  */
 
-package com.android.systemui.keyguard.ui.viewmodel
 
-import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
-import com.android.systemui.kosmos.Kosmos
+package com.android.internal.protolog.common;
 
-val Kosmos.dreamingToGlanceableHubTransitionViewModel by
-    Kosmos.Fixture {
-        DreamingToGlanceableHubTransitionViewModel(
-            animationFlow = keyguardTransitionAnimationFlow,
-        )
-    }
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+@Target({ElementType.FIELD, ElementType.PARAMETER})
+public @interface ProtoLogToolInjected {
+    enum Value { VIEWER_CONFIG_PATH, LEGACY_OUTPUT_FILE_PATH, LEGACY_VIEWER_CONFIG_PATH }
+
+    Value value();
+}
diff --git a/core/jni/LayoutlibLoader.cpp b/core/jni/LayoutlibLoader.cpp
index 01e9f43..06d5eb3 100644
--- a/core/jni/LayoutlibLoader.cpp
+++ b/core/jni/LayoutlibLoader.cpp
@@ -362,6 +362,22 @@
 
 using namespace android;
 
+// Called right before aborting by LOG_ALWAYS_FATAL. Print the pending exception.
+void abort_handler(const char* abort_message) {
+    ALOGE("Abort to abort the process...");
+
+    JNIEnv* env = NULL;
+    if (javaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+        ALOGE("vm->GetEnv() failed");
+        return;
+    }
+    if (env->ExceptionOccurred() != NULL) {
+        ALOGE("Pending exception:");
+        env->ExceptionDescribe();
+    }
+    ALOGE("Aborting because: %s", abort_message);
+}
+
 JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) {
     javaVM = vm;
     JNIEnv* env = nullptr;
@@ -369,6 +385,8 @@
         return JNI_ERR;
     }
 
+    __android_log_set_aborter(abort_handler);
+
     init_android_graphics();
 
     // Configuration is stored as java System properties.
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index 285dee3..b39d5cf 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -85,9 +85,24 @@
 
 ScopedLocalRef<jobject> android_view_MotionEvent_obtainAsCopy(JNIEnv* env,
                                                               const MotionEvent& event) {
-    std::unique_ptr<MotionEvent> destEvent = std::make_unique<MotionEvent>();
+    ScopedLocalRef<jobject> eventObj(env,
+                                     env->CallStaticObjectMethod(gMotionEventClassInfo.clazz,
+                                                                 gMotionEventClassInfo.obtain));
+    if (env->ExceptionCheck() || !eventObj.get()) {
+        ALOGE("An exception occurred while obtaining a motion event.");
+        LOGE_EX(env);
+        env->ExceptionClear();
+        return ScopedLocalRef<jobject>(env);
+    }
+
+    MotionEvent* destEvent = android_view_MotionEvent_getNativePtr(env, eventObj.get());
+    if (!destEvent) {
+        destEvent = new MotionEvent();
+        android_view_MotionEvent_setNativePtr(env, eventObj, destEvent);
+    }
+
     destEvent->copyFrom(&event, true);
-    return android_view_MotionEvent_obtainFromNative(env, std::move(destEvent));
+    return eventObj;
 }
 
 ScopedLocalRef<jobject> android_view_MotionEvent_obtainFromNative(
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 0938ce17..3ed9f49 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1965,7 +1965,7 @@
 
     // If this zygote isn't root, it won't be able to create a process group,
     // since the directory is owned by root.
-    if (!is_system_server && getuid() == 0) {
+    if (getuid() == 0) {
         const int rc = createProcessGroup(uid, getpid());
         if (rc != 0) {
             fail_fn(rc == -EROFS ? CREATE_ERROR("createProcessGroup failed, kernel missing "
diff --git a/core/proto/android/internal/protolog.proto b/core/proto/android/internal/protolog.proto
index fee7a87..9e205e2 100644
--- a/core/proto/android/internal/protolog.proto
+++ b/core/proto/android/internal/protolog.proto
@@ -27,7 +27,7 @@
     option (.android.msg_privacy).dest = DEST_LOCAL;
 
     /* log statement identifier, created from message string and log level. */
-    optional sfixed32 message_hash = 1;
+    optional sfixed32 message_hash_legacy = 1 [deprecated = true];
     /* log time, relative to the elapsed system time clock. */
     optional fixed64 elapsed_realtime_nanos = 2;
     /* string parameters passed to the log call. */
@@ -38,6 +38,9 @@
     repeated double double_params = 5 [packed=true];
     /* boolean parameters passed to the log call. */
     repeated bool boolean_params = 6 [packed=true];
+
+    /* log statement identifier, created from message string and log level. */
+    optional sfixed64 message_hash = 7;
 }
 
 /* represents a log file containing ProtoLog log entries.
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 4fc9b40..763d9ce 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -101,6 +101,7 @@
         optional SettingProto accessibility_magnification_two_finger_triple_tap_enabled = 53 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto qs_targets = 54 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto accessibility_pinch_to_zoom_anywhere_enabled = 55 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto accessibility_single_finger_panning_enabled = 56 [ (android.privacy).dest = DEST_AUTOMATIC ];
 
     }
     optional Accessibility accessibility = 2;
diff --git a/core/res/Android.bp b/core/res/Android.bp
index 277824c..e2e419f 100644
--- a/core/res/Android.bp
+++ b/core/res/Android.bp
@@ -159,7 +159,7 @@
         "android.content.pm.flags-aconfig",
         "android.provider.flags-aconfig",
         "camera_platform_flags",
-        "com.android.net.flags-aconfig",
+        "android.net.platform.flags-aconfig",
         "com.android.window.flags.window-aconfig",
     ],
 }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 8720f94..487b5be 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2281,7 +2281,7 @@
     <!-- @SystemApi @hide Allows changing Thread network state and access to Thread network
         credentials such as Network Key and PSKc.
         <p>Not for use by third-party applications.
-        @FlaggedApi("com.android.net.thread.flags.thread_enabled_platform") -->
+        @FlaggedApi("com.android.net.thread.platform.flags.thread_enabled_platform") -->
     <permission android:name="android.permission.THREAD_NETWORK_PRIVILEGED"
                 android:protectionLevel="signature|privileged" />
 
@@ -2331,12 +2331,12 @@
     <!-- Allows system apps to call methods to register itself as a mDNS offload engine.
         <p>Not for use by third-party or privileged applications.
         @SystemApi
-        @FlaggedApi("com.android.net.flags.register_nsd_offload_engine")
+        @FlaggedApi("android.net.platform.flags.register_nsd_offload_engine")
         @hide This should only be used by system apps.
     -->
     <permission android:name="android.permission.REGISTER_NSD_OFFLOAD_ENGINE"
         android:protectionLevel="signature"
-        android:featureFlag="com.android.net.flags.register_nsd_offload_engine" />
+        android:featureFlag="android.net.platform.flags.register_nsd_offload_engine" />
 
     <!-- ======================================= -->
     <!-- Permissions for short range, peripheral networks -->
@@ -3629,7 +3629,7 @@
 
     <!-- Allows an application to set policy related to <a
     href="https://www.threadgroup.org">Thread</a> network.
-        @FlaggedApi("com.android.net.thread.flags.thread_user_restriction_enabled")
+        @FlaggedApi("com.android.net.thread.platform.flags.thread_user_restriction_enabled")
     -->
     <permission android:name="android.permission.MANAGE_DEVICE_POLICY_THREAD_NETWORK"
                 android:protectionLevel="internal|role" />
@@ -7986,7 +7986,7 @@
         @hide
       -->
     <permission android:name="android.permission.GET_APP_METADATA"
-                android:protectionLevel="signature|installer" />
+                android:protectionLevel="signature|installer|verifier" />
 
     <!-- @hide @SystemApi Allows an application to stage HealthConnect's remote data so that
          HealthConnect can later integrate it. -->
diff --git a/core/res/res/drawable/pointer_wait_vector.xml b/core/res/res/drawable/pointer_wait_vector.xml
new file mode 100644
index 0000000..4de0690
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="utf-8"?>
+<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false">
+  <item android:drawable="@drawable/pointer_wait_vector_0" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_1" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_2" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_3" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_4" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_5" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_6" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_7" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_8" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_9" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_10" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_11" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_12" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_13" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_14" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_15" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_16" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_17" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_18" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_19" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_20" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_21" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_22" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_23" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_24" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_25" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_26" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_27" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_28" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_29" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_30" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_31" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_32" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_33" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_34" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_35" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_36" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_37" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_38" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_39" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_40" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_41" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_42" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_43" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_44" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_45" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_46" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_47" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_48" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_49" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_50" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_51" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_52" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_53" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_54" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_55" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_56" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_57" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_58" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_59" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_60" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_61" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_62" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_63" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_64" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_65" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_66" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_67" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_68" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_69" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_70" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_71" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_72" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_73" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_74" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_75" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_76" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_77" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_78" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_79" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_80" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_81" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_82" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_83" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_84" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_85" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_86" android:duration="16"/>
+  <item android:drawable="@drawable/pointer_wait_vector_87" android:duration="16"/>
+</animation-list>
diff --git a/core/res/res/drawable/pointer_wait_vector_0.xml b/core/res/res/drawable/pointer_wait_vector_0.xml
new file mode 100644
index 0000000..4bfbc9f
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_0.xml
@@ -0,0 +1,27 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.116,18.654a1.78,1.78 0,1 0,0.061 3.561,1.78 1.78,0 0,0 -0.061,-3.561m-7.194,-1.73a1.781,1.781 0,1 0,2.594 2.441,1.781 1.781,0 0,0 -2.594,-2.441"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.294,7.294a1.78,1.78 0,1 0,-2.517 -2.519,1.78 1.78,0 0,0 2.517,2.519"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.225,7.294a1.78,1.78 0,1 0,-2.517 -2.519,1.78 1.78,0 0,0 2.517,2.519"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.436,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.747,16.665a1.78,1.78 0,1 0,2.539 2.497,1.78 1.78,0 0,0 -2.539,-2.497"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_1.xml b/core/res/res/drawable/pointer_wait_vector_1.xml
new file mode 100644
index 0000000..bab91e1
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_1.xml
@@ -0,0 +1,21 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.174,18.653a1.782,1.782 0,1 0,0.094 3.562,1.782 1.782,0 0,0 -0.094,-3.562m-7.187,-1.637a1.782,1.782 0,1 0,2.627 2.407,1.782 1.782,0 0,0 -2.627,-2.407"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.294,7.294a1.78,1.78 0,1 0,-2.517 -2.519,1.78 1.78,0 0,0 2.517,2.519"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.225,7.294a1.78,1.78 0,1 0,-2.517 -2.519,1.78 1.78,0 0,0 2.517,2.519m1.203,2.888a1.78,1.78 0,1 0,0.016 3.562,1.78 1.78,0 1,0 -0.016,-3.562m-3.641,6.441a1.782,1.782 0,1 0,2.564 2.475,1.782 1.782,0 0,0 -2.564,-2.475"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_10.xml b/core/res/res/drawable/pointer_wait_vector_10.xml
new file mode 100644
index 0000000..ae3e360
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_10.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M13.028,20.374m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.952,18.76m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12.066m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.957,6.113m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.779,3.566m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.7,5.78m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.42,11.485m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.462,17.423m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_11.xml b/core/res/res/drawable/pointer_wait_vector_11.xml
new file mode 100644
index 0000000..d2c014d
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_11.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M13.101,20.364m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.101,18.868m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12.074m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.931,6.139m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.706,3.569m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.646,5.731m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.41,11.338m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.509,17.366m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_12.xml b/core/res/res/drawable/pointer_wait_vector_12.xml
new file mode 100644
index 0000000..e9a36c0
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_12.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M13.247,20.344m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.222,18.953m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.564,12.147m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.88,6.193m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.632,3.571m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.591,5.681m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.404,11.265m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.602,17.252m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_13.xml b/core/res/res/drawable/pointer_wait_vector_13.xml
new file mode 100644
index 0000000..5800f39
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_13.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M13.392,20.321m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.344,19.035m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.565,12.184m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.83,6.246m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.559,3.575m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.535,5.633m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.39,11.118m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.693,17.136m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_14.xml b/core/res/res/drawable/pointer_wait_vector_14.xml
new file mode 100644
index 0000000..3566aaf
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_14.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M13.537,20.295m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.467,19.115m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.567,12.258m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.755,6.327m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.485,3.579m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.423,5.537m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.386,11.082m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.759,17.048m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_15.xml b/core/res/res/drawable/pointer_wait_vector_15.xml
new file mode 100644
index 0000000..c995faf
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_15.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M13.682,20.267m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.718,19.269m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.568,12.295m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.73,6.355m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.412,3.584m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.367,5.49m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.369,10.935m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.847,16.929m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_16.xml b/core/res/res/drawable/pointer_wait_vector_16.xml
new file mode 100644
index 0000000..1793282
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_16.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M13.826,20.237m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.846,19.343m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.57,12.331m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.706,6.382m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.338,3.589m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.31,5.444m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.354,10.826m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.91,16.839m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_17.xml b/core/res/res/drawable/pointer_wait_vector_17.xml
new file mode 100644
index 0000000..59772f5
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_17.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M13.969,20.204m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.974,19.414m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.571,12.368m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.681,6.41m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.191,3.602m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.194,5.352m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.333,10.68m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.994,16.718m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_18.xml b/core/res/res/drawable/pointer_wait_vector_18.xml
new file mode 100644
index 0000000..1bbb242
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_18.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M14.184,20.149m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M8.236,19.55m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.575,12.442m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.585,6.521m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.118,3.61m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.136,5.307m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.315,10.571m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.075,16.595m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_19.xml b/core/res/res/drawable/pointer_wait_vector_19.xml
new file mode 100644
index 0000000..b8e0dd5
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_19.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M14.325,20.11m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M8.434,19.646m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.581,12.552m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.537,6.577m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.972,3.626m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.959,5.175m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.282,10.39m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.193,16.408m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_2.xml b/core/res/res/drawable/pointer_wait_vector_2.xml
new file mode 100644
index 0000000..5c4606f
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_2.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.331,20.43m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.355,18.269m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.035m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.435,11.89m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.094,17.834m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_20.xml b/core/res/res/drawable/pointer_wait_vector_20.xml
new file mode 100644
index 0000000..b3ac2dab
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_20.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M14.607,20.024m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M8.703,19.766m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.592,12.699m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.49,6.634m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.899,3.636m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.899,5.132m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.252,10.246m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.269,16.282m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_21.xml b/core/res/res/drawable/pointer_wait_vector_21.xml
new file mode 100644
index 0000000..884476e
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_21.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M14.816,19.953m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M8.908,19.849m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.589,12.662m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.443,6.691m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.753,3.656m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.718,5.006m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.22,10.102m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.414,16.025m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_22.xml b/core/res/res/drawable/pointer_wait_vector_22.xml
new file mode 100644
index 0000000..20660ca
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_22.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M15.092,19.849m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.184,19.952m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.617,12.955m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.352,6.806m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.608,3.679m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.595,4.925m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.149,9.816m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.483,15.896m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_23.xml b/core/res/res/drawable/pointer_wait_vector_23.xml
new file mode 100644
index 0000000..6b594ee7
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_23.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M15.296,19.766m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.533,20.068m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.609,12.882m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.262,6.923m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.463,3.705m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.471,4.845m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.11,9.675m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.614,15.632m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_24.xml b/core/res/res/drawable/pointer_wait_vector_24.xml
new file mode 100644
index 0000000..a35203e
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_24.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M15.632,19.615m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.816,20.149m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.626,13.028m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.175,7.041m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.318,3.733m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.346,4.769m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.046,9.463m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.677,15.498m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_25.xml b/core/res/res/drawable/pointer_wait_vector_25.xml
new file mode 100644
index 0000000..df8549a
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_25.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M15.896,19.483m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.174,20.236m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.645,13.174m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.089,7.161m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.174,3.763m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.219,4.694m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.977,9.253m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.794,15.228m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_26.xml b/core/res/res/drawable/pointer_wait_vector_26.xml
new file mode 100644
index 0000000..0abb7d41
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_26.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M16.154,19.343m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.535,20.308m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.667,13.32m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.006,7.282m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.959,3.814m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M15.961,4.551m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.902,9.045m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.902,14.955m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_27.xml b/core/res/res/drawable/pointer_wait_vector_27.xml
new file mode 100644
index 0000000..bde2425
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_27.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M16.471,19.155m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.972,20.374m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.691,13.465m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.885,7.467m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.817,3.851m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M15.831,4.483m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.85,8.908m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.023,14.607m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_28.xml b/core/res/res/drawable/pointer_wait_vector_28.xml
new file mode 100644
index 0000000..19cb410
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_28.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M16.778,18.953m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.411,20.416m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.718,13.61m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.807,7.592m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.604,3.911m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M15.566,4.354m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.677,8.502m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.109,14.325m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_29.xml b/core/res/res/drawable/pointer_wait_vector_29.xml
new file mode 100644
index 0000000..5d6776f
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_29.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M17.136,18.693m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.926,20.436m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.748,13.754m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.731,7.718m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.463,3.954m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M15.365,4.263m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.55,8.236m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.203,13.969m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_3.xml b/core/res/res/drawable/pointer_wait_vector_3.xml
new file mode 100644
index 0000000..8a19401
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_3.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.368,20.429m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.437,18.343m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.94,6.009m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.435,11.853m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.119,17.807m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_30.xml b/core/res/res/drawable/pointer_wait_vector_30.xml
new file mode 100644
index 0000000..56dcdc2
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_30.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M17.479,18.415m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12.441,20.425m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.796,13.969m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.586,7.974m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.184,4.047m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M15.092,4.151m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.414,7.975m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.281,13.61m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_31.xml b/core/res/res/drawable/pointer_wait_vector_31.xml
new file mode 100644
index 0000000..5687a9b
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_31.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M17.807,18.12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M13.028,20.373m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.832,14.112m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.517,8.104m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M8.908,4.15m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M14.817,4.047m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.269,7.718m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.344,13.247m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_32.xml b/core/res/res/drawable/pointer_wait_vector_32.xml
new file mode 100644
index 0000000..cb626e4
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_32.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M18.17,17.754m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M13.61,20.281m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.87,14.254m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.417,8.302m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M8.704,4.234m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M14.537,3.954m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.076,7.405m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.397,12.809m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_33.xml b/core/res/res/drawable/pointer_wait_vector_33.xml
new file mode 100644
index 0000000..052f973
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_33.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M18.51,17.366m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M14.183,20.149m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.954,14.537m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.323,8.501m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M8.435,4.354m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M14.184,3.851m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.868,7.101m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.428,12.368m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_34.xml b/core/res/res/drawable/pointer_wait_vector_34.xml
new file mode 100644
index 0000000..9e665756
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_34.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M18.911,16.839m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M14.885,19.928m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.999,14.677m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.206,8.771m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M8.17,4.483m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M13.826,3.764m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.603,6.748m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.433,11.779m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_35.xml b/core/res/res/drawable/pointer_wait_vector_35.xml
new file mode 100644
index 0000000..1d063fc
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_35.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M19.232,16.345m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M15.566,19.646m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.098,14.955m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.098,9.045m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.846,4.657m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M13.465,3.692m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.27,6.355m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.41,11.338m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_36.xml b/core/res/res/drawable/pointer_wait_vector_36.xml
new file mode 100644
index 0000000..db0ad1c
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_36.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M19.583,15.698m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.345,19.232m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.205,15.229m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.999,9.323m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.592,4.807m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M13.028,3.626m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.035m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.344,10.753m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_37.xml b/core/res/res/drawable/pointer_wait_vector_37.xml
new file mode 100644
index 0000000..ee944a6
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_37.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M19.876,15.023m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.077,18.738m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.323,15.499m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.911,9.604m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.221,5.047m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12.589,3.584m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.59,5.681m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.236,10.174m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_38.xml b/core/res/res/drawable/pointer_wait_vector_38.xml
new file mode 100644
index 0000000..a347a36
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_38.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M20.129,14.255m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.861,18.069m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.45,15.764m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.796,10.031m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.864,5.307m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12.147,3.565m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.136,5.307m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.046,9.463m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_39.xml b/core/res/res/drawable/pointer_wait_vector_39.xml
new file mode 100644
index 0000000..2c86f0d
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_39.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M20.321,13.392m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.557,17.309m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.586,16.026m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.705,10.462m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.521,5.585m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.559,3.575m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.657,4.965m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.766,8.704m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_4.xml b/core/res/res/drawable/pointer_wait_vector_4.xml
new file mode 100644
index 0000000..a6690c0
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_4.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.441,20.425m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.493,18.391m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.914,5.983m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.433,11.772m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.17,17.754m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_40.xml b/core/res/res/drawable/pointer_wait_vector_40.xml
new file mode 100644
index 0000000..953fdc1
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_40.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M20.428,12.368m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.232,16.345m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.731,16.282m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.656,10.753m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.193,5.88m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.972,3.626m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.026,4.586m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.449,8.039m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_41.xml b/core/res/res/drawable/pointer_wait_vector_41.xml
new file mode 100644
index 0000000..a1b17fa
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_41.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M20.41,11.338m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.766,15.296m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.924,16.595m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.602,11.191m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.83,6.246m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.39,3.719m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M15.364,4.263m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.994,7.282m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_42.xml b/core/res/res/drawable/pointer_wait_vector_42.xml
new file mode 100644
index 0000000..4de9b8d
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_42.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M20.244,10.21m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.14,14.219m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.153,16.929m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.571,11.632m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.49,6.634m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.817,3.851m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M14.677,4m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.367,6.465m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_43.xml b/core/res/res/drawable/pointer_wait_vector_43.xml
new file mode 100644
index 0000000..38187fe
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_43.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M19.94,9.149m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.365,13.101m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.397,17.252m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.566,12.221m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.089,7.161m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.115,4.072m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M13.826,3.763m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.645,5.73m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_44.xml b/core/res/res/drawable/pointer_wait_vector_44.xml
new file mode 100644
index 0000000..890ba7e
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_44.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M19.466,8.072m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.436,12.073m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.73,17.645m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.589,12.662m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.768,7.655m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M8.368,4.385m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12.882,3.61m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.839,5.089m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_45.xml b/core/res/res/drawable/pointer_wait_vector_45.xml
new file mode 100644
index 0000000..309ac08
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_45.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M18.847,7.071m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.382,11.045m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.139,18.069m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.656,13.247m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.417,8.302m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.592,4.807m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.853,3.565m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M15.83,4.483m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_46.xml b/core/res/res/drawable/pointer_wait_vector_46.xml
new file mode 100644
index 0000000..5a9bf70
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_46.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M18.195,6.273m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.237,10.174m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.465,18.367m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.797,13.969m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.124,8.977m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.864,5.307m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.826,3.646m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M14.747,4.023m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_47.xml b/core/res/res/drawable/pointer_wait_vector_47.xml
new file mode 100644
index 0000000..0068f27
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_47.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M17.451,5.561m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.046,9.463m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.922,18.738m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.954,14.537m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.851,9.817m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.087,5.983m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.675,3.89m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M13.61,3.718m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_48.xml b/core/res/res/drawable/pointer_wait_vector_48.xml
new file mode 100644
index 0000000..6ece990
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_48.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M16.748,5.026m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.822,8.84m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.405,19.076m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.205,15.229m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.667,10.68m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.397,6.748m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M8.569,4.293m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12.588,3.584m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_49.xml b/core/res/res/drawable/pointer_wait_vector_49.xml
new file mode 100644
index 0000000..d444389
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_49.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M16.09,4.621m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.583,8.302m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.974,19.414m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.586,16.025m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.571,11.632m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.768,7.655m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.655,4.768m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.558,3.575m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_5.xml b/core/res/res/drawable/pointer_wait_vector_5.xml
new file mode 100644
index 0000000..4952fe5
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_5.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.515,20.421m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.577,18.463m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.877,5.947m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.433,11.779m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.22,17.7m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_50.xml b/core/res/res/drawable/pointer_wait_vector_50.xml
new file mode 100644
index 0000000..a85155f
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_50.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M15.499,4.323m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.343,7.846m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M8.636,19.737m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.047,16.778m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.589,12.662m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.234,8.704m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.634,5.49m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.608,3.679m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_51.xml b/core/res/res/drawable/pointer_wait_vector_51.xml
new file mode 100644
index 0000000..95b4aaa
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_51.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M14.885,4.072m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.155,7.529m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.393,20.024m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.585,17.479m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.748,13.754m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.851,9.817m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.88,6.193m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.816,3.851m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_52.xml b/core/res/res/drawable/pointer_wait_vector_52.xml
new file mode 100644
index 0000000..34619b5
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_52.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M14.396,3.911m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.953,7.221m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.246,20.252m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.3,18.22m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.072,14.885m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.636,10.899m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.307,6.864m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.114,4.072m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_53.xml b/core/res/res/drawable/pointer_wait_vector_53.xml
new file mode 100644
index 0000000..926b639
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_53.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M13.969,3.797m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.782,6.982m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.118,20.39m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.221,18.953m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.551,15.961m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.564,11.927m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.807,7.592m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M8.568,4.293m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_54.xml b/core/res/res/drawable/pointer_wait_vector_54.xml
new file mode 100644
index 0000000..c51851fc
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_54.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M13.61,3.718m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.603,6.748m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12.147,20.435m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M8.17,19.517m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.132,16.899m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.618,12.955m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.45,8.236m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M8.104,4.517m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_55.xml b/core/res/res/drawable/pointer_wait_vector_55.xml
new file mode 100644
index 0000000..cdf435f
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_55.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M13.247,3.656m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.463,6.577m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M13.247,20.344m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.253,19.977m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.83,17.754m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.748,13.754m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.178,8.84m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.686,4.749m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_56.xml b/core/res/res/drawable/pointer_wait_vector_56.xml
new file mode 100644
index 0000000..1528711
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_56.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M13.028,3.626m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.319,6.41m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M14.325,20.11m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.39,20.282m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.521,18.415m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.954,14.537m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.976,9.393m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.405,4.924m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_57.xml b/core/res/res/drawable/pointer_wait_vector_57.xml
new file mode 100644
index 0000000..1715db1
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_57.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.772,3.599m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.22,6.3m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M15.431,19.707m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.411,20.416m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.282,18.994m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.178,15.16m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.851,9.817m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.041,5.175m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_58.xml b/core/res/res/drawable/pointer_wait_vector_58.xml
new file mode 100644
index 0000000..83aec4b
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_58.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.589,3.584m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.12,6.193m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.471,19.155m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12.442,20.425m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M7.974,19.414m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.417,15.698m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.748,10.246m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.864,5.307m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_59.xml b/core/res/res/drawable/pointer_wait_vector_59.xml
new file mode 100644
index 0000000..2e5e472
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_59.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.442,3.575m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.069,6.139m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.309,18.556m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M13.465,20.308m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M8.568,19.707m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.657,16.154m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.679,10.608m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.634,5.49m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_6.xml b/core/res/res/drawable/pointer_wait_vector_6.xml
new file mode 100644
index 0000000..d4f57af
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_6.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.588,20.416m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.633,18.51m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.926,3.564m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.861,5.931m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.431,11.706m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.269,17.645m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_60.xml b/core/res/res/drawable/pointer_wait_vector_60.xml
new file mode 100644
index 0000000..4f25767
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_60.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.294,3.569m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.069,6.139m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.12,17.807m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M14.183,20.149m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.115,19.928m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M4.845,16.471m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.646,10.826m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.465,5.633m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_61.xml b/core/res/res/drawable/pointer_wait_vector_61.xml
new file mode 100644
index 0000000..7e06db4
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_61.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.147,3.565m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.017,6.087m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.738,17.077m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M14.885,19.928m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M9.604,20.089m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.047,16.779m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.61,11.118m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.355,5.73m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_62.xml b/core/res/res/drawable/pointer_wait_vector_62.xml
new file mode 100644
index 0000000..b3d0541
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_62.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.074,3.564m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.231,16.345m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M15.432,19.707m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.102,20.22m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.307,17.136m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.584,11.411m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.246,5.83m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_63.xml b/core/res/res/drawable/pointer_wait_vector_63.xml
new file mode 100644
index 0000000..ee09c25
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_63.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.583,15.698m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M15.961,19.449m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.39,20.282m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.397,17.252m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.575,11.558m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.193,5.88m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_64.xml b/core/res/res/drawable/pointer_wait_vector_64.xml
new file mode 100644
index 0000000..e87f94f
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_64.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M19.822,15.16m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.345,19.232m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.826,20.354m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.537,17.423m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.571,11.632m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.139,5.931m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_65.xml b/core/res/res/drawable/pointer_wait_vector_65.xml
new file mode 100644
index 0000000..b8407c44
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_65.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.023,14.607m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.718,18.994m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M10.972,20.374m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.681,17.59m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.569,11.706m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.087,5.983m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_66.xml b/core/res/res/drawable/pointer_wait_vector_66.xml
new file mode 100644
index 0000000..7e2448d
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_66.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.149,14.184m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M16.959,18.825m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.265,20.405m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.78,17.7m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.565,11.853m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_67.xml b/core/res/res/drawable/pointer_wait_vector_67.xml
new file mode 100644
index 0000000..615ac04
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_67.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.252,13.754m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.194,18.648m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.412,20.416m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.88,17.807m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_68.xml b/core/res/res/drawable/pointer_wait_vector_68.xml
new file mode 100644
index 0000000..0ba4634
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_68.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.308,13.465m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.366,18.51m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.632,20.429m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.931,17.861m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_69.xml b/core/res/res/drawable/pointer_wait_vector_69.xml
new file mode 100644
index 0000000..efa90bf
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_69.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.354,13.174m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.535,18.367m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.706,20.432m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.931,17.86m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_7.xml b/core/res/res/drawable/pointer_wait_vector_7.xml
new file mode 100644
index 0000000..86d571a
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_7.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.661,20.411m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.69,18.556m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.024,6.045m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.889,3.564m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.808,5.88m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.428,11.632m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.318,17.59m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_70.xml b/core/res/res/drawable/pointer_wait_vector_70.xml
new file mode 100644
index 0000000..4e58af5
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_70.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.39,12.882m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.645,18.27m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.853,20.435m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_71.xml b/core/res/res/drawable/pointer_wait_vector_71.xml
new file mode 100644
index 0000000..5a53434
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_71.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.416,12.589m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.754,18.17m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.853,20.435m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_72.xml b/core/res/res/drawable/pointer_wait_vector_72.xml
new file mode 100644
index 0000000..40fb5d3
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_72.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.425,12.442m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.807,18.12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_73.xml b/core/res/res/drawable/pointer_wait_vector_73.xml
new file mode 100644
index 0000000..933cc6a
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_73.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.429,12.368m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.861,18.069m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_74.xml b/core/res/res/drawable/pointer_wait_vector_74.xml
new file mode 100644
index 0000000..6c7fef2
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_74.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.431,12.294m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_75.xml b/core/res/res/drawable/pointer_wait_vector_75.xml
new file mode 100644
index 0000000..24e64e3
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_75.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.435,12.147m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_76.xml b/core/res/res/drawable/pointer_wait_vector_76.xml
new file mode 100644
index 0000000..2ede57d
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_76.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.436,12.073m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_77.xml b/core/res/res/drawable/pointer_wait_vector_77.xml
new file mode 100644
index 0000000..71f811a
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_77.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.436,12.037m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_78.xml b/core/res/res/drawable/pointer_wait_vector_78.xml
new file mode 100644
index 0000000..e2d56c6
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_78.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.437,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_79.xml b/core/res/res/drawable/pointer_wait_vector_79.xml
new file mode 100644
index 0000000..e2d56c6
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_79.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.437,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_8.xml b/core/res/res/drawable/pointer_wait_vector_8.xml
new file mode 100644
index 0000000..ebac749
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_8.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.808,20.398m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.806,18.648m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.008,6.061m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.853,3.565m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.754,5.83m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.425,11.558m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.367,17.535m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_80.xml b/core/res/res/drawable/pointer_wait_vector_80.xml
new file mode 100644
index 0000000..40fb5d3
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_80.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.425,12.442m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.807,18.12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_81.xml b/core/res/res/drawable/pointer_wait_vector_81.xml
new file mode 100644
index 0000000..933cc6a
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_81.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.429,12.368m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.861,18.069m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_82.xml b/core/res/res/drawable/pointer_wait_vector_82.xml
new file mode 100644
index 0000000..6c7fef2
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_82.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.431,12.294m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_83.xml b/core/res/res/drawable/pointer_wait_vector_83.xml
new file mode 100644
index 0000000..24e64e3
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_83.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.435,12.147m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_84.xml b/core/res/res/drawable/pointer_wait_vector_84.xml
new file mode 100644
index 0000000..2ede57d
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_84.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.436,12.073m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_85.xml b/core/res/res/drawable/pointer_wait_vector_85.xml
new file mode 100644
index 0000000..71f811a
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_85.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.436,12.037m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_86.xml b/core/res/res/drawable/pointer_wait_vector_86.xml
new file mode 100644
index 0000000..e2d56c6
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_86.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.437,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_87.xml b/core/res/res/drawable/pointer_wait_vector_87.xml
new file mode 100644
index 0000000..e2d56c6
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_87.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,3.563m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.437,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.966,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M12,20.437m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,17.966m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.034,6.034m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_9.xml b/core/res/res/drawable/pointer_wait_vector_9.xml
new file mode 100644
index 0000000..d46dfa3
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_9.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12.881,20.39m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M6.864,18.693m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M3.563,12.052m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M5.983,6.087m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M11.816,3.565m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M17.754,5.83m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M20.423,11.522m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+  <path
+      android:pathData="M18.415,17.479m-1.781,0a1.781,1.781 0,1 1,3.562 0a1.781,1.781 0,1 1,-3.562 0"
+      android:fillColor="#FFF"/>
+</vector>
diff --git a/core/res/res/drawable/pointer_wait_vector_icon.xml b/core/res/res/drawable/pointer_wait_vector_icon.xml
new file mode 100644
index 0000000..45d371e
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_vector_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
+    android:bitmap="@drawable/pointer_wait_vector"
+    android:hotSpotX="12dp"
+    android:hotSpotY="12dp" />
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index b2e0be7c..c882938 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1618,15 +1618,13 @@
         <!-- Data (photo, file, account) upload/download, backup/restore, import/export, fetch,
             transfer over network between device and cloud.
 
-            <p><b>THIS TYPE IS DEPRECATED.</b>
-            <p><em>Note: For apps with <code>targetSdkVersion</code>
-            {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} and above, this type should
-            <b>NOT</b> be used: calling
-            {@link android.app.Service#startForeground(int, android.app.Notification, int)}
-            with this type on devices running
-            {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} is still allowed, but it may
-            throw an {@link android.app.InvalidForegroundServiceTypeException} in future platform
-            releases.</em>
+            <p>For apps with <code>targetSdkVersion</code>
+            {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and above, this type should NOT
+            be used: calling
+            {@link android.app.Service#startForeground(int, android.app.Notification, int)} with
+            this type on devices running {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}
+            is still allowed, but calling it with this type on devices running future platform
+            releases may get a {@link android.app.InvalidForegroundServiceTypeException}.
         -->
         <flag name="dataSync" value="0x01" />
         <!-- Music, video, news or other media play.
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 1f06b0b..6134e78 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -6967,4 +6967,16 @@
 
     <!-- Whether to use file hashes cache in watchlist-->
     <bool name="config_watchlistUseFileHashesCache">false</bool>
+
+    <!-- Name of the package responsible to handle Contextual Search. -->
+    <string name="config_defaultContextualSearchPackageName" translatable="false" />
+
+    <!-- The key containing the entrypoint for Contextual Search. -->
+    <string name="config_defaultContextualSearchKey" translatable="false" />
+
+    <!-- The key containing the branching boolean for Contextual Search. -->
+    <string name="config_defaultContextualSearchEnabled" translatable="false" />
+
+    <!-- The key containing the branching boolean for legacy Search. -->
+    <string name="config_defaultContextualSearchLegacyEnabled" translatable="false" />
 </resources>
diff --git a/core/res/res/values/config_battery_saver.xml b/core/res/res/values/config_battery_saver.xml
index e1b0ef4..551cd0a 100644
--- a/core/res/res/values/config_battery_saver.xml
+++ b/core/res/res/values/config_battery_saver.xml
@@ -33,6 +33,9 @@
     <!-- Whether or not battery saver should be "sticky" when manually enabled. -->
     <bool name="config_batterySaverStickyBehaviourDisabled">false</bool>
 
+    <!-- Whether to enable "Battery Saver turned off" notification. -->
+    <bool name="config_batterySaverTurnedOffNotificationEnabled">true</bool>
+
     <!-- Config flag to track default disable threshold for Dynamic power savings enabled battery saver. -->
     <integer name="config_dynamicPowerSavingsDefaultDisableThreshold">80</integer>
 
diff --git a/core/res/res/values/config_display.xml b/core/res/res/values/config_display.xml
new file mode 100644
index 0000000..2e66060
--- /dev/null
+++ b/core/res/res/values/config_display.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright (C) 2024 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.
+*/
+-->
+
+<!-- Resources used in DisplayManager.
+
+     These resources are around just to allow their values to be customized
+     for different hardware and product builds.  Do not translate.
+
+     NOTE: The naming convention is "config_camelCaseValue". -->
+
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether even dimmer feature is enabled. -->
+    <bool name="config_evenDimmerEnabled">false</bool>
+
+</resources>
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index 104b7cd..c87b7cd 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -73,6 +73,11 @@
     <bool name="auto_data_switch_ping_test_before_switch">true</bool>
     <java-symbol type="bool" name="auto_data_switch_ping_test_before_switch" />
 
+    <!-- TODO: remove after V -->
+    <!-- Boolean indicating whether allow to use a roaming nonDDS if user enabled its roaming. -->
+    <bool name="auto_data_switch_allow_roaming">true</bool>
+    <java-symbol type="bool" name="auto_data_switch_allow_roaming" />
+
     <!-- Define the tolerated gap of score for auto data switch decision, larger than which the
          device will switch to the SIM with higher score. The score is used in conjunction with the
          score table defined in
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index adf8d9f..5945f81 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1468,7 +1468,7 @@
         <item name="pointerIconHand">@drawable/pointer_hand_vector_icon</item>
         <item name="pointerIconContextMenu">@drawable/pointer_context_menu_vector_icon</item>
         <item name="pointerIconHelp">@drawable/pointer_help_vector_icon</item>
-        <item name="pointerIconWait">@drawable/pointer_wait_icon</item>
+        <item name="pointerIconWait">@drawable/pointer_wait_vector_icon</item>
         <item name="pointerIconCell">@drawable/pointer_cell_vector_icon</item>
         <item name="pointerIconCrosshair">@drawable/pointer_crosshair_vector_icon</item>
         <item name="pointerIconText">@drawable/pointer_text_vector_icon</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 3284791..2f5183f 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4123,6 +4123,7 @@
   <java-symbol type="bool" name="config_batterySaverSupported" />
   <java-symbol type="string" name="config_batterySaverDeviceSpecificConfig" />
   <java-symbol type="bool" name="config_batterySaverStickyBehaviourDisabled" />
+  <java-symbol type="bool" name="config_batterySaverTurnedOffNotificationEnabled" />
   <java-symbol type="integer" name="config_dynamicPowerSavingsDefaultDisableThreshold" />
   <java-symbol type="string" name="config_batterySaverScheduleProvider" />
   <java-symbol type="string" name="config_powerSaveModeChangedListenerPackage" />
@@ -5363,5 +5364,12 @@
   <java-symbol type="string" name="satellite_notification_how_it_works" />
   <java-symbol type="drawable" name="ic_satellite_alt_24px" />
 
+  <!-- DisplayManager configs. -->
+  <java-symbol type="bool" name="config_evenDimmerEnabled" />
+
   <java-symbol type="bool" name="config_watchlistUseFileHashesCache" />
+  <java-symbol type="string" name="config_defaultContextualSearchPackageName" />
+  <java-symbol type="string" name="config_defaultContextualSearchKey" />
+  <java-symbol type="string" name="config_defaultContextualSearchEnabled" />
+  <java-symbol type="string" name="config_defaultContextualSearchLegacyEnabled" />
 </resources>
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 37e6780..e72beee 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -28,10 +28,19 @@
     visibility: ["//visibility:private"],
 }
 
+java_defaults {
+    name: "FrameworksCoreTests-resources",
+    aaptflags: [
+        "-0 .dat",
+        "-0 .gld",
+        "-c fa",
+    ],
+    resource_dirs: ["res"],
+}
+
 android_test {
     name: "FrameworksCoreTests",
-    // FrameworksCoreTestsRavenwood references the .aapt.srcjar
-    use_resource_processor: false,
+    defaults: ["FrameworksCoreTests-resources"],
 
     srcs: [
         "src/**/*.java",
@@ -117,7 +126,6 @@
 
     certificate: "platform",
 
-    resource_dirs: ["res"],
     resource_zips: [":FrameworksCoreTests_apks_as_resources"],
     java_resources: [":FrameworksCoreTests_unit_test_cert_der"],
 
@@ -128,6 +136,24 @@
     ],
 }
 
+// FrameworksCoreTestsRavenwood pulls in the R.java class from this one.
+// Note, "FrameworksCoreTests" and "FrameworksCoreTests-resonly" _might_ not have indentical
+// R.java (not sure if there's a guarantee), but that doesn't matter as long as
+// FrameworksCoreTestsRavenwood consistently uses the R definition in this module.
+android_app {
+    name: "FrameworksCoreTests-resonly",
+    defaults: ["FrameworksCoreTests-resources"],
+
+    // FrameworksCoreTestsRavenwood references the .aapt.srcjar
+    use_resource_processor: false,
+    libs: [
+        "framework-res",
+        "android.test.runner",
+        "org.apache.http.legacy",
+    ],
+    sdk_version: "core_platform",
+}
+
 // Rules to copy all the test apks to the intermediate raw resource directory
 java_genrule {
     name: "FrameworksCoreTests_apks_as_resources",
@@ -225,7 +251,11 @@
         "src/com/android/internal/util/**/*.java",
         "src/com/android/internal/power/EnergyConsumerStatsTest.java",
 
-        ":FrameworksCoreTests{.aapt.srcjar}",
+        // Pull in R.java from FrameworksCoreTests-resonly, not from FrameworksCoreTests,
+        // to avoid having a dependency to FrameworksCoreTests.
+        // This way, when updating source files and running this test, we don't need to
+        // rebuild the entire FrameworksCoreTests, which would be slow.
+        ":FrameworksCoreTests-resonly{.aapt.srcjar}",
         ":FrameworksCoreTests-aidl",
         ":FrameworksCoreTests-helpers",
         ":FrameworksCoreTestDoubles-sources",
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index a7d083c..64c17bd 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -65,6 +65,7 @@
 import android.util.MergedConfiguration;
 import android.view.Display;
 import android.view.View;
+import android.window.ActivityWindowInfo;
 import android.window.WindowContextInfo;
 import android.window.WindowTokenClientController;
 
@@ -394,11 +395,13 @@
             olderConfig.seq = seq + 1;
 
             final ActivityClientRecord r = getActivityClientRecord(activity);
-            activityThread.handleActivityConfigurationChanged(r, olderConfig, INVALID_DISPLAY);
+            activityThread.handleActivityConfigurationChanged(r, olderConfig, INVALID_DISPLAY,
+                    new ActivityWindowInfo());
             assertEquals(numOfConfig, activity.mNumOfConfigChanges);
             assertEquals(olderConfig.orientation, activity.mConfig.orientation);
 
-            activityThread.handleActivityConfigurationChanged(r, newerConfig, INVALID_DISPLAY);
+            activityThread.handleActivityConfigurationChanged(r, newerConfig, INVALID_DISPLAY,
+                    new ActivityWindowInfo());
             assertEquals(numOfConfig + 1, activity.mNumOfConfigChanges);
             assertEquals(newerConfig.orientation, activity.mConfig.orientation);
         });
@@ -416,7 +419,7 @@
             config.orientation = ORIENTATION_PORTRAIT;
 
             activityThread.handleActivityConfigurationChanged(getActivityClientRecord(activity),
-                    config, INVALID_DISPLAY);
+                    config, INVALID_DISPLAY, new ActivityWindowInfo());
         });
 
         final IApplicationThread appThread = activityThread.getApplicationThread();
@@ -487,7 +490,7 @@
             config.orientation = ORIENTATION_PORTRAIT;
 
             activityThread.handleActivityConfigurationChanged(getActivityClientRecord(activity),
-                    config, INVALID_DISPLAY);
+                    config, INVALID_DISPLAY, new ActivityWindowInfo());
         });
 
         final int numOfConfig = activity.mNumOfConfigChanges;
@@ -617,7 +620,7 @@
             activityThread.updatePendingActivityConfiguration(activity.getActivityToken(),
                     newActivityConfig);
             activityThread.handleActivityConfigurationChanged(r, newActivityConfig,
-                    INVALID_DISPLAY);
+                    INVALID_DISPLAY, new ActivityWindowInfo());
 
             assertEquals("Virtual display orientation must not change when activity"
                             + " configuration orientation changes.",
@@ -782,8 +785,8 @@
 
     /**
      * Calls {@link ActivityThread#handleActivityConfigurationChanged(ActivityClientRecord,
-     * Configuration, int)} to try to push activity configuration to the activity for the given
-     * sequence number.
+     * Configuration, int, ActivityWindowInfo)} to try to push activity configuration to the
+     * activity for the given sequence number.
      * <p>
      * It uses orientation to push the configuration and it tries a different orientation if the
      * first attempt doesn't make through, to rule out the possibility that the previous
@@ -802,7 +805,8 @@
         Configuration config = new Configuration();
         config.orientation = ORIENTATION_PORTRAIT;
         config.seq = seq;
-        activityThread.handleActivityConfigurationChanged(r, config, INVALID_DISPLAY);
+        activityThread.handleActivityConfigurationChanged(r, config, INVALID_DISPLAY,
+                new ActivityWindowInfo());
 
         if (activity.mNumOfConfigChanges > numOfConfig) {
             return config.seq;
@@ -811,7 +815,8 @@
         config = new Configuration();
         config.orientation = ORIENTATION_LANDSCAPE;
         config.seq = seq + 1;
-        activityThread.handleActivityConfigurationChanged(r, config, INVALID_DISPLAY);
+        activityThread.handleActivityConfigurationChanged(r, config, INVALID_DISPLAY,
+                new ActivityWindowInfo());
 
         return config.seq;
     }
@@ -839,7 +844,7 @@
         final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(
                 activity.getActivityToken(), null, null, 0,
                 new MergedConfiguration(currentConfig, currentConfig),
-                false /* preserveWindow */);
+                false /* preserveWindow */, new ActivityWindowInfo());
         final ResumeActivityItem resumeStateRequest =
                 ResumeActivityItem.obtain(activity.getActivityToken(), true /* isForward */,
                         false /* shouldSendCompatFakeFocus*/);
diff --git a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionItemTest.java b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionItemTest.java
index b5e8203..85a1b4e 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionItemTest.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionItemTest.java
@@ -40,6 +40,7 @@
 import android.util.MergedConfiguration;
 import android.view.IWindow;
 import android.view.InsetsState;
+import android.window.ActivityWindowInfo;
 import android.window.ClientWindowFrames;
 import android.window.WindowContext;
 import android.window.WindowContextInfo;
@@ -116,7 +117,8 @@
     public void testActivityRelaunchItem_getContextToUpdate() {
         final ActivityRelaunchItem item = ActivityRelaunchItem
                 .obtain(mActivityToken, null /* pendingResults */, null  /* pendingNewIntents */,
-                        0 /* configChange */, mMergedConfiguration, false /* preserveWindow */);
+                        0 /* configChange */, mMergedConfiguration, false /* preserveWindow */,
+                        new ActivityWindowInfo());
         final Context context = item.getContextToUpdate(mHandler);
 
         assertEquals(mActivity, context);
@@ -175,7 +177,7 @@
     @Test
     public void testMoveToDisplayItem_getContextToUpdate() {
         final MoveToDisplayItem item = MoveToDisplayItem
-                .obtain(mActivityToken, DEFAULT_DISPLAY, mConfiguration);
+                .obtain(mActivityToken, DEFAULT_DISPLAY, mConfiguration, new ActivityWindowInfo());
         final Context context = item.getContextToUpdate(mHandler);
 
         assertEquals(mActivity, context);
diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
index c6447be..906558f 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
@@ -39,6 +39,7 @@
 import android.os.IBinder;
 import android.os.PersistableBundle;
 import android.platform.test.annotations.Presubmit;
+import android.window.ActivityWindowInfo;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -124,6 +125,7 @@
         final int deviceId = 3;
         final IBinder taskFragmentToken = new Binder();
         final IBinder initialCallerInfoAccessToken = new Binder();
+        final ActivityWindowInfo activityWindowInfo = new ActivityWindowInfo();
 
         testRecycle(() -> new LaunchActivityItemBuilder(
                 activityToken, intent, activityInfo)
@@ -142,18 +144,21 @@
                 .setTaskFragmentToken(taskFragmentToken)
                 .setDeviceId(deviceId)
                 .setInitialCallerInfoAccessToken(initialCallerInfoAccessToken)
+                .setActivityWindowInfo(activityWindowInfo)
                 .build());
     }
 
     @Test
     public void testRecycleActivityRelaunchItem() {
         testRecycle(() -> ActivityRelaunchItem.obtain(mActivityToken,
-                resultInfoList(), referrerIntentList(), 42, mergedConfig(), true));
+                resultInfoList(), referrerIntentList(), 42, mergedConfig(), true,
+                new ActivityWindowInfo()));
     }
 
     @Test
     public void testRecycleMoveToDisplayItem() {
-        testRecycle(() -> MoveToDisplayItem.obtain(mActivityToken, 4, config()));
+        testRecycle(() -> MoveToDisplayItem.obtain(mActivityToken, 4, config(),
+                new ActivityWindowInfo()));
     }
 
     @Test
diff --git a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
index d641659..c1b9efd 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TestUtils.java
@@ -32,6 +32,7 @@
 import android.os.IBinder;
 import android.os.PersistableBundle;
 import android.util.MergedConfiguration;
+import android.window.ActivityWindowInfo;
 
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.content.ReferrerIntent;
@@ -134,6 +135,8 @@
         private IBinder mTaskFragmentToken;
         @Nullable
         private IBinder mInitialCallerInfoAccessToken;
+        @NonNull
+        private ActivityWindowInfo mActivityWindowInfo = new ActivityWindowInfo();
 
         LaunchActivityItemBuilder(@NonNull IBinder activityToken, @NonNull Intent intent,
                 @NonNull ActivityInfo info) {
@@ -260,6 +263,13 @@
         }
 
         @NonNull
+        LaunchActivityItemBuilder setActivityWindowInfo(
+                @NonNull ActivityWindowInfo activityWindowInfo) {
+            mActivityWindowInfo.set(activityWindowInfo);
+            return this;
+        }
+
+        @NonNull
         LaunchActivityItem build() {
             return LaunchActivityItem.obtain(mActivityToken, mIntent, mIdent, mInfo,
                     mCurConfig, mOverrideConfig, mDeviceId, mReferrer, mVoiceInteractor,
@@ -267,7 +277,7 @@
                     mActivityOptions != null ? mActivityOptions.getSceneTransitionInfo() : null,
                     mIsForward, mProfilerInfo, mAssistToken, null /* activityClientController */,
                     mShareableActivityToken, mLaunchedFromBubble, mTaskFragmentToken,
-                    mInitialCallerInfoAccessToken);
+                    mInitialCallerInfoAccessToken, mActivityWindowInfo);
         }
     }
 }
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index aa80013..dbb090f 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -32,6 +32,7 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.res.Configuration;
+import android.graphics.Rect;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -40,6 +41,7 @@
 import android.os.PersistableBundle;
 import android.platform.test.annotations.Presubmit;
 import android.platform.test.flag.junit.SetFlagsRule;
+import android.window.ActivityWindowInfo;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -108,8 +110,11 @@
     @Test
     public void testMoveToDisplay() {
         // Write to parcel
+        final ActivityWindowInfo activityWindowInfo = new ActivityWindowInfo();
+        activityWindowInfo.set(true /* isEmbedded */, new Rect(0, 0, 500, 1000),
+                new Rect(0, 0, 500, 500));
         MoveToDisplayItem item = MoveToDisplayItem.obtain(mActivityToken, 4 /* targetDisplayId */,
-                config());
+                config(), activityWindowInfo);
         writeAndPrepareForReading(item);
 
         // Read from parcel and assert
@@ -180,6 +185,9 @@
         bundle.putParcelable("data", new ParcelableData(1));
         final PersistableBundle persistableBundle = new PersistableBundle();
         persistableBundle.putInt("k", 4);
+        final ActivityWindowInfo activityWindowInfo = new ActivityWindowInfo();
+        activityWindowInfo.set(true /* isEmbedded */, new Rect(0, 0, 500, 1000),
+                new Rect(0, 0, 500, 500));
 
         final LaunchActivityItem item = new LaunchActivityItemBuilder(
                 activityToken, intent, activityInfo)
@@ -198,6 +206,7 @@
                 .setShareableActivityToken(new Binder())
                 .setTaskFragmentToken(new Binder())
                 .setInitialCallerInfoAccessToken(new Binder())
+                .setActivityWindowInfo(activityWindowInfo)
                 .build();
 
         writeAndPrepareForReading(item);
@@ -214,8 +223,11 @@
         // Write to parcel
         Configuration overrideConfig = new Configuration();
         overrideConfig.assetsSeq = 5;
+        final ActivityWindowInfo activityWindowInfo = new ActivityWindowInfo();
+        activityWindowInfo.set(true /* isEmbedded */, new Rect(0, 0, 500, 1000),
+                new Rect(0, 0, 500, 500));
         ActivityRelaunchItem item = ActivityRelaunchItem.obtain(mActivityToken, resultInfoList(),
-                referrerIntentList(), 35, mergedConfig(), true);
+                referrerIntentList(), 35, mergedConfig(), true, activityWindowInfo);
         writeAndPrepareForReading(item);
 
         // Read from parcel and assert
diff --git a/core/tests/coretests/src/android/os/WakeLockStatsTest.java b/core/tests/coretests/src/android/os/WakeLockStatsTest.java
index 2675ba0..f3b18c8 100644
--- a/core/tests/coretests/src/android/os/WakeLockStatsTest.java
+++ b/core/tests/coretests/src/android/os/WakeLockStatsTest.java
@@ -29,10 +29,114 @@
 public class WakeLockStatsTest {
 
     @Test
+    public void isDataValidOfWakeLockData_invalid_returnFalse() {
+        WakeLockStats.WakeLockData wakeLockData =
+                new WakeLockStats.WakeLockData(
+                        /* timesAcquired= */ 0, /* totalTimeHeldMs= */ 10, /* timeHeldMs= */ 0);
+        assertThat(wakeLockData.isDataValid()).isFalse();
+
+        wakeLockData =
+                new WakeLockStats.WakeLockData(
+                        /* timesAcquired= */ 1, /* totalTimeHeldMs= */ 0, /* timeHeldMs= */ 0);
+        assertThat(wakeLockData.isDataValid()).isFalse();
+
+        wakeLockData =
+                new WakeLockStats.WakeLockData(
+                        /* timesAcquired= */ 1, /* totalTimeHeldMs= */ 10, /* timeHeldMs= */ -10);
+        assertThat(wakeLockData.isDataValid()).isFalse();
+
+        wakeLockData =
+                new WakeLockStats.WakeLockData(
+                        /* timesAcquired= */ 1, /* totalTimeHeldMs= */ 10, /* timeHeldMs= */ 20);
+        assertThat(wakeLockData.isDataValid()).isFalse();
+    }
+
+    @Test
+    public void isDataValidOfWakeLockData_empty_returnTrue() {
+        final WakeLockStats.WakeLockData wakeLockData = WakeLockStats.WakeLockData.EMPTY;
+        assertThat(wakeLockData.isDataValid()).isTrue();
+    }
+
+    @Test
+    public void isDataValidOfWakeLockData_valid_returnTrue() {
+        WakeLockStats.WakeLockData wakeLockData =
+                new WakeLockStats.WakeLockData(
+                        /* timesAcquired= */ 1, /* totalTimeHeldMs= */ 10, /* timeHeldMs= */ 5);
+        assertThat(wakeLockData.isDataValid()).isTrue();
+    }
+
+    @Test
+    public void isDataValidOfWakeLock_zeroTotalHeldMs_returnFalse() {
+        final WakeLockStats.WakeLockData wakeLockData =
+                new WakeLockStats.WakeLockData(
+                        /* timesAcquired= */ 0, /* totalTimeHeldMs= */ 0, /* timeHeldMs= */ 0);
+
+        assertThat(WakeLockStats.WakeLock.isDataValid(wakeLockData, wakeLockData)).isFalse();
+    }
+
+    @Test
+    public void isDataValidOfWakeLock_invalidData_returnFalse() {
+        final WakeLockStats.WakeLockData totalWakeLockData =
+                new WakeLockStats.WakeLockData(
+                        /* timesAcquired= */ 6, /* totalTimeHeldMs= */ 60, /* timeHeldMs= */ 20);
+        final WakeLockStats.WakeLockData backgroundWakeLockData =
+                new WakeLockStats.WakeLockData(
+                        /* timesAcquired= */ 0, /* totalTimeHeldMs= */ 10, /* timeHeldMs= */ 0);
+
+        assertThat(WakeLockStats.WakeLock.isDataValid(totalWakeLockData, backgroundWakeLockData))
+                .isFalse();
+    }
+
+    @Test
+    public void isDataValidOfWakeLock_totalSmallerThanBackground_returnFalse() {
+        final WakeLockStats.WakeLockData totalWakeLockData =
+                new WakeLockStats.WakeLockData(
+                        /* timesAcquired= */ 10, /* totalTimeHeldMs= */ 60, /* timeHeldMs= */ 50);
+        final WakeLockStats.WakeLockData backgroundWakeLockData =
+                new WakeLockStats.WakeLockData(
+                        /* timesAcquired= */ 6, /* totalTimeHeldMs= */ 100, /* timeHeldMs= */ 30);
+
+        assertThat(WakeLockStats.WakeLock.isDataValid(totalWakeLockData, backgroundWakeLockData))
+                .isFalse();
+    }
+
+    @Test
+    public void isDataValidOfWakeLock_returnTrue() {
+        final WakeLockStats.WakeLockData totalWakeLockData =
+                new WakeLockStats.WakeLockData(
+                        /* timesAcquired= */ 10, /* totalTimeHeldMs= */ 100, /* timeHeldMs= */ 50);
+        final WakeLockStats.WakeLockData backgroundWakeLockData =
+                new WakeLockStats.WakeLockData(
+                        /* timesAcquired= */ 6, /* totalTimeHeldMs= */ 60, /* timeHeldMs= */ 20);
+
+        assertThat(WakeLockStats.WakeLock.isDataValid(totalWakeLockData, backgroundWakeLockData))
+                .isTrue();
+    }
+
+    @Test
     public void parcelablity() {
+        final WakeLockStats.WakeLockData totalWakeLockData1 =
+                new WakeLockStats.WakeLockData(
+                        /* timesAcquired= */ 10, /* totalTimeHeldMs= */ 60, /* timeHeldMs= */ 50);
+        final WakeLockStats.WakeLockData backgroundWakeLockData1 =
+                new WakeLockStats.WakeLockData(
+                        /* timesAcquired= */ 6, /* totalTimeHeldMs= */ 100, /* timeHeldMs= */ 30);
+        final WakeLockStats.WakeLock wakeLock1 =
+                new WakeLockStats.WakeLock(
+                        1, "foo", /* isAggregated= */ false, totalWakeLockData1,
+                        backgroundWakeLockData1);
+        final WakeLockStats.WakeLockData totalWakeLockData2 =
+                new WakeLockStats.WakeLockData(
+                        /* timesAcquired= */ 20, /* totalTimeHeldMs= */ 80, /* timeHeldMs= */ 30);
+        final WakeLockStats.WakeLockData backgroundWakeLockData2 =
+                new WakeLockStats.WakeLockData(
+                        /* timesAcquired= */ 1, /* totalTimeHeldMs= */ 100, /* timeHeldMs= */ 30);
+        final WakeLockStats.WakeLock wakeLock2 =
+                new WakeLockStats.WakeLock(
+                        2, "bar", /* isAggregated= */ true, totalWakeLockData2,
+                        backgroundWakeLockData2);
         WakeLockStats wakeLockStats = new WakeLockStats(
-                List.of(new WakeLockStats.WakeLock(1, "foo", 200, 3000, 40000),
-                        new WakeLockStats.WakeLock(2, "bar", 500, 6000, 70000)));
+                List.of(wakeLock1), List.of(wakeLock2));
 
         Parcel parcel = Parcel.obtain();
         wakeLockStats.writeToParcel(parcel, 0);
@@ -44,15 +148,28 @@
         parcel.setDataPosition(0);
 
         WakeLockStats actual = WakeLockStats.CREATOR.createFromParcel(parcel);
-        assertThat(actual.getWakeLocks()).hasSize(2);
-        WakeLockStats.WakeLock wl1 = actual.getWakeLocks().get(0);
-        assertThat(wl1.uid).isEqualTo(1);
-        assertThat(wl1.name).isEqualTo("foo");
-        assertThat(wl1.timesAcquired).isEqualTo(200);
-        assertThat(wl1.totalTimeHeldMs).isEqualTo(3000);
-        assertThat(wl1.timeHeldMs).isEqualTo(40000);
+        assertThat(actual.getWakeLocks()).hasSize(1);
+        WakeLockStats.WakeLock actualWakelock = actual.getWakeLocks().get(0);
+        assertThat(actualWakelock.uid).isEqualTo(1);
+        assertThat(actualWakelock.name).isEqualTo("foo");
+        assertThat(actualWakelock.isAggregated).isFalse();
+        assertThat(actualWakelock.totalWakeLockData.timesAcquired).isEqualTo(10);
+        assertThat(actualWakelock.totalWakeLockData.totalTimeHeldMs).isEqualTo(60);
+        assertThat(actualWakelock.totalWakeLockData.timeHeldMs).isEqualTo(50);
+        assertThat(actualWakelock.backgroundWakeLockData.timesAcquired).isEqualTo(6);
+        assertThat(actualWakelock.backgroundWakeLockData.totalTimeHeldMs).isEqualTo(100);
+        assertThat(actualWakelock.backgroundWakeLockData.timeHeldMs).isEqualTo(30);
 
-        WakeLockStats.WakeLock wl2 = actual.getWakeLocks().get(1);
-        assertThat(wl2.uid).isEqualTo(2);
+        assertThat(actual.getAggregatedWakeLocks()).hasSize(1);
+        WakeLockStats.WakeLock actualAggregatedWakelock = actual.getAggregatedWakeLocks().get(0);
+        assertThat(actualAggregatedWakelock.uid).isEqualTo(2);
+        assertThat(actualAggregatedWakelock.name).isEqualTo("bar");
+        assertThat(actualAggregatedWakelock.isAggregated).isTrue();
+        assertThat(actualAggregatedWakelock.totalWakeLockData.timesAcquired).isEqualTo(20);
+        assertThat(actualAggregatedWakelock.totalWakeLockData.totalTimeHeldMs).isEqualTo(80);
+        assertThat(actualAggregatedWakelock.totalWakeLockData.timeHeldMs).isEqualTo(30);
+        assertThat(actualAggregatedWakelock.backgroundWakeLockData.timesAcquired).isEqualTo(1);
+        assertThat(actualAggregatedWakelock.backgroundWakeLockData.totalTimeHeldMs).isEqualTo(100);
+        assertThat(actualAggregatedWakelock.backgroundWakeLockData.timeHeldMs).isEqualTo(30);
     }
-}
+}
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/tracing/perfetto/DataSourceTest.java b/core/tests/coretests/src/android/tracing/perfetto/DataSourceTest.java
index d57f1fc..030d420 100644
--- a/core/tests/coretests/src/android/tracing/perfetto/DataSourceTest.java
+++ b/core/tests/coretests/src/android/tracing/perfetto/DataSourceTest.java
@@ -24,15 +24,15 @@
 import static java.nio.file.Files.createTempDirectory;
 
 import android.internal.perfetto.protos.PerfettoTrace;
-import android.tools.common.ScenarioBuilder;
-import android.tools.common.Tag;
-import android.tools.common.io.TraceType;
-import android.tools.device.traces.TraceConfig;
-import android.tools.device.traces.TraceConfigs;
-import android.tools.device.traces.io.ResultReader;
-import android.tools.device.traces.io.ResultWriter;
-import android.tools.device.traces.monitors.PerfettoTraceMonitor;
-import android.tools.device.traces.monitors.TraceMonitor;
+import android.tools.ScenarioBuilder;
+import android.tools.Tag;
+import android.tools.io.TraceType;
+import android.tools.traces.TraceConfig;
+import android.tools.traces.TraceConfigs;
+import android.tools.traces.io.ResultReader;
+import android.tools.traces.io.ResultWriter;
+import android.tools.traces.monitors.PerfettoTraceMonitor;
+import android.tools.traces.monitors.TraceMonitor;
 import android.util.proto.ProtoInputStream;
 import android.util.proto.ProtoOutputStream;
 
diff --git a/core/tests/coretests/src/android/view/RoundedCornersTest.java b/core/tests/coretests/src/android/view/RoundedCornersTest.java
index 07ef33a..ec665ad 100644
--- a/core/tests/coretests/src/android/view/RoundedCornersTest.java
+++ b/core/tests/coretests/src/android/view/RoundedCornersTest.java
@@ -16,6 +16,8 @@
 
 package android.view;
 
+import static android.content.res.Configuration.SCREENLAYOUT_ROUND_NO;
+import static android.content.res.Configuration.SCREENLAYOUT_ROUND_YES;
 import static android.view.RoundedCorner.POSITION_BOTTOM_LEFT;
 import static android.view.RoundedCorner.POSITION_BOTTOM_RIGHT;
 import static android.view.RoundedCorner.POSITION_TOP_LEFT;
@@ -28,22 +30,47 @@
 import static org.hamcrest.Matchers.not;
 import static org.hamcrest.Matchers.nullValue;
 import static org.hamcrest.Matchers.sameInstance;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertThat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.when;
 
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.platform.test.annotations.Presubmit;
+import android.util.DisplayMetrics;
 import android.util.Pair;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.internal.R;
+
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 @Presubmit
 public class RoundedCornersTest {
 
+    @Mock
+    DisplayMetrics mMockDisplayMetrics;
+    @Mock
+    Resources mMockResources;
+    @Mock TypedArray mMockTypedArray;
+    Configuration mConfiguration;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mConfiguration = Configuration.EMPTY;
+    }
+
     final RoundedCorners mRoundedCorners = new RoundedCorners(
             new RoundedCorner(POSITION_TOP_LEFT, 10, 10, 10),
             new RoundedCorner(POSITION_TOP_RIGHT, 10, 190, 10),
@@ -199,4 +226,63 @@
         assertThat(RoundedCorners.fromRadii(radius, 200, 300),
                 not(sameInstance(cached)));
     }
+
+    @Test
+    public void testGetRoundedCornerRadius_withRoundDevice_usesDisplayRadiusAsDefault() {
+        final int displayWidth = 400;
+        mConfiguration.screenLayout = SCREENLAYOUT_ROUND_YES;
+        mMockDisplayMetrics.widthPixels = displayWidth;
+
+        when(mMockResources.getConfiguration()).thenReturn(mConfiguration);
+        when(mMockResources.getDisplayMetrics()).thenReturn(mMockDisplayMetrics);
+        when(mMockResources.getStringArray(R.array.config_displayUniqueIdArray))
+                .thenReturn(new String[]{"0"});
+        when(mMockTypedArray.length()).thenReturn(0);
+        when(mMockResources.obtainTypedArray(anyInt())).thenReturn(mMockTypedArray);
+        when(mMockResources.getDimensionPixelSize(R.dimen.rounded_corner_radius))
+                .thenReturn(0);
+
+
+        int radius = RoundedCorners.getRoundedCornerRadius(mMockResources, "0");
+        assertEquals((displayWidth / 2), radius);
+    }
+
+    @Test
+    public void testGetRoundedCornerRadius_withRoundDevice_usesOverlayIfProvided() {
+        final int displayWidth = 400;
+        final int overlayValue = 199;
+        mConfiguration.screenLayout = SCREENLAYOUT_ROUND_YES;
+        mMockDisplayMetrics.widthPixels = displayWidth;
+
+        when(mMockResources.getConfiguration()).thenReturn(mConfiguration);
+        when(mMockResources.getDisplayMetrics()).thenReturn(mMockDisplayMetrics);
+        when(mMockResources.getStringArray(R.array.config_displayUniqueIdArray))
+                .thenReturn(new String[]{"0"});
+        when(mMockTypedArray.length()).thenReturn(0);
+        when(mMockResources.obtainTypedArray(anyInt())).thenReturn(mMockTypedArray);
+        when(mMockResources.getDimensionPixelSize(R.dimen.rounded_corner_radius))
+                .thenReturn(overlayValue);
+
+        int radius = RoundedCorners.getRoundedCornerRadius(mMockResources, "0");
+        assertEquals(overlayValue, radius);
+    }
+
+    @Test
+    public void testGetRoundedCornerRadius_withNonRoundDevice_noDisplayDefault() {
+        final int displayWidth = 400;
+        mConfiguration.screenLayout = SCREENLAYOUT_ROUND_NO;
+        mMockDisplayMetrics.widthPixels = displayWidth;
+
+        when(mMockResources.getConfiguration()).thenReturn(mConfiguration);
+        when(mMockResources.getDisplayMetrics()).thenReturn(mMockDisplayMetrics);
+        when(mMockResources.getStringArray(R.array.config_displayUniqueIdArray))
+                .thenReturn(new String[]{"0"});
+        when(mMockTypedArray.length()).thenReturn(0);
+        when(mMockResources.obtainTypedArray(anyInt())).thenReturn(mMockTypedArray);
+        when(mMockResources.getDimensionPixelSize(R.dimen.rounded_corner_radius))
+                .thenReturn(0);
+
+        int radius = RoundedCorners.getRoundedCornerRadius(mMockResources, "0");
+        assertEquals(0, radius);
+    }
 }
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index 64cbe7f..7c58de6 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -1017,6 +1017,60 @@
         assertEquals(viewRootImpl.isFrameRatePowerSavingsBalanced(), true);
     }
 
+    /**
+     * Test the TextureView heuristic:
+     * 1. Store the last 3 invalidates time - FT1, FT2, FT3.
+     * 2. If FT2-FT1 > 15ms && FT3-FT2 > 15ms -> vote for NORMAL category
+     */
+    @Test
+    @RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
+    public void votePreferredFrameRate_applyTextureViewHeuristic() throws InterruptedException {
+        final long delay = 30L;
+
+        TextureView view = new TextureView(sContext);
+        WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY);
+        wmlp.token = new Binder(); // Set a fake token to bypass 'is your activity running' check
+
+        sInstrumentation.runOnMainSync(() -> {
+            WindowManager wm = sContext.getSystemService(WindowManager.class);
+            Display display = wm.getDefaultDisplay();
+            DisplayMetrics metrics = new DisplayMetrics();
+            display.getMetrics(metrics);
+            wmlp.width = (int) (metrics.widthPixels * 0.9);
+            wmlp.height = (int) (metrics.heightPixels * 0.9);
+            wm.addView(view, wmlp);
+        });
+        sInstrumentation.waitForIdleSync();
+
+        ViewRootImpl viewRootImpl = view.getViewRootImpl();
+
+        sInstrumentation.runOnMainSync(() -> {
+            assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
+                    FRAME_RATE_CATEGORY_NO_PREFERENCE);
+            view.invalidate();
+            assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
+                    FRAME_RATE_CATEGORY_HIGH);
+        });
+
+         // reset the frame rate category counts
+        for (int i = 0; i < 5; i++) {
+            Thread.sleep(delay);
+            sInstrumentation.runOnMainSync(() -> {
+                view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE);
+                view.invalidate();
+            });
+            sInstrumentation.waitForIdleSync();
+        }
+
+        Thread.sleep(delay);
+        sInstrumentation.runOnMainSync(() -> {
+            view.setRequestedFrameRate(view.REQUESTED_FRAME_RATE_CATEGORY_DEFAULT);
+            view.invalidate();
+            assertEquals(viewRootImpl.getPreferredFrameRateCategory(),
+                    FRAME_RATE_CATEGORY_NORMAL);
+        });
+    }
+
     @Test
     public void forceInvertOffDarkThemeOff_forceDarkModeDisabled() {
         mSetFlagsRule.enableFlags(FLAG_FORCE_INVERT_COLOR);
diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
index 39cb616..66be05f 100644
--- a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
+++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
@@ -61,6 +61,7 @@
 import android.platform.test.annotations.Presubmit;
 import android.testing.PollingCheck;
 import android.view.WindowManagerGlobal;
+import android.window.ActivityWindowInfo;
 import android.window.SizeConfigurationBuckets;
 
 import androidx.test.annotation.UiThreadTest;
@@ -354,7 +355,7 @@
                     null /* activityOptions */, true /* isForward */, null /* profilerInfo */,
                     mThread /* client */, null /* asssitToken */, null /* shareableActivityToken */,
                     false /* launchedFromBubble */, null /* taskfragmentToken */,
-                    null /* initialCallerInfoAccessToken */);
+                    null /* initialCallerInfoAccessToken */, new ActivityWindowInfo());
         }
 
         @Override
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 1fd1003..238a3e1 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -199,3 +199,8 @@
     name: "services.core.protolog.json",
     srcs: ["services.core.protolog.json"],
 }
+
+filegroup {
+    name: "file-core.protolog.pb",
+    srcs: ["core.protolog.pb"],
+}
diff --git a/data/etc/core.protolog.pb b/data/etc/core.protolog.pb
new file mode 100644
index 0000000..0415e44
--- /dev/null
+++ b/data/etc/core.protolog.pb
Binary files differ
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 42e3387..e8c7a53 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -1,4715 +1,4709 @@
 {
   "version": "1.0.0",
   "messages": {
-    "-2127842445": {
-      "message": "Clearing startingData for token=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-2121056984": {
-      "message": "%s",
-      "level": "WARN",
-      "group": "WM_DEBUG_LOCKTASK",
-      "at": "com\/android\/server\/wm\/LockTaskController.java"
-    },
-    "-2111539867": {
-      "message": "remove IME snapshot, caller=%s",
-      "level": "INFO",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-2109936758": {
-      "message": "removeAppToken make exiting: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-2109864870": {
-      "message": "app-release(): mOuter=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "-2107721178": {
-      "message": "grantEmbeddedWindowFocus win=%s grantFocus=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-2101985723": {
-      "message": "Failed looking up window session=%s callers=%s",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-2093859262": {
-      "message": "setClientVisible: %s clientVisible=%b Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/WindowToken.java"
-    },
-    "-2088209279": {
-      "message": "Notified TransitionController that the display is ready.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-2074882083": {
-      "message": "Content Recording: Unable to retrieve task to start recording for display %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "-2072089308": {
-      "message": "Attempted to add window with token that is a sub-window: %s.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-2072029833": {
-      "message": "Content Recording: Found no matching mirror display for id=%d for DEFAULT_DISPLAY. Nothing to mirror.",
-      "level": "WARN",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-2054442123": {
-      "message": "Setting Intent of %s to %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
-    "-2052051397": {
-      "message": "Clear animatingExit: reason=destroySurface win=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-2049725903": {
-      "message": "Task back pressed on root taskId=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
-    },
-    "-2039580386": {
-      "message": "Attempted to add input method window with unknown token %s.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-2036671725": {
-      "message": "      SKIP: is wallpaper",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-2024464438": {
-      "message": "app-onAnimationFinished(): mOuter=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "-2014162875": {
-      "message": "Could not register window container listener token=%s, container=%s",
-      "level": "ERROR",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowContextListenerController.java"
-    },
-    "-2012562539": {
-      "message": "startAnimation(): Notify animation start:",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "-2010331310": {
-      "message": "resumeTopActivity: Top activity resumed (dontWaitForPause) %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "-1980468143": {
-      "message": "DisplayArea appeared name=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
-    },
-    "-1979455254": {
-      "message": "Launch on display check: allow launch for caller present on the display",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
-    },
-    "-1976930686": {
-      "message": "Attempted to add Accessibility overlay window with bad token %s.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1973119651": {
-      "message": "SyncGroup %d: Adding to group: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_SYNC_ENGINE",
-      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
-    },
-    "-1969928125": {
-      "message": "Animation start for %s, anim=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/SurfaceAnimator.java"
-    },
-    "-1963461591": {
-      "message": "Removing %s from %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1963363332": {
-      "message": "Restart top activity process of Task taskId=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
-    },
-    "-1961637874": {
-      "message": "DeferredDisplayUpdater: applying DisplayInfo immediately",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/DeferredDisplayUpdater.java"
-    },
-    "-1949279037": {
-      "message": "Attempted to add input method window with bad token %s.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1939861963": {
-      "message": "Create root task displayId=%d winMode=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
-    },
-    "-1938839202": {
-      "message": "SURFACE LEAK DESTROY: %s",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-1938204785": {
-      "message": "Moving existing starting %s from %s to %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1933723759": {
-      "message": "Clear animatingExit: reason=relayoutVisibleWindow win=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-1924376693": {
-      "message": " Setting Ready-group to %b. group=%s from %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-1918702467": {
-      "message": "onSyncFinishedDrawing %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_SYNC_ENGINE",
-      "at": "com\/android\/server\/wm\/WindowContainer.java"
-    },
-    "-1915280162": {
-      "message": "Attempted to add wallpaper window with bad token %s.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1906387645": {
-      "message": "SURFACE controller=%s alpha=%f HScale=%f, VScale=%f: %s",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
-    },
-    "-1905191109": {
-      "message": "SyncGroup %d: Finished!",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_SYNC_ENGINE",
-      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
-    },
-    "-1895337367": {
-      "message": "Delete root task display=%d winMode=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
-    },
-    "-1886145147": {
-      "message": "resumeTopActivity: Going to sleep and all paused",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "-1885450608": {
-      "message": "Content Recording: Successfully created a ContentRecordingSession for displayId=%d to mirror content from displayId=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-1884933373": {
-      "message": "enableScreenAfterBoot: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_BOOT",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1872288685": {
-      "message": "applyAnimation: anim=%s nextAppTransition=%s transit=%s isEntrance=%b Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/AppTransition.java"
-    },
-    "-1868518158": {
-      "message": "Pending back animation due to another animation is running",
-      "level": "WARN",
-      "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/BackNavigationController.java"
-    },
-    "-1868124841": {
-      "message": "screenOnEarly=%b, awake=%b, currentAppOrientation=%d, orientationSensorEnabled=%b, keyguardDrawComplete=%b, windowManagerDrawComplete=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "-1868048288": {
-      "message": "Updating to new configuration after starting activity.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityStarter.java"
-    },
-    "-1862269827": {
-      "message": "applyAnimation: anim=%s transit=%s isEntrance=%b Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/AppTransition.java"
-    },
-    "-1844540996": {
-      "message": "  Initial targets: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-1838803135": {
-      "message": "Attempted to set windowing mode to a display that does not exist: %d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1834214907": {
-      "message": "createNonAppWindowAnimations()",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "-1828118576": {
-      "message": "SyncGroup %d: Started %sfor listener: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_SYNC_ENGINE",
-      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
-    },
-    "-1824578273": {
-      "message": "Reporting new frame to %s: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_RESIZE",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-1818910559": {
-      "message": "DeferredDisplayUpdater: applied DisplayInfo after deferring",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/DeferredDisplayUpdater.java"
-    },
-    "-1814361639": {
-      "message": "Set IME snapshot position: (%d, %d)",
-      "level": "INFO",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-1812743677": {
-      "message": "Display id=%d is ignoring all orientation requests, camera is active and the top activity is eligible for force rotation, return %s,portrait activity: %b, is natural orientation portrait: %b.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
-    },
-    "-1810446914": {
-      "message": "Trying to update display configuration for system\/invalid process.",
-      "level": "WARN",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "-1800899273": {
-      "message": "applyAnimation: anim=%s transit=%s Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/AppTransition.java"
-    },
-    "-1792633344": {
-      "message": "Register task organizer=%s uid=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
-    },
-    "-1791031393": {
-      "message": "Ensuring correct configuration: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1782453012": {
-      "message": "Checking theme of starting window: 0x%x",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1777196134": {
-      "message": "goodToGo(): No apps to animate, mPendingAnimations=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "-1777010776": {
-      "message": "create IME snapshot for %s, buff width=%s, height=%s",
-      "level": "INFO",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-1768557332": {
-      "message": "removeWallpaperAnimation()",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
-    },
-    "-1764792832": {
-      "message": "Start collecting in Transition: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/TransitionController.java"
-    },
-    "-1750206390": {
-      "message": "Exception thrown when creating surface for client %s (%s). %s",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1747461042": {
-      "message": "set mOrientationChanging of %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-1740512980": {
-      "message": "Stopping %s: nowVisible=%b animating=%b finishing=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
-    },
-    "-1730156332": {
-      "message": "Display id=%d rotation changed to %d from %d, lastOrientation=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "-1728919185": {
-      "message": "        unrelated invisible sibling %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-1710206702": {
-      "message": "Display id=%d is frozen while keyguard locked, return %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-1707370822": {
-      "message": "Ready to stop: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
-    },
-    "-1704402370": {
-      "message": "resetTaskIntendedTask: calling finishActivity on %s",
-      "level": "WARN",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java"
-    },
-    "-1700778361": {
-      "message": "Content Recording: Going ahead with updating recording for display %d to new bounds %s and\/or orientation %d and\/or surface size %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "-1699018375": {
-      "message": "Adding activity %s to task %s callers: %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
-    "-1679411993": {
-      "message": "setVr2dDisplayId called for: %d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "-1671601441": {
-      "message": "attachWindowContextToDisplayContent: calling from non-existing process pid=%d uid=%d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1670695197": {
-      "message": "Attempted to add presentation window to a non-suitable display.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1647332198": {
-      "message": "remove RecentTask %s when finishing user %d",
-      "level": "INFO",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/RecentTasks.java"
-    },
-    "-1643780158": {
-      "message": "Saving original orientation before camera compat, last orientation is %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
-    },
-    "-1639406696": {
-      "message": "NOSENSOR override detected",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotationReversionController.java"
-    },
-    "-1638958146": {
-      "message": "Removing activity %s from task=%s adding to task=%s Callers=%s",
-      "level": "INFO",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java"
-    },
-    "-1633115609": {
-      "message": "Key dispatch not paused for screen off",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "-1632122349": {
-      "message": "Changing surface while display frozen: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1631991057": {
-      "message": "Display id=%d is notified that Camera %s is closed but activity is still refreshing. Rescheduling an update.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
-    },
-    "-1630752478": {
-      "message": "removeLockedTask: removed %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_LOCKTASK",
-      "at": "com\/android\/server\/wm\/LockTaskController.java"
-    },
-    "-1598452494": {
-      "message": "activityDestroyedLocked: r=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_CONTAINERS",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1596995693": {
-      "message": "startAnimation",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "-1585311008": {
-      "message": "Bring to front target: %s from %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityStarter.java"
-    },
-    "-1583619037": {
-      "message": "Failed to register MediaProjectionWatcherCallback",
-      "level": "ERROR",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/ScreenRecordingCallbackController.java"
-    },
-    "-1582845629": {
-      "message": "Starting animation on %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_DIMMER",
-      "at": "com\/android\/server\/wm\/DimmerAnimationHelper.java"
-    },
-    "-1575977269": {
-      "message": "Skipping %s: mismatch root %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "-1568331821": {
-      "message": "Enabling listeners",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "-1567866547": {
-      "message": "Collecting in transition %d: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-1564228464": {
-      "message": "App died while pausing: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "-1559645910": {
-      "message": "Looking for task of type=%s, taskAffinity=%s, intent=%s, info=%s, preferredTDA=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "-1558137010": {
-      "message": "Config is relaunching invisible activity %s called by %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1554521902": {
-      "message": "showInsets(ime) was requested by different window: %s ",
-      "level": "WARN",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
-    },
-    "-1545962566": {
-      "message": "View server did not start",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1539974875": {
-      "message": "removeAppToken: %s delayed=%b Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1526645239": {
-      "message": "Timeout waiting for drawn: undrawn=%s",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1518132958": {
-      "message": "fractionRendered boundsOverSource=%f",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_TPL",
-      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
-    },
-    "-1517908912": {
-      "message": "requestScrollCapture: caught exception dispatching to window.token=%s",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1501564055": {
-      "message": "Organized TaskFragment is not ready= %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "-1499134947": {
-      "message": "Removing starting %s from %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1497837552": {
-      "message": "onAnimationFinished(): mPendingAnimations=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "-1495062622": {
-      "message": "Can't report activity moved to display - client not running, activityRecord=%s, displayId=%d",
-      "level": "WARN",
-      "group": "WM_DEBUG_SWITCH",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1492881555": {
-      "message": "Starting activity when config will change = %b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityStarter.java"
-    },
-    "-1483435730": {
-      "message": "InsetsSource setWin %s for type %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_WINDOW_INSETS",
-      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
-    },
-    "-1480918485": {
-      "message": "Refreshed activity: %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1480772131": {
-      "message": "No app or window is requesting an orientation, return %d for display id=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-1478175541": {
-      "message": "No longer animating wallpaper targets!",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WALLPAPER",
-      "at": "com\/android\/server\/wm\/WallpaperController.java"
-    },
-    "-1474602871": {
-      "message": "Launch on display check: disallow launch on virtual display for not-embedded activity.",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
-    },
-    "-1474292612": {
-      "message": "Could not find task for id: %d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "-1471518109": {
-      "message": "Set animatingExit: reason=onAppVisibilityChanged win=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-1468740466": {
-      "message": "Moving to PAUSED: %s (starting in paused state)",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
-    },
-    "-1452274694": {
-      "message": "      CAN PROMOTE: promoting to parent %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-1449515133": {
-      "message": "Content Recording: stopping active projection for display %d",
-      "level": "ERROR",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "-1443029505": {
-      "message": "SAFE MODE ENABLED (menu=%d s=%d dpad=%d trackball=%d)",
-      "level": "INFO",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1442613680": {
-      "message": " Creating Ready-group for Transition %d with root=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-1438175584": {
-      "message": "Input focus has changed to %s display=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/InputMonitor.java"
-    },
-    "-1434147454": {
-      "message": "cleanupAnimation(): Notify animation finished mPendingAnimations=%d reorderMode=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
-    },
-    "-1432963966": {
-      "message": "Moving to DESTROYING: %s (destroy requested)",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1427184084": {
-      "message": "addWindow: New client %s: window=%s Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1421296808": {
-      "message": "Moving to RESUMED: %s (in existing)",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "-1419762046": {
-      "message": "moveRootTaskToDisplay: moving taskId=%d to displayId=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "-1419461256": {
-      "message": "resumeTopActivity: Resumed %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "-1413901262": {
-      "message": "startRecentsActivity(): intent=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
-    },
-    "-1410260105": {
-      "message": "Schedule IME show for %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
-    },
-    "-1397175017": {
-      "message": "Other orientation overrides are in place: not reverting",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotationReversionController.java"
-    },
-    "-1394745488": {
-      "message": "ControlAdapter onAnimationCancelled mSource: %s mControlTarget: %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_WINDOW_INSETS",
-      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
-    },
-    "-1391944764": {
-      "message": "SURFACE DESTROY: %s. %s",
-      "level": "INFO",
-      "group": "WM_SHOW_SURFACE_ALLOC",
-      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
-    },
-    "-1389772804": {
-      "message": "Attempted to add voice interaction window with bad token %s.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1383884640": {
-      "message": " allReady query: used=%b override=%b defer=%d states=[%s]",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-1376035390": {
-      "message": "No task found",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "-1364754753": {
-      "message": "Task vanished taskId=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
-    },
-    "-1352076759": {
-      "message": "Removing app token: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1350198040": {
-      "message": "hideBootMessagesLocked: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_BOOT",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1340540100": {
-      "message": "Creating SnapshotStartingData",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1325565952": {
-      "message": "Attempted to get home support flag of a display that does not exist: %d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1323783276": {
-      "message": "performEnableScreen: bootFinished() failed.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1318478129": {
-      "message": "applyAnimation: win=%s anim=%d attr=0x%x a=%s transit=%d type=%d isEntrance=%b Callers %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
-    },
-    "-1311436264": {
-      "message": "Unregister task fragment organizer=%s uid=%d pid=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
-    },
-    "-1305966693": {
-      "message": "Sending position change to %s, onTop: %b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1305791032": {
-      "message": "Moving to STOPPED: %s (stop complete)",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1305755880": {
-      "message": "Initial config: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "-1304806505": {
-      "message": "Starting new activity %s in new task %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityStarter.java"
-    },
-    "-1303628829": {
-      "message": "**** STARTING EXIT",
-      "level": "INFO",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/DisplayPolicy.java"
-    },
-    "-1292329638": {
-      "message": "Added starting %s: startingWindow=%s startingView=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1288007399": {
-      "message": "performShowLocked: mDrawState=HAS_DRAWN in %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-1277068810": {
-      "message": "startBackNavigation currentTask=%s, topRunningActivity=%s, callbackInfo=%s, currentFocus=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/BackNavigationController.java"
-    },
-    "-1263316010": {
-      "message": "Computed rotation=%s (%d) for display id=%d based on lastOrientation=%s (%d) and oldRotation=%s (%d)",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "-1259022216": {
-      "message": "SURFACE HIDE ( %s ): %s",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
-    },
-    "-1258739769": {
-      "message": "onTransactionReady, opening: %s, closing: %s, animating: %s, match: %b",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/BackNavigationController.java"
-    },
-    "-1257821162": {
-      "message": "OUT SURFACE %s: copied",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1256520588": {
-      "message": "performEnableScreen: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_BOOT",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1253056469": {
-      "message": "Launch on display check: %s launch for userId=%d on displayId=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
-    },
-    "-1248645819": {
-      "message": "\tAdd container=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "-1243510456": {
-      "message": "Dim animation requested: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_DIMMER",
-      "at": "com\/android\/server\/wm\/DimmerAnimationHelper.java"
-    },
-    "-1237827119": {
-      "message": "Schedule remove starting %s startingWindow=%s animate=%b Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1228653755": {
-      "message": "Launch on display check: displayId=%d callingPid=%d callingUid=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
-    },
-    "-1219773477": {
-      "message": "setInputConsumerEnabled(%s): mCanceled=%b",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
-    },
-    "-1217596375": {
-      "message": "Content Recording: Display %d has no content and is on, so start recording for state %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "-1209762265": {
-      "message": "Registering listener=%s with id=%d for window=%s with %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TPL",
-      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
-    },
-    "-1209252064": {
-      "message": "Clear animatingExit: reason=clearAnimatingFlags win=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-1207757583": {
-      "message": "startAnimation(): Notify animation start: %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
-    },
-    "-1204565480": {
-      "message": "Adding display switch to existing collecting transition",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/PhysicalDisplaySwitchTransitionLauncher.java"
-    },
-    "-1198579104": {
-      "message": "Pushing next activity %s out to target's task %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java"
-    },
-    "-1193946201": {
-      "message": "Can't report activity position update - client not running, activityRecord=%s",
-      "level": "WARN",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1187377055": {
-      "message": "Enqueue pending stop if needed: %s wasStopping=%b visibleRequested=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "-1185473319": {
-      "message": "ControlAdapter startAnimation mSource: %s controlTarget: %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_WINDOW_INSETS",
-      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
-    },
-    "-1164930508": {
-      "message": "Moving to RESUMED: %s (starting new instance) callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
-    "-1156314529": {
-      "message": "Content Recording: Unexpectedly null window container; unable to update recording for display %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "-1156118957": {
-      "message": "Updated config=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
-    },
-    "-1153814764": {
-      "message": "onAnimationCancelled",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/NonAppWindowAnimationAdapter.java"
-    },
-    "-1152771606": {
-      "message": "Content Recording: Display %d was already recording, but pause capture since the task is in PIP",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "-1145384901": {
-      "message": "shouldWaitAnimatingExit: isTransition: %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-1142279614": {
-      "message": "Looking for focus: %s, flags=%d, canReceive=%b, reason=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-1136734598": {
-      "message": "Content Recording: Ignoring session on same display %d, with an existing session %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecordingController.java"
-    },
-    "-1136467585": {
-      "message": "The listener does not exist.",
-      "level": "INFO",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/WindowContextListenerController.java"
-    },
-    "-1136139407": {
-      "message": "no-history finish of %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1130891072": {
-      "message": "Orientation continue waiting for draw in %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
-    },
-    "-1130868271": {
-      "message": "Resizing %s WITH DRAW PENDING",
-      "level": "INFO",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-1117599386": {
-      "message": "Deferring rotation, display is not enabled.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "-1115019498": {
-      "message": "Configuration & display unchanged in %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1113134997": {
-      "message": "Attempted to add application window with unknown token %s.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1108775960": {
-      "message": "%s is requesting orientation %d (%s)",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowContainer.java"
-    },
-    "-1104347731": {
-      "message": "Setting requested orientation %s for %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1103716954": {
-      "message": "Not removing %s due to exit animation",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-1103115659": {
-      "message": "Performing post-rotate rotation",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "-1101551167": {
-      "message": "Auto-PIP allowed, entering PIP mode directly: %s, didAutoPip: %b",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "-1097851684": {
-      "message": "Content Recording: Unable to start recording due to null token for display %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "-1089874824": {
-      "message": "SURFACE SHOW (performLayout): %s",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
-    },
-    "-1075136930": {
-      "message": "startLockTaskMode: Can't lock due to auth",
-      "level": "WARN",
-      "group": "WM_DEBUG_LOCKTASK",
-      "at": "com\/android\/server\/wm\/LockTaskController.java"
-    },
-    "-1069336896": {
-      "message": "onRootTaskOrderChanged(): rootTask=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
-    },
-    "-1060529098": {
-      "message": "  Skipping post-transition snapshot for task %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-1060365734": {
-      "message": "Attempted to add QS dialog window with bad token %s.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1047945589": {
-      "message": "Remove client=%x, surfaceController=%s Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-1043981272": {
-      "message": "Reverting orientation. Rotating to %s from %s rather than %s.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "-1042574499": {
-      "message": "Attempted to add Accessibility overlay window with unknown token %s.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-1033630971": {
-      "message": "onBackNavigationDone backType=%s, triggerBack=%b",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/BackNavigationController.java"
-    },
-    "-1028213464": {
-      "message": "%s skipping animation and directly setting alpha=%f, blur=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_DIMMER",
-      "at": "com\/android\/server\/wm\/DimmerAnimationHelper.java"
-    },
-    "-1022146708": {
-      "message": "Skipping %s: mismatch activity type",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "-1016578046": {
-      "message": "Moving to %s Relaunching %s callers=%s",
-      "level": "INFO",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1009117329": {
-      "message": "isFetchingAppTransitionSpecs=true",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "-1005167552": {
-      "message": "Playing #%d in parallel on track #%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/TransitionController.java"
-    },
-    "-1003678883": {
-      "message": "Cleaning splash screen token=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-1003060523": {
-      "message": "Finish needs to pause: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-993378225": {
-      "message": "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING %s in %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_DRAW",
-      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
-    },
-    "-986746907": {
-      "message": "Starting window removed %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-962760979": {
-      "message": "thawRotation: mRotation=%d, caller=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-961053385": {
-      "message": "attachWindowContextToDisplayArea: calling from non-existing process pid=%d uid=%d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-957060823": {
-      "message": "Moving to PAUSING: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "-951939129": {
-      "message": "Unregister task organizer=%s uid=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
-    },
-    "-948446688": {
-      "message": "Create TaskDisplayArea uid=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
-    },
-    "-938271693": {
-      "message": "allResumedActivitiesIdle: rootTask=%d %s not idle",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "-937498525": {
-      "message": "Executing finish of failed to pause activity: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-930893991": {
-      "message": "Set sync ready, syncId=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/WindowOrganizerController.java"
-    },
-    "-929676529": {
-      "message": "Configuration changes for %s, allChanges=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-927199900": {
-      "message": "Updating global configuration to: %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "-926231510": {
-      "message": "State unchanged from:%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-921346089": {
-      "message": "Content Recording: Unable to tell MediaProjectionManagerService to stop the active projection for display %d: %s",
-      "level": "ERROR",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "-917215012": {
-      "message": "%s: caller %d is using old GET_TASKS but privileged; allowing",
-      "level": "WARN",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "-916108501": {
-      "message": "Adding %s to %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-914253865": {
-      "message": "Attempted to add voice interaction window with unknown token %s.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-894942237": {
-      "message": "Force Playing Transition: %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-888703350": {
-      "message": "Skipping %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_TPL",
-      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
-    },
-    "-883738232": {
-      "message": "Adding more than one toast window for UID at a time.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-877494781": {
-      "message": "Start pushing activity %s out to bottom task %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java"
-    },
-    "-874888131": {
-      "message": "Set transition ready=%b %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-874446906": {
-      "message": "showBootMessage: msg=%s always=%b mAllowBootMessages=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_BOOT",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-874087484": {
-      "message": "SyncGroup %d: Set ready %b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_SYNC_ENGINE",
-      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
-    },
-    "-869242375": {
-      "message": "Content Recording: Unable to start recording due to invalid region for display %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "-863438038": {
-      "message": "Aborting Transition: %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-861859917": {
-      "message": "Attempted to add window to a display that does not exist: %d. Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-861707633": {
-      "message": "Destroying surface %s called by %s",
-      "level": "INFO",
-      "group": "WM_SHOW_SURFACE_ALLOC",
-      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
-    },
-    "-856750101": {
-      "message": "Launch on display check: allow launch for owner of the display",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
-    },
-    "-856590985": {
-      "message": "dcTarget: %s mImeRequester: %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
-    },
-    "-853404763": {
-      "message": "\twallpaper=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "-853226675": {
-      "message": "Attempted to add window with exiting application token .%s Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-846931068": {
-      "message": "Update camera compat control state to %s for taskId=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
-    },
-    "-846078709": {
-      "message": "Configuration doesn't matter in finishing %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-814760297": {
-      "message": "Looking for task of %s in %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "-809771899": {
-      "message": "findFocusedWindow: Reached focused app=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-804217032": {
-      "message": "Skipping config check (will change): %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-799396645": {
-      "message": "Display id=%d is notified that Camera %s is closed, updating rotation.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
-    },
-    "-787664727": {
-      "message": "Cannot launch dream activity due to invalid state. dream component: %s packageName: %s",
-      "level": "ERROR",
-      "group": "WM_DEBUG_DREAM",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "-784959154": {
-      "message": "Attempted to add private presentation window to a non-private display.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-783405930": {
-      "message": "Performing post-rotate rotation",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-779535710": {
-      "message": "Transition %d: Set %s as transient-launch",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-779095785": {
-      "message": "        sibling is a participant with mode %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-778347463": {
-      "message": "Remove %s: mSurfaceController=%s mAnimatingExit=%b mRemoveOnExit=%b mHasSurface=%b surfaceShowing=%b animating=%b app-animation=%b mDisplayFrozen=%b callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-775004869": {
-      "message": "Not a match: %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "-774908272": {
-      "message": "Marking #%d animation as SYNC.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/TransitionController.java"
-    },
-    "-771177730": {
-      "message": "Removing focused app token:%s displayId=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-767091913": {
-      "message": "Content Recording: Handle incoming session on display %d, with a pre-existing session %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecordingController.java"
-    },
-    "-766059044": {
-      "message": "Display id=%d selected orientation %s (%d), got rotation %s (%d)",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "-760801764": {
-      "message": "onAnimationCancelled",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java"
-    },
-    "-760764543": {
-      "message": "Focus not requested for window=%s because it has no surface or is not focusable.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/InputMonitor.java"
-    },
-    "-754503024": {
-      "message": "Relayout %s: oldVis=%d newVis=%d. %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-743856570": {
-      "message": "shouldWaitAnimatingExit: isAnimating: %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-743431900": {
-      "message": "Configuration no differences in %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-732715767": {
-      "message": "Unable to retrieve window container to start recording for display %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "-729530161": {
-      "message": "Moving to DESTROYED: %s (no app)",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-711194343": {
-      "message": "Setting Activity.mLauncherTaskBehind to false. Activity=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/BackNavigationController.java"
-    },
-    "-706481945": {
-      "message": "TaskFragment parent info changed name=%s parentTaskId=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
-    },
-    "-705939410": {
-      "message": "Waiting for pause to complete...",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-703543418": {
-      "message": "      check sibling %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-702650156": {
-      "message": "Override with TaskFragment remote animation for transit=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "-701167286": {
-      "message": "applyAnimation: transit=%s, enter=%b, wc=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/WindowContainer.java"
-    },
-    "-694710814": {
-      "message": "Pausing rotation during drag",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DragState.java"
-    },
-    "-692907078": {
-      "message": "Handling the deferred animation after transition finished",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/BackNavigationController.java"
-    },
-    "-677449371": {
-      "message": "moveTaskToRootTask: moving task=%d to rootTaskId=%d toTop=%b",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "-672355406": {
-      "message": "  Rejecting as no-op: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-668956537": {
-      "message": "  THUMBNAIL %s: CREATE",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/SurfaceFreezer.java"
-    },
-    "-666510420": {
-      "message": "With display frozen, orientationChangeComplete=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "-658964693": {
-      "message": "onWindowAnimationFinished, wc=%s, type=%s, imeSnapshot=%s, target=%s",
-      "level": "INFO",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-655104359": {
-      "message": "Frontmost changed immersion: %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_IMMERSIVE",
-      "at": "com\/android\/server\/wm\/ActivityClientController.java"
-    },
-    "-653156702": {
-      "message": "createAppAnimations()",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "-648891906": {
-      "message": "Activity not running or entered PiP, resuming next.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "-641258376": {
-      "message": "realStartActivityLocked: Skipping start of r=%s some activities pausing...",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
-    },
-    "-639217716": {
-      "message": "setFocusedApp %s displayId=%d Callers=%s",
-      "level": "INFO",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-637815408": {
-      "message": "Invalid surface rotation angle in config_deviceTabletopRotations: %d",
-      "level": "ERROR",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "-636553602": {
-      "message": "commitVisibility: %s: visible=%b visibleRequested=%b, isInTransition=%b, runningAnimation=%b, caller=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-635082269": {
-      "message": "******** booted=%b msg=%b haveBoot=%b haveApp=%b haveWall=%b wallEnabled=%b haveKeyguard=%b",
-      "level": "INFO",
-      "group": "WM_DEBUG_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-627759820": {
-      "message": "Display id=%d is notified that Camera %s is open for package %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
-    },
-    "-622997754": {
-      "message": "postWindowRemoveCleanupLocked: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-622017164": {
-      "message": "Finish Transition: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/TransitionController.java"
-    },
-    "-597091183": {
-      "message": "Delete TaskDisplayArea uid=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
-    },
-    "-593535526": {
+    "7286191062634870297": {
       "message": "Binding proc %s with config %s",
       "level": "VERBOSE",
       "group": "WM_DEBUG_CONFIGURATION",
       "at": "com\/android\/server\/am\/ActivityManagerService.java"
     },
-    "-584061725": {
-      "message": "Content Recording: Accept session updating same display %d with granted consent, with an existing session %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecordingController.java"
-    },
-    "-583031528": {
-      "message": "%s",
-      "level": "INFO",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-576070986": {
-      "message": "Performing post-rotate rotation after seamless rotation",
-      "level": "INFO",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "-567946587": {
-      "message": "Requested redraw for orientation change: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-561092364": {
-      "message": "onPointerDownOutsideFocusLocked called on %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-549028919": {
-      "message": "enableScreenIfNeededLocked: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_BOOT",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-548282316": {
-      "message": "setLockTaskMode: Locking to %s Callers=%s",
-      "level": "WARN",
-      "group": "WM_DEBUG_LOCKTASK",
-      "at": "com\/android\/server\/wm\/LockTaskController.java"
-    },
-    "-547111355": {
-      "message": "hideIme Control target: %s ",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-545190927": {
-      "message": "<<< CLOSE TRANSACTION animate",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/WindowAnimator.java"
-    },
-    "-542756093": {
-      "message": "TaskFragment vanished name=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
-    },
-    "-532081937": {
-      "message": "  Commit activity becoming invisible: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-529187878": {
-      "message": "Reverting orientation after camera compat force rotation",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
-    },
-    "-521613870": {
-      "message": "App died during pause, not stopping: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "-519504830": {
-      "message": "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM transit=%s isEntrance=%b Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/AppTransition.java"
-    },
-    "-517666355": {
-      "message": "Content Recording: Display %d has content (%b) so pause recording",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "-509601642": {
-      "message": "    checking %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-507657818": {
-      "message": "Window %s is already added",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-503656156": {
-      "message": "Update process config of %s to new config %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "-497620140": {
-      "message": "Transaction ready, syncId=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/WindowOrganizerController.java"
-    },
-    "-496681057": {
-      "message": "Attempted to get remove mode of a display that does not exist: %d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-484194149": {
-      "message": "no-history finish of %s on new resume",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
-    },
-    "-483957611": {
-      "message": "Resuming configuration dispatch for %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-481924678": {
-      "message": "handleNotObscuredLocked w: %s, w.mHasSurface: %b, w.isOnScreen(): %b, w.isDisplayedLw(): %b, w.mAttrs.userActivityTimeout: %d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_KEEP_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "-479665533": {
-      "message": "DisplayRotationCompatPolicy: Multi-window toast not shown as package '%s' cannot be found.",
-      "level": "ERROR",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
-    },
-    "-464564167": {
-      "message": "Current transition prevents automatic focus change",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-463348344": {
-      "message": "Removing and adding activity %s to root task at top callers=%s",
-      "level": "INFO",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
-    "-451552570": {
-      "message": "Current focused window being animated by recents. Overriding back callback to recents controller callback.",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/BackNavigationController.java"
-    },
-    "-449118559": {
-      "message": "Trying to update display configuration for invalid process, pid=%d",
-      "level": "WARN",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "-445944810": {
-      "message": "finish(%b): mCanceled=%b",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
-    },
-    "-443173857": {
-      "message": "Moving pending starting from %s to %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-439951996": {
-      "message": "Disabling listeners",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "-436553282": {
-      "message": "Remove sleep token: tag=%s, displayId=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "-417730399": {
-      "message": "Preparing to sync a window that was already in the sync, so try dropping buffer. win=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_SYNC_ENGINE",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-415865166": {
-      "message": "findFocusedWindow: Found new focus @ %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-415346336": {
-      "message": "DeferredDisplayUpdater: partially applying DisplayInfo immediately",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/DeferredDisplayUpdater.java"
-    },
-    "-401282500": {
-      "message": "destroyIfPossible: r=%s destroy returned removed=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_CONTAINERS",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-401029526": {
-      "message": "%s: caller %d does not hold REAL_GET_TASKS; limiting output",
-      "level": "WARN",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "-399343789": {
-      "message": "Skipping %s: different user",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "-393505149": {
-      "message": "unable to update pointer icon",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-386552155": {
-      "message": "Attempted to set system decors flag to a display that does not exist: %d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-384639879": {
-      "message": "Acquiring screen wakelock due to %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_KEEP_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-381475323": {
-      "message": "DisplayContent: boot is waiting for window of type %d to be drawn",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_BOOT",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-379068494": {
-      "message": "unknownApps is not empty: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "-376950429": {
-      "message": "DeferredDisplayUpdater: deferring DisplayInfo update",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/DeferredDisplayUpdater.java"
-    },
-    "-374767836": {
-      "message": "setAppVisibility(%s, visible=%b): %s visible=%b mVisibleRequested=%b Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-373110070": {
-      "message": "Skipping task: (mismatch activity\/task) %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "-360208282": {
-      "message": "Animating wallpapers: old: %s hidden=%b new: %s hidden=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WALLPAPER",
-      "at": "com\/android\/server\/wm\/WallpaperController.java"
-    },
-    "-354571697": {
-      "message": "Existence Changed in transition %d: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-353495930": {
-      "message": "TaskFragmentTransaction changes are not collected in transition because there is an ongoing sync for applySyncTransaction().",
-      "level": "WARN",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/WindowOrganizerController.java"
-    },
-    "-347866078": {
-      "message": "Setting move animation on %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-344488673": {
-      "message": "Finishing drawing window %s: mDrawState=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
-    },
-    "-322743468": {
-      "message": "setInputMethodInputTarget %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-322035974": {
-      "message": "App freeze timeout expired.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-319689203": {
-      "message": "Reparenting to original parent: %s for %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/SurfaceAnimator.java"
-    },
-    "-317761482": {
-      "message": "Create sleep token: tag=%s, displayId=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "-317194205": {
-      "message": "clearLockedTasks: %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_LOCKTASK",
-      "at": "com\/android\/server\/wm\/LockTaskController.java"
-    },
-    "-315778658": {
-      "message": "transferTouchGesture failed because args transferFromToken or transferToToken is null",
-      "level": "ERROR",
-      "group": "WM_DEBUG_EMBEDDED_WINDOWS",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-312353598": {
-      "message": "Executing finish of activity: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "-310337305": {
-      "message": "Activity config changed during resume: %s, new next: %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "-304728471": {
-      "message": "New wallpaper: target=%s prev=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_WALLPAPER",
-      "at": "com\/android\/server\/wm\/WallpaperController.java"
-    },
-    "-302468788": {
-      "message": "Expected target rootTask=%s to be top most but found rootTask=%s",
-      "level": "WARN",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
-    },
-    "-292790591": {
-      "message": "Attempted to set IME policy to a display that does not exist: %d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-275077723": {
-      "message": "New animation: %s old animation: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WALLPAPER",
-      "at": "com\/android\/server\/wm\/WallpaperController.java"
-    },
-    "-266707683": {
-      "message": "Moving #%d from collecting to waiting.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
-      "at": "com\/android\/server\/wm\/TransitionController.java"
-    },
-    "-251259736": {
-      "message": "No longer freezing: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-248761393": {
-      "message": "startPausing: taskFrag =%s mResumedActivity=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "-240296576": {
-      "message": "handleAppTransitionReady: displayId=%d appTransition={%s} openingApps=[%s] closingApps=[%s] transit=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "-235225312": {
-      "message": "Skipping config check for initializing activity: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-233530384": {
-      "message": "Content Recording: Incoming session on display %d can't be set since it is already null; the corresponding VirtualDisplay must have already been removed.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecordingController.java"
-    },
-    "-230587670": {
-      "message": "SyncGroup %d:  Unfinished container: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_SYNC_ENGINE",
-      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
-    },
-    "-228813488": {
-      "message": "%s: Setting back callback %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-208825711": {
-      "message": "shouldWaitAnimatingExit: isWallpaperTarget: %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-208664771": {
-      "message": "Reparenting to leash for %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/SurfaceAnimator.java"
-    },
-    "-203358733": {
-      "message": "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
-    },
-    "-198463978": {
-      "message": "updateRotationUnchecked: alwaysSendConfiguration=%b forceRelayout=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-195654020": {
-      "message": "Attempt to transfer touch gesture with host window not associated with embedded window",
-      "level": "WARN",
-      "group": "WM_DEBUG_EMBEDDED_WINDOWS",
-      "at": "com\/android\/server\/wm\/EmbeddedWindowController.java"
-    },
-    "-193782861": {
-      "message": "Final remove of window: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_MOVEMENT",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-186693085": {
-      "message": "Starting a Recents transition which can be parallel.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "-182877285": {
-      "message": "Wallpaper layer changed: assigning layers + relayout",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WALLPAPER",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-180594244": {
-      "message": "Content Recording: Unable to tell MediaProjectionManagerService about visibility change on the active projection: %s",
-      "level": "ERROR",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "-177040661": {
-      "message": "Start rotation animation. customAnim=%s, mCurRotation=%s, mOriginalRotation=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
-    },
-    "-172326720": {
-      "message": "Saving icicle of %s: %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-168799453": {
-      "message": "Allowing features %d:0x%s",
-      "level": "WARN",
-      "group": "WM_DEBUG_LOCKTASK",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "-167822951": {
-      "message": "Attempted to add starting window to token with already existing starting window",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-163974242": {
-      "message": "setFinishTaskTransaction(%d): transaction=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
-    },
-    "-143556958": {
-      "message": "resumeNextFocusableActivityWhenRootTaskIsEmpty: %s, go home",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
-    "-125383273": {
-      "message": "Content Recording: waiting to record, so do nothing",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "-124316973": {
-      "message": "Translucent=%s Floating=%s ShowWallpaper=%s Disable=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-116086365": {
-      "message": "******************** ENABLING SCREEN!",
-      "level": "INFO",
-      "group": "WM_DEBUG_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "-108977760": {
-      "message": "Sandbox max bounds for uid %s to bounds %s. config to never sandbox = %s, config to always sandbox = %s, letterboxing from mismatch with parent bounds = %s, has mCompatDisplayInsets = %s, should create compatDisplayInsets = %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-106400104": {
-      "message": "Preload recents with %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
-    },
-    "-98422345": {
-      "message": "Focus window is closing.",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/BackNavigationController.java"
-    },
-    "-91393839": {
-      "message": "Set animatingExit: reason=remove\/applyAnimation win=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "-87705714": {
-      "message": "findFocusedWindow: focusedApp=null using new focus @ %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-86763148": {
-      "message": "  KILL SURFACE SESSION %s",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/Session.java"
-    },
-    "-81260230": {
-      "message": "Display id=%d is notified that Camera %s is closed, scheduling rotation update.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
-    },
-    "-81121442": {
-      "message": "ImeContainer just became organized but it doesn't have a parent or the parent doesn't have a surface control. mSurfaceControl=%s imeParentSurfaceControl=%s",
-      "level": "ERROR",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-80004683": {
-      "message": "Resume failed; resetting state to %s: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "-70719599": {
-      "message": "Unregister remote animations for organizer=%s uid=%d pid=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
-    },
-    "-57750640": {
-      "message": "show IME snapshot, ime target=%s, callers=%s",
-      "level": "INFO",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "-57572004": {
-      "message": "applyAnimation: anim=%s animAttr=0x%x transit=%s isEntrance=%b  canCustomizeAppTransition=%b Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/AppTransition.java"
-    },
-    "-55185509": {
-      "message": "setFocusedTask: taskId=%d touchedActivity=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_FOCUS",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "-50336993": {
-      "message": "moveFocusableActivityToTop: activity=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_FOCUS",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-33096143": {
-      "message": "applyAnimation: transition animation is disabled or skipped. container=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/WindowContainer.java"
-    },
-    "-32102932": {
-      "message": "Error sending initial configuration change to WindowContainer overlay",
-      "level": "ERROR",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowContainer.java"
-    },
-    "-21399771": {
-      "message": "activity %s already destroying, skipping request with reason:%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "-8483143": {
-      "message": "No root task above target root task=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
-    },
-    "-4263657": {
-      "message": "Got a buffer for request id=%d but latest request is id=%d. Since the buffer is out-of-date, drop it. win=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_SYNC_ENGINE",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "1877956": {
-      "message": "Content Recording: Display %d should start recording, but don't yet since the task is in PIP",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "3593205": {
-      "message": "commitVisibility: %s: visible=%b mVisibleRequested=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/WallpaperWindowToken.java"
-    },
-    "9803449": {
-      "message": "startFreezingDisplayLocked: exitAnim=%d enterAnim=%d called by %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "10608884": {
-      "message": "  FREEZE %s: CREATE",
-      "level": "INFO",
-      "group": "WM_SHOW_SURFACE_ALLOC",
-      "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
-    },
-    "11060725": {
-      "message": "Attempted to get system decors flag of a display that does not exist: %d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "17696244": {
-      "message": "startAnimation(): mPendingStart=%b mCanceled=%b",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
-    },
-    "33989965": {
-      "message": " Met condition %s for #%d (%d left)",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "34106798": {
-      "message": "Content Recording: Display %d state was (%d), is now (%d), so update recording?",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "34682671": {
-      "message": "Not moving display (displayId=%d) to top. Top focused displayId=%d. Reason: FLAG_STEAL_TOP_FOCUS_DISABLED",
-      "level": "INFO",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "35398067": {
-      "message": "goodToGo(): onAnimationStart, transit=%s, apps=%d, wallpapers=%d, nonApps=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "45285419": {
-      "message": "startingWindow was set but startingSurface==null, couldn't remove",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "51200510": {
-      "message": "  BLACK %s: DESTROY",
-      "level": "INFO",
-      "group": "WM_SHOW_SURFACE_ALLOC",
-      "at": "com\/android\/server\/wm\/BlackFrame.java"
-    },
-    "51628177": {
-      "message": "Attempted to get windowing mode of a display that does not exist: %d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "51927339": {
-      "message": "Skipping %s: voice session",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "61363198": {
-      "message": "Auto-PIP allowed, requesting PIP mode via requestStartTransition(): %s, willAutoPip: %b",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "74885950": {
-      "message": "Waiting for top state to be released by %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
-    },
-    "83950285": {
-      "message": "removeAnimation(%d)",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
-    },
-    "95216706": {
-      "message": "hideIme target: %s ",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "95902367": {
-      "message": "Relayout of %s: focusMayChange=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "100936473": {
-      "message": "Wallpaper animation!",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "102618780": {
-      "message": "resumeTopActivity: Pausing %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "108170907": {
-      "message": "Add starting %s: startingData=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "112145970": {
-      "message": "      SKIP: its sibling was rejected",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "114070759": {
-      "message": "New wallpaper target: %s prevTarget: %s caller=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WALLPAPER",
-      "at": "com\/android\/server\/wm\/WallpaperController.java"
-    },
-    "115358443": {
-      "message": "Focus changing: %s -> %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "138097009": {
-      "message": "NOSENSOR override is absent: reverting",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotationReversionController.java"
-    },
-    "140319294": {
-      "message": "IME target changed within ActivityRecord",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
-    },
-    "146871307": {
-      "message": "Tried to remove starting window but startingWindow was null: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "150351993": {
-      "message": "addWindow: %s startingWindow=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "152914409": {
-      "message": "  BLACK %s: CREATE layer=%d",
-      "level": "INFO",
-      "group": "WM_SHOW_SURFACE_ALLOC",
-      "at": "com\/android\/server\/wm\/BlackFrame.java"
-    },
-    "155482615": {
-      "message": "Focus requested for window=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/InputMonitor.java"
-    },
-    "174572959": {
-      "message": "DisplayArea info changed name=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
-    },
-    "182319432": {
-      "message": "        remove from targets %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "184362060": {
-      "message": "screenshotTask(%d): mCanceled=%b",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
-    },
-    "184610856": {
-      "message": "Start calculating TransitionInfo based on participants: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "186668272": {
-      "message": "Now changing app %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "189628502": {
-      "message": "Moving to STOPPING: %s (stop requested)",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "191486492": {
-      "message": "handleNotObscuredLocked: %s was holding screen wakelock but no longer has FLAG_KEEP_SCREEN_ON!!! called by%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_KEEP_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "200829729": {
-      "message": "ScreenRotationAnimation onAnimationEnd",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
-    },
-    "202263690": {
-      "message": "rotationForOrientation(orient=%s (%d), last=%s (%d)); user=%s (%d) %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "210750281": {
-      "message": "applyAnimationUnchecked, control: %s, task: %s, transit: %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
-    "215077284": {
-      "message": "Animation start delayed for %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/SurfaceAnimator.java"
-    },
-    "221540118": {
-      "message": "mUserActivityTimeout set to %d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_KEEP_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "232317536": {
-      "message": "Set intercept back pressed on root=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
-    },
-    "240271590": {
-      "message": "moveFocusableActivityToTop: unfocusable activity=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_FOCUS",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "241961619": {
-      "message": "Adding %s to %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/WindowToken.java"
-    },
-    "246676969": {
-      "message": "Attempted to add window with non-application token .%s Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "248210157": {
-      "message": "Finishing remote animation",
-      "level": "INFO",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "251812577": {
-      "message": "Register display organizer=%s uid=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
-    },
-    "254883724": {
-      "message": "addWindowToken: Attempted to add binder token: %s for already created window token: %s displayId=%d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "255339989": {
-      "message": "setFocusedRootTask: taskId=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_FOCUS",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "255692476": {
-      "message": "**** GOOD TO GO",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "259206414": {
-      "message": "Creating Transition: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/TransitionController.java"
-    },
-    "261227010": {
-      "message": "Content Recording: Unable to tell log windowing mode change: %s",
-      "level": "ERROR",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "269576220": {
-      "message": "Resuming rotation after drag",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DragState.java"
-    },
-    "269976641": {
-      "message": "goodToGo(): Animation canceled already",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "273212558": {
-      "message": "    info=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
-      "at": "com\/android\/server\/wm\/TransitionController.java"
-    },
-    "274773837": {
-      "message": "applyAnimation: anim=%s nextAppTransition=ANIM_CLIP_REVEAL transit=%s Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/AppTransition.java"
-    },
-    "283489582": {
-      "message": "Clear animatingExit: reason=exitAnimationDone win=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "288485303": {
-      "message": "Attempted to set remove mode to a display that does not exist: %d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "289967521": {
-      "message": "Check opening app=%s: allDrawn=%b startingDisplayed=%b startingMoved=%b isRelaunching()=%b startingWindow=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "292904800": {
-      "message": "Deferring rotation, animation in progress.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "295861935": {
-      "message": "startLockTaskMode: %s",
-      "level": "WARN",
-      "group": "WM_DEBUG_LOCKTASK",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "302969511": {
-      "message": "Task info changed taskId=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
-    },
-    "302992539": {
-      "message": "addAnimation(%s)",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
-    },
-    "306524472": {
-      "message": "Stop failed; moving to STOPPED: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "312030608": {
-      "message": "New topFocusedDisplayId=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "315395835": {
-      "message": "Trying to add window with invalid user=%d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "323235828": {
-      "message": "Delaying app transition for recents animation to finish",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "327461496": {
-      "message": "Complete pause: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "339482207": {
-      "message": "Content Recording: Display %d was already recording, so apply transformations if necessary",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "341055768": {
-      "message": "resumeTopActivity: Skip resume: need to start pausing",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "341360111": {
-      "message": "selectAnimation in %s: transit=%d",
-      "level": "INFO",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/DisplayPolicy.java"
-    },
-    "342460966": {
-      "message": "DRAG %s: pos=(%d,%d)",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/DragState.java"
-    },
-    "344795667": {
-      "message": "*** APP TRANSITION TIMEOUT. displayId=%d isTransitionSet()=%b mOpeningApps.size()=%d mClosingApps.size()=%d mChangingApps.size()=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransition.java"
-    },
-    "350168164": {
-      "message": "Removing activity %s, reason= %s callers=%s",
-      "level": "INFO",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "355720268": {
-      "message": "stopFreezingDisplayLocked: Unfreezing now",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "360319850": {
-      "message": "fractionRendered scale=%f",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_TPL",
-      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
-    },
-    "364992694": {
-      "message": "freezeDisplayRotation: current rotation=%d, new rotation=%d, caller=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "371173718": {
-      "message": "finishSync cancel=%b for %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_SYNC_ENGINE",
-      "at": "com\/android\/server\/wm\/WindowContainer.java"
-    },
-    "371641947": {
-      "message": "Window Manager Crash %s",
-      "level": "WTF",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "372792199": {
-      "message": "Non-null activity for system window of rootType=%d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "374506950": {
-      "message": "Reporting activity moved to display, activityRecord=%s, displayId=%d, config=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_SWITCH",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "374972436": {
-      "message": "performEnableScreen: Waiting for anim complete",
-      "level": "INFO",
-      "group": "WM_DEBUG_BOOT",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "378825104": {
-      "message": "Enqueueing pending pause: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "378890013": {
-      "message": "Apply and finish immediately because player is disabled for transition #%d .",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "385237117": {
-      "message": "moveFocusableActivityToTop: already on top and focused, activity=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_FOCUS",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "385595355": {
-      "message": "Starting animation on %s: type=%d, anim=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowContainer.java"
-    },
-    "390947100": {
-      "message": "Screenshotting %s [%s]",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "397382873": {
-      "message": "Moving to PAUSED: %s %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "397862437": {
-      "message": "Cancelling animation restarting=%b for %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/SurfaceAnimator.java"
-    },
-    "399841913": {
-      "message": "SURFACE RECOVER DESTROY: %s",
-      "level": "INFO",
-      "group": "WM_SHOW_SURFACE_ALLOC",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "405146734": {
-      "message": "  Final targets: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "416924848": {
-      "message": "InsetsSource Control %s for target %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_WINDOW_INSETS",
-      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
-    },
-    "417311568": {
-      "message": "onResize: Resizing %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RESIZE",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "419378610": {
-      "message": "Content Recording: Apply transformations of shift %d x %d, scale %f x %f, crop (aka recorded content size) %d x %d for display %d; display has size %d x %d; surface has size %d x %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "422634333": {
-      "message": "First draw done in potential wallpaper target %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WALLPAPER",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "424524729": {
-      "message": "Attempted to add wallpaper window with unknown token %s.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "431715812": {
-      "message": "Launch on display check: allow launch any on display",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
-    },
-    "435494046": {
-      "message": "Attempted to add window to a display for which the application does not have access: %d.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "463993897": {
-      "message": "Aborted waiting for drawn: %s",
-      "level": "WARN",
-      "group": "WM_DEBUG_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "485170982": {
-      "message": "Not finishing noHistory %s on stop because we're just sleeping",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "487621047": {
-      "message": "DisplayArea vanished name=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
-    },
-    "508887531": {
-      "message": "applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/AppTransition.java"
-    },
-    "528150092": {
-      "message": "        keep as target %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "531242746": {
-      "message": "  THUMBNAIL %s: CREATE",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/WindowContainerThumbnail.java"
-    },
-    "531891870": {
-      "message": "Previous Destination is Activity:%s Task:%s removedContainer:%s, backType=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/BackNavigationController.java"
-    },
-    "532771960": {
-      "message": "Adding untrusted state listener=%s with id=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TPL",
-      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
-    },
-    "535103992": {
-      "message": "Wallpaper may change!  Adjusting",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WALLPAPER",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "539077569": {
-      "message": "Clear freezing of %s force=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "544101314": {
-      "message": "performEnableScreen: Waited %dms for all windows to be drawn",
-      "level": "INFO",
-      "group": "WM_DEBUG_BOOT",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "556758086": {
-      "message": "Applying new update lock state '%s' for %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_IMMERSIVE",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "557227556": {
-      "message": "onAnimationFinished(): Notify animation finished:",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "558823034": {
-      "message": "SURFACE isOpaque=%b: %s",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
-    },
-    "573582981": {
-      "message": "reparent: moving activity=%s to new task fragment in task=%d at %d",
-      "level": "INFO",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "579298675": {
-      "message": "Moving to DESTROYED: %s (removed from history)",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "585096182": {
-      "message": "SURFACE isColorSpaceAgnostic=%b: %s",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
-    },
-    "585839596": {
-      "message": "call showInsets(ime) on %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
-    },
-    "594260577": {
-      "message": "createWallpaperAnimations()",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "600140673": {
-      "message": "checkBootAnimationComplete: Waiting for anim complete",
-      "level": "INFO",
-      "group": "WM_DEBUG_BOOT",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "601283564": {
-      "message": "Dream packageName does not match active dream. Package %s does not match %s",
-      "level": "ERROR",
-      "group": "WM_DEBUG_DREAM",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "605179032": {
-      "message": "checkIfInThreshold fractionRendered=%f alpha=%f currTimeMs=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_TPL",
-      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
-    },
-    "608694300": {
-      "message": "  NEW SURFACE SESSION %s",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/Session.java"
-    },
-    "612856628": {
-      "message": "Content Recording: Stop MediaProjection on virtual display %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "620519522": {
-      "message": "findFocusedWindow: No focusable windows, display=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "628276090": {
-      "message": "Delaying app transition for screen rotation animation to finish",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "631792420": {
-      "message": "Attempted to add window with token that is not a window: %s.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "638429464": {
-      "message": "\tRemove container=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "644675193": {
-      "message": "Real start recents",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
-    },
-    "646155519": {
-      "message": "Started intent=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
-    },
-    "646981048": {
-      "message": "Invalid displayId for requestScrollCapture: %d",
-      "level": "ERROR",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "662572728": {
-      "message": "Attempted to add a toast window with bad token %s.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "665256544": {
-      "message": "All windows drawn!",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "666937535": {
-      "message": "attachWindowContextToDisplayArea: trying to attach to a non-existing display:%d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "669361121": {
-      "message": "Sleep still need to stop %d activities",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "674932310": {
-      "message": "Setting Intent of %s to target %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
-    "675705156": {
-      "message": "resumeTopActivity: Top activity resumed %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "685047360": {
-      "message": "Resizing window %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_RESIZE",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "686185515": {
-      "message": "Resize reasons for w=%s:  %s configChanged=%b didFrameInsetsChange=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_RESIZE",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "691515534": {
-      "message": "  Commit wallpaper becoming invisible: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "693423992": {
-      "message": "setAnimationLocked: setting mFocusMayChange true",
-      "level": "INFO",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "701366755": {
-      "message": "Attempt to transfer touch gesture with non-existent embedded window",
-      "level": "WARN",
-      "group": "WM_DEBUG_EMBEDDED_WINDOWS",
-      "at": "com\/android\/server\/wm\/EmbeddedWindowController.java"
-    },
-    "704998117": {
-      "message": "Failed to create surface control for %s",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "708142634": {
-      "message": "Top resumed state released %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
-    },
-    "715749922": {
-      "message": "Allowlisting %d:%s",
-      "level": "WARN",
-      "group": "WM_DEBUG_LOCKTASK",
-      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
-    },
-    "723575093": {
-      "message": "Attempted to add window with a client %s that is dead. Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "726205185": {
-      "message": "Moving to DESTROYED: %s (destroy skipped)",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "733466617": {
-      "message": "Wallpaper token %s visible=%b",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_WALLPAPER",
-      "at": "com\/android\/server\/wm\/WallpaperWindowToken.java"
-    },
-    "736692676": {
-      "message": "Config is relaunching %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "743418423": {
-      "message": "Sending TaskFragment error exception=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
-    },
-    "744171317": {
-      "message": "      SKIP: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "745391677": {
-      "message": "  CREATE SURFACE %s IN SESSION %s: pid=%d format=%d flags=0x%x \/ %s",
-      "level": "INFO",
-      "group": "WM_SHOW_SURFACE_ALLOC",
-      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
-    },
-    "765395228": {
-      "message": "onAnimationFinished(): controller=%s reorderMode=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
-    },
-    "769218938": {
-      "message": "Loaded animation %s for %s, duration: %d, stack=%s",
-      "level": "INFO",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowContainer.java"
-    },
-    "781471998": {
-      "message": "moveWindowTokenToDisplay: Cannot move to the original display for token: %s",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "782864973": {
-      "message": "Releasing screen wakelock, obscured by %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_KEEP_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "791468751": {
-      "message": "Pausing rotation during re-position",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/TaskPositioner.java"
-    },
-    "793568608": {
-      "message": "        SKIP: sibling is visible but not part of transition",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "794570322": {
-      "message": "Now closing app %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "801521566": {
-      "message": "Content Recording: Attempting to mirror %d from %d but no DisplayContent associated. Changing to mirror default display.",
-      "level": "WARN",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "806891543": {
-      "message": "Setting mOrientationChangeComplete=true because wtoken %s numInteresting=%d numDrawn=%d",
-      "level": "INFO",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "810599500": {
-      "message": "SURFACE isSecure=%b: %s",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "824532141": {
-      "message": "lastState=%s newState=%s alpha=%f minAlpha=%f fractionRendered=%f minFractionRendered=%f",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_TPL",
-      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
-    },
-    "829434921": {
-      "message": "Draw state now committed in %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
-    },
-    "835814848": {
-      "message": "%s",
-      "level": "INFO",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "851368695": {
-      "message": "Deferred transition id=%d has been continued before the TaskFragmentTransaction=%s is finished",
-      "level": "WARN",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
-    },
-    "872933199": {
-      "message": "Changing focus from %s to %s displayId=%d Callers=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "873160948": {
-      "message": "Activity=%s reparent to taskId=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
-    },
-    "873914452": {
-      "message": "goodToGo()",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "892244061": {
-      "message": "Waiting for drawn %s: removed=%b visible=%b mHasSurface=%b drawState=%d",
-      "level": "INFO",
-      "group": "WM_DEBUG_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "895158150": {
-      "message": "allPausedActivitiesComplete: r=%s state=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "898863925": {
-      "message": "Attempted to add QS dialog window with unknown token %s.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "906215061": {
-      "message": "Apply window transaction, syncId=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/WindowOrganizerController.java"
-    },
-    "913494177": {
-      "message": "removeAllWindowsIfPossible: removing win=%s",
-      "level": "WARN",
-      "group": "WM_DEBUG_WINDOW_MOVEMENT",
-      "at": "com\/android\/server\/wm\/WindowToken.java"
-    },
-    "916191774": {
-      "message": "Orientation change complete in %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
-    },
-    "935418348": {
-      "message": "resumeTopActivity: Skip resume: some activity pausing.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "937080808": {
-      "message": "Content Recording: Recorded task is removed, so stop recording on display %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "939638078": {
-      "message": "config_deviceTabletopRotations is not defined. Half-fold letterboxing will work inconsistently.",
-      "level": "WARN",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "948208142": {
-      "message": "Setting Activity.mLauncherTaskBehind to true. Activity=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/BackNavigationController.java"
-    },
-    "950074526": {
-      "message": "setLockTaskMode: Can't lock due to auth",
-      "level": "WARN",
-      "group": "WM_DEBUG_LOCKTASK",
-      "at": "com\/android\/server\/wm\/LockTaskController.java"
-    },
-    "954470154": {
-      "message": "FORCED DISPLAY SCALING DISABLED",
-      "level": "INFO",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "956374481": {
-      "message": "removeLockedTask: task=%s last task, reverting locktask mode. Callers=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_LOCKTASK",
-      "at": "com\/android\/server\/wm\/LockTaskController.java"
-    },
-    "958338552": {
-      "message": "grantEmbeddedWindowFocus win=%s dropped focus so setting focus to null since no candidate was found",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "959486822": {
-      "message": "setSyncGroup #%d on %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_SYNC_ENGINE",
-      "at": "com\/android\/server\/wm\/WindowContainer.java"
-    },
-    "966569777": {
-      "message": "SyncGroup %d: onSurfacePlacement checking %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_SYNC_ENGINE",
-      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
-    },
-    "969323241": {
-      "message": "Sending new config to %s, config: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "972354148": {
-      "message": "\tcontainer=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "975028389": {
-      "message": "unable to call receiver for empty keyboard shortcuts",
-      "level": "ERROR",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "975275467": {
-      "message": "Set animatingExit: reason=remove\/isAnimating win=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "979347997": {
-      "message": "Launch on display check: disallow activity embedding without permission.",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
-    },
-    "987903142": {
-      "message": "Sleep needs to pause %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "996960396": {
-      "message": "Starting Transition %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "1001904964": {
-      "message": "***** BOOT TIMEOUT: forcing display enabled",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1015746067": {
-      "message": "Display id=%d is ignoring orientation request for %d, return %d following a per-app override for %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "1022095595": {
-      "message": "TaskFragment info changed name=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
-    },
-    "1023413388": {
-      "message": "Finish waiting for pause of: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1030898920": {
-      "message": "notifyInsetsControlChanged for %s ",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_WINDOW_INSETS",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "1033274509": {
-      "message": "moveWindowTokenToDisplay: Attempted to move non-existing token: %s",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1040675582": {
-      "message": "Can't report activity configuration update - client not running, activityRecord=%s",
-      "level": "WARN",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1042363394": {
-      "message": "Attempt to transfer touch gesture using a host window with no input channel",
-      "level": "WARN",
-      "group": "WM_DEBUG_EMBEDDED_WINDOWS",
-      "at": "com\/android\/server\/wm\/EmbeddedWindowController.java"
-    },
-    "1046228706": {
-      "message": "Defer transition id=%d for TaskFragmentTransaction=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
-    },
-    "1046922686": {
-      "message": "requestScrollCapture: caught exception dispatching callback: %s",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1047505501": {
-      "message": "notifyInsetsChanged for %s ",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_WINDOW_INSETS",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "1047769218": {
-      "message": "Finishing activity r=%s, result=%d, data=%s, reason=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1049367566": {
-      "message": "Sending to proc %s new config %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/WindowProcessController.java"
-    },
-    "1051545910": {
-      "message": "Exit animation finished in %s: remove=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "1068803972": {
-      "message": "Activity paused: token=%s, timeout=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1073230342": {
-      "message": "startAnimation",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java"
-    },
-    "1075460705": {
-      "message": "Continue transition id=%d for TaskFragmentTransaction=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
-    },
-    "1087494661": {
-      "message": "Clear window stuck on animatingExit status: %s",
-      "level": "WARN",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "1088929964": {
-      "message": "onLockTaskPackagesUpdated: starting new locktask task=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_LOCKTASK",
-      "at": "com\/android\/server\/wm\/LockTaskController.java"
-    },
-    "1089714158": {
-      "message": "  FREEZE %s: DESTROY",
-      "level": "INFO",
-      "group": "WM_SHOW_SURFACE_ALLOC",
-      "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
-    },
-    "1090378847": {
-      "message": "Checking %d windows",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_TPL",
-      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
-    },
-    "1100065297": {
-      "message": "Attempted to get IME policy of a display that does not exist: %d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1105210816": {
-      "message": "Skipping config check in destroyed state %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1112047265": {
-      "message": "finishDrawingWindow: %s mDrawState=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1115248873": {
-      "message": "Calling onTransitionReady: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "1115417974": {
-      "message": "FORCED DISPLAY SIZE: %dx%d",
-      "level": "INFO",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1126328412": {
-      "message": "Scheduling idle now: forceIdle=%b immediate=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1140424002": {
-      "message": "Finished screen turning on...",
-      "level": "INFO",
-      "group": "WM_DEBUG_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/DisplayPolicy.java"
-    },
-    "1145016093": {
-      "message": "Content Recording: Attempting to mirror self on %d",
-      "level": "WARN",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "1149424314": {
-      "message": "Unregister display organizer=%s uid=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
-    },
-    "1151072840": {
-      "message": "collectTaskRemoteAnimations, target: %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
-    },
-    "1164325516": {
-      "message": "onExitAnimationDone in %s: exiting=%b remove=%b selfAnimating=%b anim=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "1166381079": {
-      "message": "Execute app transition: %s, displayId: %d Callers=%s",
-      "level": "WARN",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "1175495463": {
-      "message": "ImeContainer just became organized. Reparenting under parent. imeParentSurfaceControl=%s",
-      "level": "INFO",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "1178653181": {
-      "message": "Old wallpaper still the target.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WALLPAPER",
-      "at": "com\/android\/server\/wm\/WallpaperController.java"
-    },
-    "1191587912": {
-      "message": "Moved rootTask=%s behind rootTask=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
-    },
-    "1192413464": {
-      "message": "Comparing existing cls=%s \/aff=%s to new cls=%s \/aff=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "1208313423": {
-      "message": "addWindowToken: Attempted to add token: %s for non-exiting displayId=%d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1210037962": {
-      "message": "Register remote animations for organizer=%s uid=%d pid=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
-    },
-    "1219600119": {
-      "message": "addWindow: win=%s Callers=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_FOCUS",
-      "at": "com\/android\/server\/wm\/WindowToken.java"
-    },
-    "1224184681": {
-      "message": "No longer Stopped: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1224307091": {
-      "message": "checkBootAnimationComplete: Animation complete!",
-      "level": "INFO",
-      "group": "WM_DEBUG_BOOT",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1239439010": {
-      "message": "moveFocusableActivityToTop: set focused, activity=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_FOCUS",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1251721200": {
-      "message": "unregister failed, couldn't find deathRecipient for %s with id=%d",
-      "level": "ERROR",
-      "group": "WM_DEBUG_TPL",
-      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
-    },
-    "1252594551": {
-      "message": "Window types in WindowContext and LayoutParams.type should match! Type from LayoutParams is %d, but type from WindowContext is %d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1254403969": {
-      "message": "Surface returned was null: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1264179654": {
-      "message": "No focused window, defaulting to top current task's window",
-      "level": "WARN",
-      "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/BackNavigationController.java"
-    },
-    "1270792394": {
-      "message": "Resumed after relaunch %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1282992082": {
-      "message": "Disabling player for transition #%d because display isn't enabled yet",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/TransitionController.java"
-    },
-    "1284122013": {
-      "message": "TaskFragment appeared name=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
-    },
-    "1288731814": {
-      "message": "WindowState.hideLw: setting mFocusMayChange true",
-      "level": "INFO",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "1288920916": {
-      "message": "Error sending initial insets change to WindowContainer overlay",
-      "level": "ERROR",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowContainer.java"
-    },
-    "1305412562": {
+    "-4921282642721622589": {
       "message": "Report configuration: %s %s",
       "level": "VERBOSE",
       "group": "WM_DEBUG_CONFIGURATION",
       "at": "com\/android\/server\/wm\/ActivityClientController.java"
     },
-    "1309365288": {
-      "message": "Removing dim surface %s on transaction %s",
+    "-1597980207704427048": {
+      "message": "Frontmost changed immersion: %s",
       "level": "DEBUG",
-      "group": "WM_DEBUG_DIMMER",
-      "at": "com\/android\/server\/wm\/SmoothDimmer.java"
+      "group": "WM_DEBUG_IMMERSIVE",
+      "at": "com\/android\/server\/wm\/ActivityClientController.java"
     },
-    "1316533291": {
-      "message": "State movement: %s from:%s to:%s reason:%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
+    "-6509265758887333864": {
+      "message": "Can't report activity moved to display - client not running, activityRecord=%s, displayId=%d",
+      "level": "WARN",
+      "group": "WM_DEBUG_SWITCH",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "1325649102": {
-      "message": "Bad requesting window %s",
+    "-4183059578873561863": {
+      "message": "Reporting activity moved to display, activityRecord=%s, displayId=%d, config=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SWITCH",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "7435279034964784633": {
+      "message": "Can't report activity configuration update - client not running, activityRecord=%s",
       "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1329340614": {
-      "message": "Orientation not waiting for draw in %s, surfaceController %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "1330804250": {
-      "message": "addChild: %s at top.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
-    "1331177619": {
-      "message": "Attempted to add a toast window with unknown token %s.  Aborting.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1335791109": {
-      "message": "createSurface %s: mDrawState=DRAW_PENDING",
-      "level": "INFO",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
-    },
-    "1337596507": {
-      "message": "Sending to proc %s new compat %s",
-      "level": "VERBOSE",
       "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/CompatModePackages.java"
-    },
-    "1346895820": {
-      "message": "ScreenRotation still animating: type: %d\nmDisplayAnimator: %s\nmEnterBlackFrameAnimator: %s\nmRotateScreenAnimator: %s\nmScreenshotRotationAnimator: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
-    },
-    "1360176455": {
-      "message": "stopFreezingDisplayLocked: Returning waitingForConfig=%b, waitingForRemoteDisplayChange=%b, mAppsFreezingScreen=%d, mWindowsFreezingScreen=%d, mClientFreezingScreen=%b, mOpeningApps.size()=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1364126018": {
-      "message": "Resumed activity; dropping state of: %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_STATES",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "1364498663": {
-      "message": "notifyAppResumed: wasStopped=%b %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1373000889": {
-      "message": "abortShowImePostLayout",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
-    },
-    "1381227466": {
-      "message": "App is requesting an orientation, return %d for display id=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/TaskDisplayArea.java"
-    },
-    "1382634842": {
-      "message": "Unregistering listener=%s with id=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TPL",
-      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
-    },
-    "1393721079": {
-      "message": "Starting remote display change: from [rot = %d], to [%dx%d, rot = %d]",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/RemoteDisplayChangeController.java"
-    },
-    "1396893178": {
-      "message": "createRootTask unknown displayId=%d",
-      "level": "ERROR",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
-    },
-    "1401295262": {
-      "message": "Mode default, asking user",
-      "level": "WARN",
-      "group": "WM_DEBUG_LOCKTASK",
-      "at": "com\/android\/server\/wm\/LockTaskController.java"
-    },
-    "1401700824": {
-      "message": "Window drawn win=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1422781269": {
-      "message": "Resuming rotation after re-position",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/TaskPositioner.java"
-    },
-    "1423418408": {
-      "message": "unable to restore pointer icon",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1430336882": {
-      "message": "findFocusedWindow: focusedApp windows not focusable using new focus @ %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "1434383382": {
-      "message": "Attempted to get flag of a display that does not exist: %d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1445704347": {
-      "message": "coveredRegionsAbove updated with %s frame:%s region:%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_TPL",
-      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
-    },
-    "1448683958": {
-      "message": "Override pending remote transitionSet=%b adapter=%s",
-      "level": "INFO",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransition.java"
-    },
-    "1457990604": {
-      "message": "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM_IN_PLACE transit=%s Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/AppTransition.java"
-    },
-    "1460759282": {
-      "message": "getAnimationTarget in=%s, out=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "1463355909": {
-      "message": "Queueing legacy sync-set: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
-      "at": "com\/android\/server\/wm\/TransitionController.java"
-    },
-    "1469310004": {
-      "message": "          SKIP: common mode mismatch. was %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "1473051122": {
-      "message": "Pausing configuration dispatch for  %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1494644409": {
-      "message": "  Rejecting as detached: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "1495525537": {
-      "message": "createWallpaperAnimations()",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
-    },
-    "1497304204": {
-      "message": "Deferring rotation, rotation is paused.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "1504168072": {
-      "message": "removeIfPossible: %s callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "1511273241": {
-      "message": "Refreshing activity for camera compatibility treatment, activityRecord=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
-    },
-    "1518495446": {
-      "message": "removeWindowToken: Attempted to remove non-existing token: %s",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1519757176": {
-      "message": "setHomeApp(%s)",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
-    },
-    "1520642640": {
-      "message": "Attempt to transfer touch gesture using embedded window with no associated host",
-      "level": "WARN",
-      "group": "WM_DEBUG_EMBEDDED_WINDOWS",
-      "at": "com\/android\/server\/wm\/EmbeddedWindowController.java"
-    },
-    "1521476038": {
-      "message": "Attempted to set flag to a display that does not exist: %d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1524174282": {
-      "message": "Launch on display check: no caller info, skip check",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
-    },
-    "1525976603": {
-      "message": "cancelAnimation(): reason=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
-    },
-    "1528528509": {
-      "message": "No thumbnail header bitmap for: %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1546187372": {
-      "message": "Content Recording: Pause the recording session on display %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecordingController.java"
-    },
-    "1557732761": {
-      "message": "For Intent %s bringing to top: %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "1563755163": {
-      "message": "Permission Denial: %s from pid=%d, uid=%d requires %s",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1577579529": {
-      "message": "win=%s destroySurfaces: appStopped=%b win.mWindowRemovalAllowed=%b win.mRemoveOnExit=%b",
-      "level": "ERROR",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "1584270979": {
-      "message": "applyAnimation: container=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/WindowContainer.java"
-    },
-    "1589610525": {
-      "message": "applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS: anim=%s transit=%s isEntrance=true Callers=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/AppTransition.java"
-    },
-    "1610646518": {
-      "message": "Enqueueing pending finish: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1621562070": {
-      "message": "    startWCT=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
-      "at": "com\/android\/server\/wm\/TransitionController.java"
-    },
-    "1628345525": {
-      "message": "Now opening app %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "1634557978": {
-      "message": "**** Dismissing screen rotation animation",
-      "level": "INFO",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1635062046": {
-      "message": "Skipping config check invisible: %s",
+    "-7418876140361338495": {
+      "message": "Sending new config to %s, config: %s",
       "level": "VERBOSE",
       "group": "WM_DEBUG_CONFIGURATION",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "1635462459": {
-      "message": "onMovedByResize: Moving %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RESIZE",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "1640436199": {
-      "message": "No app is requesting an orientation, return %d for display id=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/TaskDisplayArea.java"
-    },
-    "1653025361": {
-      "message": "Register task fragment organizer=%s uid=%d pid=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
-    },
-    "1653210583": {
-      "message": "Removing app %s delayed=%b animation=%s animating=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
+    "-4284934398288119962": {
+      "message": "Can't report activity position update - client not running, activityRecord=%s",
+      "level": "WARN",
+      "group": "WM_DEBUG_STATES",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "1658605381": {
-      "message": "onImeControlTargetChanged %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/InsetsStateController.java"
-    },
-    "1661414284": {
-      "message": "Content Recording: Unable to tell MediaProjectionManagerService about resizing the active projection: %s",
-      "level": "ERROR",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "1670933628": {
-      "message": " Setting allReady override",
+    "7244227111034368231": {
+      "message": "Sending position change to %s, onTop: %b",
       "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "1674747211": {
-      "message": "%s forcing orientation to %d for display id=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayArea.java"
-    },
-    "1677260366": {
-      "message": "Finish starting %s: first real window is shown, no animation",
+    "338586566486930495": {
+      "message": "Checking theme of starting window: 0x%x",
       "level": "VERBOSE",
       "group": "WM_DEBUG_STARTING_WINDOW",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "1679569477": {
-      "message": "Configuration doesn't matter not running %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1687944543": {
-      "message": "Content Recording: Unable to update recording for display %d to new bounds %s and\/or orientation %d and\/or surface size %s, since the surface is not available.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "1699269281": {
-      "message": "Don't organize or trigger events for untrusted displayId=%d",
-      "level": "WARN",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
-    },
-    "1712935427": {
-      "message": "Content Recording: Unable to start recording for display %d since the surface is not available.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "1720229827": {
-      "message": "Creating animation bounds layer",
-      "level": "INFO",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1721036256": {
-      "message": "Attempt to transfer touch gesture using embedded window that has no input channel",
-      "level": "WARN",
-      "group": "WM_DEBUG_EMBEDDED_WINDOWS",
-      "at": "com\/android\/server\/wm\/EmbeddedWindowController.java"
-    },
-    "1730300180": {
-      "message": "PendingStartTransaction found",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_SYNC_ENGINE",
-      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
-    },
-    "1735199721": {
-      "message": "Queueing transition: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
-      "at": "com\/android\/server\/wm\/TransitionController.java"
-    },
-    "1739298851": {
-      "message": "removeWindowToken: Attempted to remove token: %s for non-exiting displayId=%d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1746778201": {
-      "message": "Set freezing of %s: visible=%b freezing=%b visibleRequested=%b. %s",
-      "level": "INFO",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1750878635": {
-      "message": "Content Recording: Provided surface for recording on display %d is not present, so do not update the surface",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONTENT_RECORDING",
-      "at": "com\/android\/server\/wm\/ContentRecorder.java"
-    },
-    "1756082882": {
-      "message": "Orientation change skips hidden %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
-    },
-    "1774661765": {
-      "message": "Devices still not ready after waiting %d milliseconds before attempting to detect safe mode.",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1781673113": {
-      "message": "onAnimationFinished(): targetRootTask=%s targetActivity=%s mRestoreTargetBehindRootTask=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
-    },
-    "1786463281": {
-      "message": "Adding trusted state listener=%s with id=%d",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TPL",
-      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
-    },
-    "1789321832": {
-      "message": "Then token:%s is invalid. It might be removed",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1789603530": {
-      "message": "Removing activity %s hasSavedState=%b stateNotNeeded=%s finishing=%b state=%s callers=%s",
-      "level": "INFO",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1794249572": {
-      "message": "Requesting StartTransition: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/TransitionController.java"
-    },
-    "1804245629": {
-      "message": "Attempted to add starting window to token but already cleaned",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1805116444": {
-      "message": "We don't support remote animation for Task with multiple TaskFragmentOrganizers.",
-      "level": "ERROR",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "1810019902": {
-      "message": "TRANSIT_FLAG_OPEN_BEHIND,  adding %s to mOpeningApps",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1810209625": {
-      "message": "Animation done in %s: exiting=%b, reportedVisible=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
-    },
-    "1810872941": {
-      "message": "setWallpaperCropHints: non-existent wallpaper token: %s",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1820873642": {
-      "message": "SyncGroup %d:  Unfinished dependencies: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_SYNC_ENGINE",
-      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
-    },
-    "1822314934": {
-      "message": "Expected target rootTask=%s to restored behind rootTask=%s but it is behind rootTask=%s",
-      "level": "WARN",
-      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
-    },
-    "1822843721": {
-      "message": "Aborted starting %s: startingData=%s",
+    "-2561793317091789573": {
+      "message": "Translucent=%s Floating=%s ShowWallpaper=%s Disable=%s",
       "level": "VERBOSE",
       "group": "WM_DEBUG_STARTING_WINDOW",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "1824105730": {
-      "message": "setLockTaskAuth: task=%s mLockTaskAuth=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_LOCKTASK",
-      "at": "com\/android\/server\/wm\/Task.java"
-    },
-    "1829094918": {
-      "message": "onLockTaskPackagesUpdated: removing %s mLockTaskAuth()=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_LOCKTASK",
-      "at": "com\/android\/server\/wm\/LockTaskController.java"
-    },
-    "1831008694": {
-      "message": "Loading animation for app transition. transit=%s enter=%b frame=%s insets=%s surfaceInsets=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/WindowContainer.java"
-    },
-    "1836214582": {
-      "message": "startingData was nulled out before handling mAddStartingWindow: %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STARTING_WINDOW",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1836306327": {
-      "message": "Skipping set freeze of %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1856783490": {
-      "message": "resumeTopActivity: Restarting %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "1865125884": {
-      "message": "finishScreenTurningOn: mAwake=%b, mScreenOnEarly=%b, mScreenOnFully=%b, mKeyguardDrawComplete=%b, mWindowManagerDrawComplete=%b",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_SCREEN_ON",
-      "at": "com\/android\/server\/wm\/DisplayPolicy.java"
-    },
-    "1866772666": {
-      "message": "SAFE MODE not enabled",
-      "level": "INFO",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1874559932": {
-      "message": "The TaskDisplayArea with %s does not exist.",
-      "level": "WARN",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/DisplayAreaPolicyBuilder.java"
-    },
-    "1877863087": {
-      "message": "Display id=%d is ignoring orientation request for %d, return %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
-    },
-    "1879463933": {
-      "message": "attachWindowContextToWindowToken: calling from non-existing process pid=%d uid=%d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "1891501279": {
-      "message": "cancelAnimation(): reason=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "1912291550": {
-      "message": "Sleep still waiting to pause %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "1918448345": {
-      "message": "Task appeared taskId=%d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_ORGANIZER",
-      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
-    },
-    "1928325128": {
-      "message": "Run showImeRunner",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_IME",
-      "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
-    },
-    "1931178855": {
-      "message": "\tnonApp=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "1945495497": {
-      "message": "Focused window didn't have a valid surface drawn.",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_BACK_PREVIEW",
-      "at": "com\/android\/server\/wm\/BackNavigationController.java"
-    },
-    "1946983717": {
-      "message": "Waiting for screen on due to %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_STATES",
-      "at": "com\/android\/server\/wm\/TaskFragment.java"
-    },
-    "1947239194": {
-      "message": "Deferring rotation, still finishing previous rotation",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "1947936538": {
-      "message": "Found matching class!",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
-    },
-    "1955470028": {
-      "message": "computeFractionRendered: visibleRegion=%s screenBounds=%s contentSize=%s scale=%f,%f",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_TPL",
-      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
-    },
-    "1964565370": {
-      "message": "Starting remote animation",
-      "level": "INFO",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "1967975839": {
-      "message": "Changing app %s visible=%b performLayout=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
-    },
-    "1984782949": {
-      "message": ">>> OPEN TRANSACTION animate",
-      "level": "INFO",
-      "group": "WM_SHOW_TRANSACTIONS",
-      "at": "com\/android\/server\/wm\/WindowAnimator.java"
-    },
-    "1984843251": {
-      "message": "Hiding wallpaper %s from %s target=%s prev=%s callers=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_WALLPAPER",
-      "at": "com\/android\/server\/wm\/WallpaperController.java"
-    },
-    "1995093920": {
-      "message": "Checking to restart %s: changed=0x%s, handles=0x%s, mLastReportedConfiguration=%s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_CONFIGURATION",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "1999594750": {
-      "message": "startAnimation",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/NonAppWindowAnimationAdapter.java"
-    },
-    "2001473656": {
-      "message": "App %s is focused, but the window is not ready. Start a transaction to remove focus from the window of non-focused apps.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_FOCUS_LIGHT",
-      "at": "com\/android\/server\/wm\/InputMonitor.java"
-    },
-    "2004282287": {
-      "message": "Override sync-method for %s because seamless rotating",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
-    },
-    "2010476671": {
-      "message": "Animation done in %s: reportedVisible=%b okToDisplay=%b okToAnimate=%b startingDisplayed=%b",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/ActivityRecord.java"
-    },
-    "2018454757": {
-      "message": "WS.removeImmediately: %s Already removed...",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/WindowState.java"
-    },
-    "2018852077": {
+    "7269690012594027154": {
       "message": "Creating SplashScreenStartingData",
       "level": "VERBOSE",
       "group": "WM_DEBUG_STARTING_WINDOW",
       "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "2019765997": {
-      "message": "selectRotationAnimation topFullscreen=%s rotationAnimation=%d forceJumpcut=%b",
-      "level": "INFO",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    "-3432060893368468911": {
+      "message": "Creating SnapshotStartingData",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "2021079047": {
-      "message": "%s",
+    "1789854065584848502": {
+      "message": "startingData was nulled out before handling mAddStartingWindow: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "5659016061937922595": {
+      "message": "Add starting %s: startingData=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-9066702108316454290": {
+      "message": "Aborted starting %s: startingData=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "7506106334102501360": {
+      "message": "Added starting %s: startingWindow=%s startingView=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "1048048288756547220": {
+      "message": "Surface returned was null: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-1298801500610545721": {
+      "message": "Cleaning splash screen token=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-1948849214526113495": {
+      "message": "Clearing startingData for token=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "5545923784327902026": {
+      "message": "Schedule remove starting %s startingWindow=%s animate=%b Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-5150982660941074218": {
+      "message": "startingWindow was set but startingSurface==null, couldn't remove",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-2178757341169633804": {
+      "message": "Tried to remove starting window but startingWindow was null: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "5521236266092347335": {
+      "message": "reparent: moving activity=%s to new task fragment in task=%d at %d",
+      "level": "INFO",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-9024836052864189016": {
+      "message": "moveFocusableActivityToTop: unfocusable activity=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "134255351804410010": {
+      "message": "moveFocusableActivityToTop: already on top and focused, activity=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-1058622321669556178": {
+      "message": "moveFocusableActivityToTop: set focused, activity=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "731006689098152100": {
+      "message": "moveFocusableActivityToTop: activity=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "3707721620395081349": {
+      "message": "Finishing activity r=%s, result=%d, data=%s, reason=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-3691592300155948194": {
+      "message": "Finish needs to pause: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "5813636479397543744": {
+      "message": "Finish waiting for pause of: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-2989211291975863399": {
+      "message": "destroyIfPossible: r=%s destroy returned removed=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_CONTAINERS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "3169053633576517098": {
+      "message": "Enqueueing pending finish: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "9050478058743283018": {
+      "message": "activity %s already destroying, skipping request with reason:%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "5672598223877126839": {
+      "message": "Moving to DESTROYING: %s (destroy requested)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-1834399855266808961": {
+      "message": "Moving to DESTROYED: %s (destroy skipped)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "3282063745558462269": {
+      "message": "Moving to DESTROYED: %s (no app)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "8836546031252812807": {
+      "message": "Removing activity %s, reason= %s callers=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "8348126473928520781": {
+      "message": "Moving to DESTROYED: %s (removed from history)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-8001673213497887656": {
+      "message": "activityDestroyedLocked: r=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_CONTAINERS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "587363723665813898": {
+      "message": "Removing activity %s hasSavedState=%b stateNotNeeded=%s finishing=%b state=%s callers=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-1842512343787359105": {
+      "message": "Removing app token: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "5548174277852675449": {
+      "message": "Removing app %s delayed=%b animation=%s animating=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-601582700132879947": {
+      "message": "removeAppToken: %s delayed=%b Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "3478214322581157355": {
+      "message": "removeAppToken make exiting: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-7226216420432530281": {
+      "message": "Removing focused app token:%s displayId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "8361394136152947990": {
+      "message": "Moving existing starting %s from %s to %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-3450064502566932331": {
+      "message": "Removing starting %s from %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "8639603536400037285": {
+      "message": "Moving pending starting from %s to %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-3452055378690362514": {
+      "message": "setAppVisibility(%s, visible=%b): %s visible=%b mVisibleRequested=%b Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "1728033820691545386": {
+      "message": "No longer Stopped: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "5062176994575790703": {
+      "message": "TRANSIT_FLAG_OPEN_BEHIND,  adding %s to mOpeningApps",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-477271988506706928": {
+      "message": "commitVisibility: %s: visible=%b visibleRequested=%b, isInTransition=%b, runningAnimation=%b, caller=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-6873410057142191118": {
+      "message": "State movement: %s from:%s to:%s reason:%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "4437231720834282527": {
+      "message": "State unchanged from:%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "926038819327785799": {
+      "message": "notifyAppResumed: wasStopped=%b %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "1734586111478674085": {
+      "message": "Resumed activity; dropping state of: %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-69666241054231397": {
+      "message": "Refreshed activity: %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "1256300416726217367": {
+      "message": "Activity paused: token=%s, timeout=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "6879640870754727133": {
+      "message": "Moving to PAUSED: %s %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "2737811012914917932": {
+      "message": "Executing finish of failed to pause activity: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-2566496855129705006": {
+      "message": "Waiting for pause to complete...",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "7498807658620137882": {
+      "message": "no-history finish of %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "3207149655622038378": {
+      "message": "Not finishing noHistory %s on stop because we're just sleeping",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-2530718588485487045": {
+      "message": "Moving to STOPPING: %s (stop requested)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-8424334454318351870": {
+      "message": "Stop failed; moving to STOPPED: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-4913512058893421188": {
+      "message": "Saving icicle of %s: %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "7613353074402340933": {
+      "message": "Moving to STOPPED: %s (stop complete)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "3981777934616509782": {
+      "message": "Scheduling idle now: forceIdle=%b immediate=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "1083992181663415298": {
+      "message": "Skipping set freeze of %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "3713860954819212080": {
+      "message": "Set freezing of %s: visible=%b freezing=%b visibleRequested=%b. %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "7696002120820208745": {
+      "message": "Clear freezing of %s force=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-8387262166329116492": {
+      "message": "No longer freezing: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-6965298896142649709": {
+      "message": "Finish starting %s: first real window is shown, no animation",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "3235691043029201724": {
+      "message": "Setting mOrientationChangeComplete=true because wtoken %s numInteresting=%d numDrawn=%d",
+      "level": "INFO",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "5991628884266137609": {
+      "message": "Creating animation bounds layer",
+      "level": "INFO",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-1836789237982086339": {
+      "message": "No thumbnail header bitmap for: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-8809523216004991008": {
+      "message": "Animation done in %s: reportedVisible=%b okToDisplay=%b okToAnimate=%b startingDisplayed=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-9178011226407552682": {
+      "message": "Setting requested orientation %s for %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-1963190756391505590": {
+      "message": "Sandbox max bounds for uid %s to bounds %s. config to never sandbox = %s, config to always sandbox = %s, letterboxing from mismatch with parent bounds = %s, has mCompatDisplayInsets = %s, should create compatDisplayInsets = %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "2612201759169917322": {
+      "message": "Pausing configuration dispatch for  %s",
       "level": "VERBOSE",
       "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
-      "at": "com\/android\/server\/wm\/TransitionController.java"
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "2022422429": {
-      "message": "createAnimationAdapter(): container=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
-    },
-    "2024493888": {
-      "message": "\tWallpaper of display=%s is not visible",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
-      "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java"
-    },
-    "2028163120": {
-      "message": "applyAnimation: anim=%s nextAppTransition=ANIM_SCALE_UP transit=%s isEntrance=%s Callers=%s",
+    "5153784493059555057": {
+      "message": "Resuming configuration dispatch for %s",
       "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/AppTransition.java"
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "2034780299": {
-      "message": "CHECK_IF_BOOT_ANIMATION_FINISHED:",
+    "-8630021188868292872": {
+      "message": "Skipping config check (will change): %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-3976984054291875926": {
+      "message": "Configuration doesn't matter in finishing %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-1036762753077003128": {
+      "message": "Skipping config check in destroyed state %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-6543078196636665108": {
+      "message": "Skipping config check invisible: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-3588725633248053181": {
+      "message": "Ensuring correct configuration: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "4672360193194734037": {
+      "message": "Configuration & display unchanged in %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-8624278141553396410": {
+      "message": "Skipping config check for initializing activity: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "2485365009287691179": {
+      "message": "Configuration no differences in %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-8909639363543223474": {
+      "message": "Configuration changes for %s, allChanges=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "-8048404379899908050": {
+      "message": "Configuration doesn't matter not running %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "4979286847769557939": {
+      "message": "Checking to restart %s: changed=0x%s, handles=0x%s, mLastReportedConfiguration=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "6779426581354721909": {
+      "message": "Config is relaunching %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "8969401915706456725": {
+      "message": "Config is relaunching invisible activity %s called by %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "328802837600679598": {
+      "message": "Moving to %s Relaunching %s callers=%s",
       "level": "INFO",
-      "group": "WM_DEBUG_BOOT",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
     },
-    "2039056415": {
-      "message": "Found matching affinity candidate!",
+    "-3997125892953197985": {
+      "message": "Resumed after relaunch %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityRecord.java"
+    },
+    "1665699123574159131": {
+      "message": "Starting activity when config will change = %b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityStarter.java"
+    },
+    "4748139468532105082": {
+      "message": "Updating to new configuration after starting activity.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityStarter.java"
+    },
+    "-2867366986304729": {
+      "message": "Bring to front target: %s from %s",
       "level": "DEBUG",
       "group": "WM_DEBUG_TASKS",
-      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+      "at": "com\/android\/server\/wm\/ActivityStarter.java"
     },
-    "2043434284": {
-      "message": "setWallpaperShowWhenLocked: non-existent wallpaper token: %s",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "2045641491": {
-      "message": "Checking %d opening apps (frozen=%b timeout=%b)...",
+    "-2190454940975874759": {
+      "message": "Starting new activity %s in new task %s",
       "level": "VERBOSE",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityStarter.java"
     },
-    "2053743391": {
-      "message": " Add condition %s for #%d",
+    "5445799252721678675": {
+      "message": "Initial config: %s",
       "level": "VERBOSE",
-      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/Transition.java"
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
     },
-    "2060978050": {
-      "message": "moveWindowTokenToDisplay: Attempted to move token: %s to non-exiting displayId=%d",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "2066210760": {
-      "message": "foldStateChanged: displayId %d, halfFoldStateChanged %s, saved rotation: %d, mUserRotation: %d, mLastSensorRotation: %d, mLastOrientation: %d, mRotation: %d",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
-    },
-    "2070726247": {
-      "message": "InsetsSource updateVisibility for %s, serverVisible: %s clientVisible: %s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_WINDOW_INSETS",
-      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
-    },
-    "2075693141": {
-      "message": "Set animatingExit: reason=startExitingAnimation\/%s win=%s",
-      "level": "DEBUG",
-      "group": "WM_DEBUG_ANIM",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "2079410261": {
-      "message": "applyAnimation:  override requested, but it is prohibited by policy.",
+    "-3811526397232923712": {
+      "message": "Cannot launch dream activity due to invalid state. dream component: %s packageName: %s",
       "level": "ERROR",
-      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
-      "at": "com\/android\/server\/wm\/AppTransition.java"
+      "group": "WM_DEBUG_DREAM",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
     },
-    "2083556954": {
-      "message": "Set mOrientationChanging of %s",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    "-6981899770129924827": {
+      "message": "Dream packageName does not match active dream. Package %s does not match %s",
+      "level": "ERROR",
+      "group": "WM_DEBUG_DREAM",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
     },
-    "2086878461": {
-      "message": "Could not send command %s with parameters %s. %s",
-      "level": "WARN",
-      "group": "WM_ERROR",
-      "at": "com\/android\/server\/wm\/WindowManagerService.java"
-    },
-    "2100457473": {
-      "message": "Task=%d contains embedded TaskFragment. Disabled all input during TaskFragment remote animation.",
+    "6075150529915862250": {
+      "message": "Applying new update lock state '%s' for %s",
       "level": "DEBUG",
-      "group": "WM_DEBUG_APP_TRANSITIONS",
-      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+      "group": "WM_DEBUG_IMMERSIVE",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
     },
-    "2117696413": {
+    "-4356952232698761083": {
+      "message": "setFocusedRootTask: taskId=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "301842347780487555": {
+      "message": "setFocusedTask: taskId=%d touchedActivity=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "7095858131234795548": {
       "message": "moveTaskToFront: moving taskId=%d",
       "level": "DEBUG",
       "group": "WM_DEBUG_TASKS",
       "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
     },
-    "2119122320": {
+    "-4458288191054594222": {
+      "message": "Could not find task for id: %d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "-1136891560663761442": {
+      "message": "moveTaskToRootTask: moving task=%d to rootTaskId=%d toTop=%b",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "6954122272402912822": {
+      "message": "startLockTaskMode: %s",
+      "level": "WARN",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "-829638795650515884": {
+      "message": "Allowlisting %d:%s",
+      "level": "WARN",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "893763316922465955": {
+      "message": "moveRootTaskToDisplay: moving taskId=%d to displayId=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "8392804603924461448": {
+      "message": "%s: caller %d is using old GET_TASKS but privileged; allowing",
+      "level": "WARN",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "4303745325174700522": {
+      "message": "%s: caller %d does not hold REAL_GET_TASKS; limiting output",
+      "level": "WARN",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "-559595900417262876": {
+      "message": "Allowing features %d:0x%s",
+      "level": "WARN",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "2008996027621913637": {
+      "message": "Updating global configuration to: %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "-6404059840638143757": {
+      "message": "Update process config of %s to new config %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "2959074735946674755": {
+      "message": "Trying to update display configuration for system\/invalid process.",
+      "level": "WARN",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "5668810920995272206": {
+      "message": "Trying to update display configuration for invalid process, pid=%d",
+      "level": "WARN",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "-1123414663662718691": {
+      "message": "setVr2dDisplayId called for: %d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskManagerService.java"
+    },
+    "7803197981786977817": {
+      "message": "no-history finish of %s on new resume",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
+    },
+    "4094852138446437211": {
+      "message": "realStartActivityLocked: Skipping start of r=%s some activities pausing...",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
+    },
+    "1045761390992110034": {
+      "message": "Moving to PAUSED: %s (starting in paused state)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
+    },
+    "-8529426827020190143": {
+      "message": "Launch on display check: displayId=%d callingPid=%d callingUid=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
+    },
+    "9147909968067116569": {
+      "message": "Launch on display check: no caller info, skip check",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
+    },
+    "4781135167649953680": {
+      "message": "Launch on display check: allow launch any on display",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
+    },
+    "7828411869729995271": {
+      "message": "Launch on display check: disallow launch on virtual display for not-embedded activity.",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
+    },
+    "-2215878620906309682": {
+      "message": "Launch on display check: disallow activity embedding without permission.",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
+    },
+    "986565579776405555": {
+      "message": "Launch on display check: %s launch for userId=%d on displayId=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
+    },
+    "-2201418325681949201": {
+      "message": "Launch on display check: allow launch for owner of the display",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
+    },
+    "-4258279435559028377": {
+      "message": "Launch on display check: allow launch for caller present on the display",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
+    },
+    "1496536241884839051": {
+      "message": "Stopping %s: nowVisible=%b animating=%b finishing=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
+    },
+    "5677125188685281770": {
+      "message": "Ready to stop: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
+    },
+    "3604633008357193496": {
+      "message": "Waiting for top state to be released by %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
+    },
+    "3997062844427155487": {
+      "message": "Top resumed state released %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
+    },
+    "-4049608245387511746": {
+      "message": "applyAnimation:  override requested, but it is prohibited by policy.",
+      "level": "ERROR",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "-2133100418670643322": {
+      "message": "applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "6121116119545820299": {
+      "message": "applyAnimation: anim=%s transit=%s Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "-8382864384468306610": {
+      "message": "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM transit=%s isEntrance=%b Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "222576013987954454": {
+      "message": "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM_IN_PLACE transit=%s Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "4808089291562562413": {
+      "message": "applyAnimation: anim=%s nextAppTransition=ANIM_CLIP_REVEAL transit=%s Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "-1463563572526433695": {
+      "message": "applyAnimation: anim=%s nextAppTransition=ANIM_SCALE_UP transit=%s isEntrance=%s Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "-8749850292010208926": {
+      "message": "applyAnimation: anim=%s nextAppTransition=%s transit=%s isEntrance=%b Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "5939232373291430513": {
+      "message": "applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS: anim=%s transit=%s isEntrance=true Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "9082776604722675018": {
+      "message": "applyAnimation: anim=%s transit=%s isEntrance=%b Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "-1218632020771063497": {
+      "message": "applyAnimation: anim=%s animAttr=0x%x transit=%s isEntrance=%b  canCustomizeAppTransition=%b Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "6217525691846442213": {
+      "message": "Override pending remote transitionSet=%b adapter=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "5233255302148535928": {
+      "message": "*** APP TRANSITION TIMEOUT. displayId=%d isTransitionSet()=%b mOpeningApps.size()=%d mClosingApps.size()=%d mChangingApps.size()=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransition.java"
+    },
+    "-5726018006883159788": {
+      "message": "Delaying app transition for recents animation to finish",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "6514556033257323299": {
+      "message": "**** GOOD TO GO",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "3518082157667760495": {
+      "message": "handleAppTransitionReady: displayId=%d appTransition={%s} openingApps=[%s] closingApps=[%s] transit=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "-2503124388387340567": {
+      "message": "Wallpaper animation!",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "855146509305002043": {
+      "message": "We don't support remote animation for Task with multiple TaskFragmentOrganizers.",
+      "level": "ERROR",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "59396412370137517": {
+      "message": "Override with TaskFragment remote animation for transit=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "2280055488397326910": {
+      "message": "Task=%d contains embedded TaskFragment. Disabled all input during TaskFragment remote animation.",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "-3156084190956669377": {
+      "message": "Changing app %s visible=%b performLayout=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "-8226278785414579647": {
+      "message": "getAnimationTarget in=%s, out=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "4418653408751596915": {
+      "message": "Now opening app %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "-8367738619313176909": {
+      "message": "Now closing app %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "1855459282905873641": {
+      "message": "Now changing app %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "2951634988136738868": {
+      "message": "Checking %d opening apps (frozen=%b timeout=%b)...",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "4963754906024950916": {
+      "message": "Delaying app transition for screen rotation animation to finish",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "5073676463280304697": {
+      "message": "Check opening app=%s: allDrawn=%b startingDisplayed=%b startingMoved=%b isRelaunching()=%b startingWindow=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "3437142041296647115": {
+      "message": "isFetchingAppTransitionSpecs=true",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "1461079689316480707": {
+      "message": "unknownApps is not empty: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "3579533288018884842": {
+      "message": "Organized TaskFragment is not ready= %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/AppTransitionController.java"
+    },
+    "495867940519492701": {
+      "message": "SyncGroup %d: onSurfacePlacement checking %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+    },
+    "8452501904614439940": {
+      "message": "SyncGroup %d:  Unfinished dependencies: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+    },
+    "616739530932040800": {
+      "message": "SyncGroup %d:  Unfinished container: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+    },
+    "6649777898123506907": {
+      "message": "SyncGroup %d: Finished!",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+    },
+    "4174320302463990554": {
+      "message": "PendingStartTransaction found",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+    },
+    "6310906192788668020": {
+      "message": "SyncGroup %d: Set ready %b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+    },
+    "-476337038362199951": {
+      "message": "SyncGroup %d: Adding to group: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+    },
+    "-2978812352001196863": {
+      "message": "SyncGroup %d: Started %sfor listener: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
+    },
+    "-699215053676660941": {
+      "message": "No focused window, defaulting to top current task's window",
+      "level": "WARN",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
+    "-1459414342866553129": {
+      "message": "Current focused window being animated by recents. Overriding back callback to recents controller callback.",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
+    "2881085074175114605": {
+      "message": "Focused window didn't have a valid surface drawn.",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
+    "-6183551796617134986": {
+      "message": "Focus window is closing.",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
+    "4039315468791789889": {
+      "message": "startBackNavigation currentTask=%s, topRunningActivity=%s, callbackInfo=%s, currentFocus=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
+    "8456834061534378653": {
+      "message": "Previous Destination is Activity:%s Task:%s removedContainer:%s, backType=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
+    "4900967164780429209": {
+      "message": "Pending back animation due to another animation is running",
+      "level": "WARN",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
+    "-6431452312492819825": {
+      "message": "onTransactionReady, opening: %s, closing: %s, animating: %s, match: %b",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
+    "-4051770154814262074": {
+      "message": "Handling the deferred animation after transition finished",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
+    "2077221835543623088": {
+      "message": "Setting Activity.mLauncherTaskBehind to true. Activity=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
+    "-4442170697458371588": {
+      "message": "Setting Activity.mLauncherTaskBehind to false. Activity=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
+    "267946503010201613": {
+      "message": "onBackNavigationDone backType=%s, triggerBack=%b",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
+    "-2963535976860666511": {
+      "message": "  BLACK %s: CREATE layer=%d",
+      "level": "INFO",
+      "group": "WM_SHOW_SURFACE_ALLOC",
+      "at": "com\/android\/server\/wm\/BlackFrame.java"
+    },
+    "-5633771912572750947": {
+      "message": "  BLACK %s: DESTROY",
+      "level": "INFO",
+      "group": "WM_SHOW_SURFACE_ALLOC",
+      "at": "com\/android\/server\/wm\/BlackFrame.java"
+    },
+    "-74949168947384056": {
+      "message": "Sending to proc %s new compat %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/CompatModePackages.java"
+    },
+    "-6620483833570774987": {
+      "message": "Content Recording: Unexpectedly null window container; unable to update recording for display %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "7226080178642957768": {
+      "message": "Content Recording: Display %d was already recording, but pause capture since the task is in PIP",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "-311001578548807570": {
+      "message": "Content Recording: Display %d was already recording, so apply transformations if necessary",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "2350883351096538149": {
+      "message": "Content Recording: Going ahead with updating recording for display %d to new bounds %s and\/or orientation %d and\/or surface size %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "8446758574558556540": {
+      "message": "Content Recording: Unable to update recording for display %d to new bounds %s and\/or orientation %d and\/or surface size %s, since the surface is not available.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "-4320004054011530388": {
+      "message": "Content Recording: Display %d has content (%b) so pause recording",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "5951434375221687741": {
+      "message": "Content Recording: Stop MediaProjection on virtual display %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "-3395581813971405090": {
+      "message": "Content Recording: waiting to record, so do nothing",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "6779858226066635065": {
+      "message": "Content Recording: Display %d should start recording, but don't yet since the task is in PIP",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "7051210836345306671": {
+      "message": "Content Recording: Unable to start recording for display %d since the surface is not available.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "2255758299558330282": {
+      "message": "Content Recording: Display %d has no content and is on, so start recording for state %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "2269158922723670768": {
+      "message": "Unable to retrieve window container to start recording for display %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "-2177493963028285555": {
+      "message": "Content Recording: Unable to start recording due to null token for display %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "-928577038848872043": {
+      "message": "Content Recording: Unable to retrieve task to start recording for display %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "-3564317873468917405": {
+      "message": "Content Recording: Unable to start recording due to invalid region for display %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "1100676037289065396": {
+      "message": "Content Recording: Apply transformations of shift %d x %d, scale %f x %f, crop (aka recorded content size) %d x %d for display %d; display has size %d x %d; surface has size %d x %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "2330946591287751995": {
+      "message": "Content Recording: Provided surface for recording on display %d is not present, so do not update the surface",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "7993045936648632984": {
+      "message": "Content Recording: Recorded task is removed, so stop recording on display %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "3197882223327917085": {
+      "message": "Content Recording: stopping active projection for display %d",
+      "level": "ERROR",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "4391984931064789228": {
+      "message": "Content Recording: Unable to tell MediaProjectionManagerService to stop the active projection for display %d: %s",
+      "level": "ERROR",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "6721270269112237694": {
+      "message": "Content Recording: Unable to tell MediaProjectionManagerService about resizing the active projection: %s",
+      "level": "ERROR",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "1600318776990120244": {
+      "message": "Content Recording: Unable to tell MediaProjectionManagerService about visibility change on the active projection: %s",
+      "level": "ERROR",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "-1451477179301743956": {
+      "message": "Content Recording: Unable to tell log windowing mode change: %s",
+      "level": "ERROR",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecorder.java"
+    },
+    "-225319884529912382": {
+      "message": "Content Recording: Accept session updating same display %d with granted consent, with an existing session %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecordingController.java"
+    },
+    "-5981322449150461244": {
+      "message": "Content Recording: Ignoring session on same display %d, with an existing session %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecordingController.java"
+    },
+    "4226710957373144819": {
+      "message": "Content Recording: Handle incoming session on display %d, with a pre-existing session %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecordingController.java"
+    },
+    "-1415855962859555663": {
+      "message": "Content Recording: Incoming session on display %d can't be set since it is already null; the corresponding VirtualDisplay must have already been removed.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecordingController.java"
+    },
+    "-5750232782380780139": {
+      "message": "Content Recording: Pause the recording session on display %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/ContentRecordingController.java"
+    },
+    "-8058211784911995417": {
+      "message": "DeferredDisplayUpdater: applying DisplayInfo immediately",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/DeferredDisplayUpdater.java"
+    },
+    "1944392458089872195": {
+      "message": "DeferredDisplayUpdater: partially applying DisplayInfo immediately",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/DeferredDisplayUpdater.java"
+    },
+    "8391643185322408089": {
+      "message": "DeferredDisplayUpdater: deferring DisplayInfo update",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/DeferredDisplayUpdater.java"
+    },
+    "-915675022936690176": {
+      "message": "DeferredDisplayUpdater: applied DisplayInfo after deferring",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/DeferredDisplayUpdater.java"
+    },
+    "3778139410556664218": {
+      "message": "%s skipping animation and directly setting alpha=%f, blur=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_DIMMER",
+      "at": "com\/android\/server\/wm\/DimmerAnimationHelper.java"
+    },
+    "-6357087772993832060": {
+      "message": "Starting animation on %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_DIMMER",
+      "at": "com\/android\/server\/wm\/DimmerAnimationHelper.java"
+    },
+    "-1187783168730646350": {
+      "message": "Dim animation requested: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_DIMMER",
+      "at": "com\/android\/server\/wm\/DimmerAnimationHelper.java"
+    },
+    "2230151187668089583": {
+      "message": "%s forcing orientation to %d for display id=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayArea.java"
+    },
+    "3968604152682328317": {
+      "message": "Register display organizer=%s uid=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
+    },
+    "-3066370283926570943": {
+      "message": "Don't organize or trigger events for untrusted displayId=%d",
+      "level": "WARN",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
+    },
+    "-943497726140336963": {
+      "message": "Unregister display organizer=%s uid=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
+    },
+    "5147103403966149923": {
+      "message": "Create TaskDisplayArea uid=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
+    },
+    "-1659480097203667175": {
+      "message": "Delete TaskDisplayArea uid=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
+    },
+    "-4514772405648277945": {
+      "message": "DisplayArea appeared name=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
+    },
+    "995846188225477231": {
+      "message": "DisplayArea vanished name=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
+    },
+    "-1007032390526684388": {
+      "message": "DisplayArea info changed name=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
+    },
+    "4917824058925068521": {
+      "message": "The TaskDisplayArea with %s does not exist.",
+      "level": "WARN",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/DisplayAreaPolicyBuilder.java"
+    },
+    "1432179297701477868": {
+      "message": "Looking for focus: %s, flags=%d, canReceive=%b, reason=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-1998969924927409574": {
+      "message": "findFocusedWindow: focusedApp=null using new focus @ %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-1513212297283619351": {
+      "message": "findFocusedWindow: focusedApp windows not focusable using new focus @ %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "271075236829935631": {
+      "message": "findFocusedWindow: Reached focused app=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "3066566560703920191": {
+      "message": "findFocusedWindow: Found new focus @ %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-8667452489821572603": {
+      "message": "First draw done in potential wallpaper target %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WALLPAPER",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "6283995720623600346": {
+      "message": "handleNotObscuredLocked: %s was holding screen wakelock but no longer has FLAG_KEEP_SCREEN_ON!!! called by%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_KEEP_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "1959209522588955826": {
+      "message": "Acquiring screen wakelock due to %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_KEEP_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "352937214222086717": {
+      "message": "Releasing screen wakelock, obscured by %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_KEEP_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "2632363530212357762": {
+      "message": "Set mOrientationChanging of %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-9191821315942566105": {
+      "message": "Display id=%d is frozen while keyguard locked, return %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-74384795669614579": {
+      "message": "Display id=%d is ignoring orientation request for %d, return %d following a per-app override for %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-3395592185328682328": {
+      "message": "Display id=%d is ignoring orientation request for %d, return %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "3438870491084701232": {
+      "message": "No app or window is requesting an orientation, return %d for display id=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-1123818872155982592": {
+      "message": "findFocusedWindow: No focusable windows, display=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-2192125645150932161": {
+      "message": "Current transition prevents automatic focus change",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "3101160328044493048": {
+      "message": "Changing focus from %s to %s displayId=%d Callers=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "7634130879993688940": {
+      "message": "setFocusedApp %s displayId=%d Callers=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-4130402450005935184": {
+      "message": "SURFACE LEAK DESTROY: %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "4464269036743635127": {
       "message": "setInputMethodTarget %s",
       "level": "INFO",
       "group": "WM_DEBUG_IME",
       "at": "com\/android\/server\/wm\/DisplayContent.java"
     },
-    "2124732293": {
+    "4835192778854186097": {
+      "message": "create IME snapshot for %s, buff width=%s, height=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "2408509162360028352": {
+      "message": "Set IME snapshot position: (%d, %d)",
+      "level": "INFO",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "2005731931732324688": {
+      "message": "remove IME snapshot, caller=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-6495118720675662641": {
+      "message": "show IME snapshot, ime target=%s, callers=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-4354595179162289537": {
+      "message": "setInputMethodInputTarget %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "2432701541536053712": {
+      "message": "DisplayContent: boot is waiting for window of type %d to be drawn",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "5683557566110711213": {
+      "message": "******** booted=%b msg=%b haveBoot=%b haveApp=%b haveWall=%b wallEnabled=%b haveKeyguard=%b",
+      "level": "INFO",
+      "group": "WM_DEBUG_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-124113386733162358": {
+      "message": "onWindowAnimationFinished, wc=%s, type=%s, imeSnapshot=%s, target=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-1556099709547629010": {
+      "message": "ImeContainer just became organized. Reparenting under parent. imeParentSurfaceControl=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "1119786654111970652": {
+      "message": "ImeContainer just became organized but it doesn't have a parent or the parent doesn't have a surface control. mSurfaceControl=%s imeParentSurfaceControl=%s",
+      "level": "ERROR",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "7019634211809476510": {
+      "message": "Execute app transition: %s, displayId: %d Callers=%s",
+      "level": "WARN",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-3219913508985161450": {
+      "message": "Wallpaper layer changed: assigning layers + relayout",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WALLPAPER",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-8165317816061445169": {
+      "message": "Content Recording: Display %d state was (%d), is now (%d), so update recording?",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "4162342172327950908": {
+      "message": "Content Recording: Attempting to mirror self on %d",
+      "level": "WARN",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "5489691866309868814": {
+      "message": "Content Recording: Found no matching mirror display for id=%d for DEFAULT_DISPLAY. Nothing to mirror.",
+      "level": "WARN",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-39794010824230928": {
+      "message": "Content Recording: Attempting to mirror %d from %d but no DisplayContent associated. Changing to mirror default display.",
+      "level": "WARN",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "6545352723229848841": {
+      "message": "Content Recording: Successfully created a ContentRecordingSession for displayId=%d to mirror content from displayId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONTENT_RECORDING",
+      "at": "com\/android\/server\/wm\/DisplayContent.java"
+    },
+    "-6228339285356824882": {
+      "message": "finishScreenTurningOn: mAwake=%b, mScreenOnEarly=%b, mScreenOnFully=%b, mKeyguardDrawComplete=%b, mWindowManagerDrawComplete=%b",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/DisplayPolicy.java"
+    },
+    "-6028033043540330282": {
+      "message": "Finished screen turning on...",
+      "level": "INFO",
+      "group": "WM_DEBUG_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/DisplayPolicy.java"
+    },
+    "-7427596081878257508": {
+      "message": "selectAnimation in %s: transit=%d",
+      "level": "INFO",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/DisplayPolicy.java"
+    },
+    "-6269658847003264525": {
+      "message": "**** STARTING EXIT",
+      "level": "INFO",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/DisplayPolicy.java"
+    },
+    "-6776561147903919733": {
+      "message": "Deferring rotation, rotation is paused.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "7439675997626642740": {
+      "message": "Deferring rotation, animation in progress.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "1104181226551849840": {
+      "message": "Deferring rotation, still finishing previous rotation",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "-2222079183499215612": {
+      "message": "Deferring rotation, display is not enabled.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "662988298513100908": {
+      "message": "Reverting orientation. Rotating to %s from %s rather than %s.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "-7113483678655694375": {
+      "message": "Computed rotation=%s (%d) for display id=%d based on lastOrientation=%s (%d) and oldRotation=%s (%d)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "-8809129029906317617": {
+      "message": "Display id=%d selected orientation %s (%d), got rotation %s (%d)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "6753221849083491323": {
+      "message": "Display id=%d rotation changed to %d from %d, lastOrientation=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "-1216224951455892544": {
+      "message": "Performing post-rotate rotation after seamless rotation",
+      "level": "INFO",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "-7672508047849737424": {
+      "message": "selectRotationAnimation topFullscreen=%s rotationAnimation=%d forceJumpcut=%b",
+      "level": "INFO",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "-2426404033822048710": {
+      "message": "screenOnEarly=%b, awake=%b, currentAppOrientation=%d, orientationSensorEnabled=%b, keyguardDrawComplete=%b, windowManagerDrawComplete=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "7339471241580327852": {
+      "message": "rotationForOrientation(orient=%s (%d), last=%s (%d)); user=%s (%d) %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "5325136615007859122": {
+      "message": "Invalid surface rotation angle in config_deviceTabletopRotations: %d",
+      "level": "ERROR",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "4616480353797749295": {
+      "message": "config_deviceTabletopRotations is not defined. Half-fold letterboxing will work inconsistently.",
+      "level": "WARN",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "8852346340572084230": {
+      "message": "foldStateChanged: displayId %d, halfFoldStateChanged %s, saved rotation: %d, mUserRotation: %d, mLastSensorRotation: %d, mLastOrientation: %d, mRotation: %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "-8674269704471038429": {
+      "message": "onProposedRotationChanged, rotation=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "418312772547457152": {
+      "message": "Enabling listeners",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "4641814558273780952": {
+      "message": "Disabling listeners",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+    },
+    "7429138692709430028": {
+      "message": "Display id=%d is ignoring all orientation requests, camera is active and the top activity is eligible for force rotation, return %s,portrait activity: %b, is natural orientation portrait: %b.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
+    },
+    "-7756685416834187936": {
+      "message": "Refreshing activity for camera compatibility treatment, activityRecord=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
+    },
+    "-5176775281239247368": {
+      "message": "Reverting orientation after camera compat force rotation",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
+    },
+    "-2188976047008497712": {
+      "message": "Saving original orientation before camera compat, last orientation is %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
+    },
+    "-8302211458579221117": {
+      "message": "Display id=%d is notified that Camera %s is open for package %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
+    },
+    "-1534784331886673955": {
+      "message": "DisplayRotationCompatPolicy: Multi-window toast not shown as package '%s' cannot be found.",
+      "level": "ERROR",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
+    },
+    "1797195804376906831": {
+      "message": "Display id=%d is notified that Camera %s is closed, scheduling rotation update.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
+    },
+    "-8746776274432739264": {
+      "message": "Display id=%d is notified that Camera %s is closed but activity is still refreshing. Rescheduling an update.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
+    },
+    "3622181214422515679": {
+      "message": "Display id=%d is notified that Camera %s is closed, updating rotation.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotationCompatPolicy.java"
+    },
+    "-6949326633913532620": {
+      "message": "NOSENSOR override detected",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotationReversionController.java"
+    },
+    "-2060428960792625366": {
+      "message": "NOSENSOR override is absent: reverting",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotationReversionController.java"
+    },
+    "-4296736202875980050": {
+      "message": "Other orientation overrides are in place: not reverting",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DisplayRotationReversionController.java"
+    },
+    "7928129513685401229": {
+      "message": "Pausing rotation during drag",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DragState.java"
+    },
+    "8231481023986546563": {
+      "message": "Resuming rotation after drag",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/DragState.java"
+    },
+    "12662399232325663": {
+      "message": "DRAG %s: pos=(%d,%d)",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/DragState.java"
+    },
+    "-1797662102094201628": {
+      "message": "Attempt to transfer touch gesture with non-existent embedded window",
+      "level": "WARN",
+      "group": "WM_DEBUG_EMBEDDED_WINDOWS",
+      "at": "com\/android\/server\/wm\/EmbeddedWindowController.java"
+    },
+    "929964979835124721": {
+      "message": "Attempt to transfer touch gesture using embedded window with no associated host",
+      "level": "WARN",
+      "group": "WM_DEBUG_EMBEDDED_WINDOWS",
+      "at": "com\/android\/server\/wm\/EmbeddedWindowController.java"
+    },
+    "676191989331669410": {
+      "message": "Attempt to transfer touch gesture with host window not associated with embedded window",
+      "level": "WARN",
+      "group": "WM_DEBUG_EMBEDDED_WINDOWS",
+      "at": "com\/android\/server\/wm\/EmbeddedWindowController.java"
+    },
+    "553249487221306249": {
+      "message": "Attempt to transfer touch gesture using embedded window that has no input channel",
+      "level": "WARN",
+      "group": "WM_DEBUG_EMBEDDED_WINDOWS",
+      "at": "com\/android\/server\/wm\/EmbeddedWindowController.java"
+    },
+    "-8678904073078032058": {
+      "message": "Attempt to transfer touch gesture using a host window with no input channel",
+      "level": "WARN",
+      "group": "WM_DEBUG_EMBEDDED_WINDOWS",
+      "at": "com\/android\/server\/wm\/EmbeddedWindowController.java"
+    },
+    "-786355099910065121": {
+      "message": "IME target changed within ActivityRecord",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
+    },
+    "2634707843050913730": {
+      "message": "Schedule IME show for %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
+    },
+    "8923821958256605927": {
+      "message": "Run showImeRunner",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
+    },
+    "-3529253275087521638": {
+      "message": "call showInsets(ime) on %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
+    },
+    "7927729210300708186": {
+      "message": "showInsets(ime) was requested by different window: %s ",
+      "level": "WARN",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
+    },
+    "-6529782994356455131": {
+      "message": "abortShowImePostLayout",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
+    },
+    "-6629998049460863403": {
+      "message": "dcTarget: %s mImeRequester: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
+    },
+    "-8553129529717081823": {
+      "message": "Input focus has changed to %s display=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/InputMonitor.java"
+    },
+    "4027486077547983902": {
+      "message": "App %s is focused, but the window is not ready. Start a transaction to remove focus from the window of non-focused apps.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/InputMonitor.java"
+    },
+    "-8537908614386667236": {
+      "message": "Focus not requested for window=%s because it has no surface or is not focusable.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/InputMonitor.java"
+    },
+    "-6346673514571615151": {
+      "message": "Focus requested for window=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/InputMonitor.java"
+    },
+    "1522894362518893789": {
+      "message": "InsetsSource setWin %s for type %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WINDOW_INSETS",
+      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
+    },
+    "6243049416211184258": {
+      "message": "InsetsSource Control %s for target %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WINDOW_INSETS",
+      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
+    },
+    "-8234068212532234206": {
+      "message": "InsetsSource updateVisibility for %s, serverVisible: %s clientVisible: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WINDOW_INSETS",
+      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
+    },
+    "-8601070090234611338": {
+      "message": "ControlAdapter startAnimation mSource: %s controlTarget: %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_WINDOW_INSETS",
+      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
+    },
+    "-6857870589074001153": {
+      "message": "ControlAdapter onAnimationCancelled mSource: %s mControlTarget: %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_WINDOW_INSETS",
+      "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
+    },
+    "-6684172224226118673": {
+      "message": "onImeControlTargetChanged %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/InsetsStateController.java"
+    },
+    "8891808212671675155": {
+      "message": "clearLockedTasks: %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/LockTaskController.java"
+    },
+    "8970634498594714645": {
+      "message": "removeLockedTask: removed %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/LockTaskController.java"
+    },
+    "8735562128135241598": {
+      "message": "removeLockedTask: task=%s last task, reverting locktask mode. Callers=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/LockTaskController.java"
+    },
+    "737192738184050156": {
+      "message": "startLockTaskMode: Can't lock due to auth",
+      "level": "WARN",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/LockTaskController.java"
+    },
+    "-7119521978513736788": {
+      "message": "Mode default, asking user",
+      "level": "WARN",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/LockTaskController.java"
+    },
+    "-1557441750657584614": {
+      "message": "%s",
+      "level": "WARN",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/LockTaskController.java"
+    },
+    "-4314079913933391851": {
+      "message": "setLockTaskMode: Can't lock due to auth",
+      "level": "WARN",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/LockTaskController.java"
+    },
+    "3321878763832425380": {
+      "message": "setLockTaskMode: Locking to %s Callers=%s",
+      "level": "WARN",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/LockTaskController.java"
+    },
+    "-4819015209006579825": {
+      "message": "onLockTaskPackagesUpdated: removing %s mLockTaskAuth()=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/LockTaskController.java"
+    },
+    "2119751067469297845": {
+      "message": "onLockTaskPackagesUpdated: starting new locktask task=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/LockTaskController.java"
+    },
+    "3788905348567806832": {
+      "message": "startAnimation",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/NonAppWindowAnimationAdapter.java"
+    },
+    "705955074330737483": {
+      "message": "onAnimationCancelled",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/NonAppWindowAnimationAdapter.java"
+    },
+    "5106303602270682056": {
+      "message": "Adding display switch to existing collecting transition",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/PhysicalDisplaySwitchTransitionLauncher.java"
+    },
+    "3308140128142966415": {
+      "message": "remove RecentTask %s when finishing user %d",
+      "level": "INFO",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RecentTasks.java"
+    },
+    "-3758280623533049031": {
+      "message": "Preload recents with %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "-3365656764099317101": {
+      "message": "Updated config=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "-7165162073742035900": {
+      "message": "Real start recents",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "-3403665718306852375": {
+      "message": "startRecentsActivity(): intent=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "-8325607672707336373": {
+      "message": "No root task above target root task=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "-7278356485797757819": {
+      "message": "Moved rootTask=%s behind rootTask=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "1012359606301505741": {
+      "message": "Started intent=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "5474198007669537235": {
+      "message": "onAnimationFinished(): controller=%s reorderMode=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "3525834288436624965": {
+      "message": "onAnimationFinished(): targetRootTask=%s targetActivity=%s mRestoreTargetBehindRootTask=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "-5961176083217302671": {
+      "message": "Expected target rootTask=%s to be top most but found rootTask=%s",
+      "level": "WARN",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "-5893976429537642045": {
+      "message": "Expected target rootTask=%s to restored behind rootTask=%s but it is behind rootTask=%s",
+      "level": "WARN",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "4515487264815398694": {
+      "message": "onRootTaskOrderChanged(): rootTask=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimation.java"
+    },
+    "6530904107141905844": {
+      "message": "screenshotTask(%d): mCanceled=%b",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "-3286551982713129633": {
+      "message": "setFinishTaskTransaction(%d): transaction=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "5187133389446459984": {
+      "message": "finish(%b): mCanceled=%b",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "6879496555046975661": {
+      "message": "setInputConsumerEnabled(%s): mCanceled=%b",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "-5305978958548091997": {
+      "message": "setHomeApp(%s)",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "-3801497203749932106": {
+      "message": "addAnimation(%s)",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "3721473589747203697": {
+      "message": "removeAnimation(%d)",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "5156407755139006078": {
+      "message": "removeWallpaperAnimation()",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "-1997836523186474317": {
+      "message": "startAnimation(): mPendingStart=%b mCanceled=%b",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "-7532294363367395195": {
+      "message": "startAnimation(): Notify animation start: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "-1336603089105439710": {
+      "message": "collectTaskRemoteAnimations, target: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "2547528895718568379": {
+      "message": "createWallpaperAnimations()",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "5444932814080651576": {
+      "message": "cancelAnimation(): reason=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "622027757443954945": {
+      "message": "cleanupAnimation(): Notify animation finished mPendingAnimations=%d reorderMode=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RecentsAnimationController.java"
+    },
+    "-5444412205083968021": {
+      "message": "createAnimationAdapter(): container=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "6986037643494242400": {
+      "message": "goodToGo()",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-1902984034737899928": {
+      "message": "goodToGo(): Animation canceled already",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "6727618365838540075": {
+      "message": "goodToGo(): No apps to animate, mPendingAnimations=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-2525509826755873433": {
+      "message": "goodToGo(): onAnimationStart, transit=%s, apps=%d, wallpapers=%d, nonApps=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-1148281153370899511": {
+      "message": "startAnimation(): Notify animation start:",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "7501495587927045391": {
+      "message": "cancelAnimation(): reason=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-1424368765415574722": {
+      "message": "Starting remote animation",
+      "level": "INFO",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-2676700429940607853": {
+      "message": "%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "7094394833775573933": {
+      "message": "createAppAnimations()",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-4411070227420990074": {
+      "message": "\tAdd container=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-4411631520586057580": {
+      "message": "\tRemove container=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-7002230949892506736": {
+      "message": "createWallpaperAnimations()",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "8743612568733301175": {
+      "message": "createNonAppWindowAnimations()",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-2716313493239418198": {
+      "message": "onAnimationFinished(): mPendingAnimations=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "7221400292415257709": {
+      "message": "onAnimationFinished(): Notify animation finished:",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "7483194715776694698": {
+      "message": "\tcontainer=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "6697982664439247822": {
+      "message": "\twallpaper=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "6938838346517131964": {
+      "message": "\tnonApp=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-3880290251819699866": {
+      "message": "Finishing remote animation",
+      "level": "INFO",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "-7169244688499657832": {
+      "message": "app-onAnimationFinished(): mOuter=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "3923111589554171989": {
+      "message": "app-release(): mOuter=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "8918152561092803537": {
+      "message": "startAnimation",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
+    },
+    "1736084564226683342": {
+      "message": "Starting remote display change: from [rot = %d], to [%dx%d, rot = %d]",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/RemoteDisplayChangeController.java"
+    },
+    "-4617490621756721600": {
+      "message": "resetTaskIntendedTask: calling finishActivity on %s",
+      "level": "WARN",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java"
+    },
+    "3361857745281957526": {
+      "message": "Removing activity %s from task=%s adding to task=%s Callers=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java"
+    },
+    "3958829063955690349": {
+      "message": "Pushing next activity %s out to target's task %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java"
+    },
+    "1730793580703791926": {
+      "message": "Start pushing activity %s out to bottom task %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/ResetTargetTaskHelper.java"
+    },
+    "-8961882615747561040": {
+      "message": "Looking for task of %s in %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "8899721161806265460": {
+      "message": "Skipping task: (mismatch activity\/task) %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "6841550641928224256": {
+      "message": "Skipping %s: voice session",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "4468520936943270392": {
+      "message": "Skipping %s: different user",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "-4764624740388751268": {
+      "message": "Skipping %s: mismatch root %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "9031436623838917667": {
+      "message": "Skipping %s: mismatch activity type",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "6022828946761399284": {
+      "message": "Comparing existing cls=%s \/aff=%s to new cls=%s \/aff=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "-3413620974545388702": {
+      "message": "Found matching class!",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "-2649361982747625232": {
+      "message": "For Intent %s bringing to top: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "7046266138098744790": {
+      "message": "Found matching affinity candidate!",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "6481733556290926693": {
+      "message": "Not a match: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "3331249072840061049": {
+      "message": "New topFocusedDisplayId=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "865845626039449679": {
+      "message": "SURFACE RECOVER DESTROY: %s",
+      "level": "INFO",
+      "group": "WM_SHOW_SURFACE_ALLOC",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "-4150611780753674023": {
+      "message": "Wallpaper may change!  Adjusting",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WALLPAPER",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "4177291132772627699": {
+      "message": "With display frozen, orientationChangeComplete=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "-5513616928833586179": {
+      "message": "Performing post-rotate rotation",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "-7698723716637247994": {
+      "message": "handleNotObscuredLocked w: %s, w.mHasSurface: %b, w.isOnScreen(): %b, w.isDisplayedLw(): %b, w.mAttrs.userActivityTimeout: %d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_KEEP_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "8621291657500572364": {
+      "message": "mUserActivityTimeout set to %d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_KEEP_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "-1418592110950138870": {
+      "message": "Looking for task of type=%s, taskAffinity=%s, intent=%s, info=%s, preferredTDA=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "2828976699481734755": {
+      "message": "No task found",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "-4405347314716558580": {
+      "message": "Create sleep token: tag=%s, displayId=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "1329131651776855609": {
+      "message": "Remove sleep token: tag=%s, displayId=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "1653728842643223887": {
+      "message": "allResumedActivitiesIdle: rootTask=%d %s not idle",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "3785779399471740019": {
+      "message": "allPausedActivitiesComplete: r=%s state=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+    },
+    "4666728330189027178": {
+      "message": "Failed to register MediaProjectionWatcherCallback",
+      "level": "ERROR",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/ScreenRecordingCallbackController.java"
+    },
+    "8010999385228654193": {
+      "message": "  FREEZE %s: CREATE",
+      "level": "INFO",
+      "group": "WM_SHOW_SURFACE_ALLOC",
+      "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
+    },
+    "-6586462455018013482": {
+      "message": "Start rotation animation. customAnim=%s, mCurRotation=%s, mOriginalRotation=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
+    },
+    "-5825336546511998057": {
+      "message": "  FREEZE %s: DESTROY",
+      "level": "INFO",
+      "group": "WM_SHOW_SURFACE_ALLOC",
+      "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
+    },
+    "6883897856740637908": {
+      "message": "ScreenRotation still animating: type: %d\nmDisplayAnimator: %s\nmEnterBlackFrameAnimator: %s\nmRotateScreenAnimator: %s\nmScreenshotRotationAnimator: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
+    },
+    "-3943622313307983155": {
+      "message": "ScreenRotationAnimation onAnimationEnd",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
+    },
+    "-1594708154257031561": {
+      "message": "  NEW SURFACE SESSION %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/Session.java"
+    },
+    "2638961674625826260": {
+      "message": "  KILL SURFACE SESSION %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/Session.java"
+    },
+    "5380455212389185829": {
+      "message": "Removing dim surface %s on transaction %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_DIMMER",
+      "at": "com\/android\/server\/wm\/SmoothDimmer.java"
+    },
+    "-820649637734629482": {
+      "message": "Animation start delayed for %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/SurfaceAnimator.java"
+    },
+    "1371702561758591499": {
+      "message": "Animation start for %s, anim=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/SurfaceAnimator.java"
+    },
+    "-5370506662233296228": {
+      "message": "Cancelling animation restarting=%b for %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/SurfaceAnimator.java"
+    },
+    "-3045933321063743917": {
+      "message": "Reparenting to original parent: %s for %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/SurfaceAnimator.java"
+    },
+    "-855083149623806053": {
+      "message": "Reparenting to leash for %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/SurfaceAnimator.java"
+    },
+    "-2595923278763115975": {
+      "message": "  THUMBNAIL %s: CREATE",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/SurfaceFreezer.java"
+    },
+    "-8609432747982701423": {
+      "message": "Setting Intent of %s to %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
+    "-9155008290180285590": {
+      "message": "Setting Intent of %s to target %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_TASKS",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
+    "6424220442758232673": {
+      "message": "Removing and adding activity %s to root task at top callers=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
+    "-1028890010429408946": {
+      "message": "addChild: %s at top.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
+    "38991867929900764": {
+      "message": "setLockTaskAuth: task=%s mLockTaskAuth=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_LOCKTASK",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
+    "-3401780415681318335": {
+      "message": "applyAnimationUnchecked, control: %s, task: %s, transit: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RECENTS_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
+    "4446998544419008924": {
+      "message": "Moving to RESUMED: %s (starting new instance) callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
+    "4037728373502324767": {
+      "message": "resumeNextFocusableActivityWhenRootTaskIsEmpty: %s, go home",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
+    "-2261257617975724313": {
+      "message": "Adding activity %s to task %s callers: %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
+    "7378236902389922467": {
+      "message": "App is requesting an orientation, return %d for display id=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/TaskDisplayArea.java"
+    },
+    "2005499548343677845": {
+      "message": "No app is requesting an orientation, return %d for display id=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/TaskDisplayArea.java"
+    },
+    "646076184396185067": {
+      "message": "App died while pausing: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-7596917112222697106": {
+      "message": "Waiting for screen on due to %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-8472961767591168851": {
+      "message": "Sleep needs to pause %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-1472885369931482317": {
+      "message": "Sleep still waiting to pause %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-2693016397674039814": {
+      "message": "Sleep still need to stop %d activities",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "8892147402270850613": {
+      "message": "resumeTopActivity: Skip resume: some activity pausing.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "958293038551087087": {
+      "message": "resumeTopActivity: Top activity resumed %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "4340810061306869942": {
+      "message": "resumeTopActivity: Going to sleep and all paused",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-7681635901109618685": {
+      "message": "resumeTopActivity: Pausing %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-3463034909521330970": {
+      "message": "resumeTopActivity: Skip resume: need to start pausing",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-2264725269594226780": {
+      "message": "resumeTopActivity: Top activity resumed (dontWaitForPause) %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-8359248677489986541": {
+      "message": "Moving to RESUMED: %s (in existing)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "2088177629189452176": {
+      "message": "Activity config changed during resume: %s, new next: %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-8483536760290526299": {
+      "message": "resumeTopActivity: Resumed %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-4911500660485375799": {
+      "message": "Resume failed; resetting state to %s: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "3723891427717889172": {
+      "message": "resumeTopActivity: Restarting %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "1529152423206006904": {
+      "message": "startPausing: taskFrag =%s mResumedActivity=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "136971836458873178": {
+      "message": "Moving to PAUSING: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-208996201631695262": {
+      "message": "Auto-PIP allowed, requesting PIP mode via requestStartTransition(): %s, willAutoPip: %b",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-4123447037565780632": {
+      "message": "Auto-PIP allowed, entering PIP mode directly: %s, didAutoPip: %b",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-3710776151994843320": {
+      "message": "Key dispatch not paused for screen off",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "8543865526552245064": {
+      "message": "Activity not running or entered PiP, resuming next.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "1917394294249960915": {
+      "message": "Enqueueing pending pause: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-8936154984341817384": {
+      "message": "Complete pause: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "4971958459026584561": {
+      "message": "Executing finish of activity: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-7113165071559345173": {
+      "message": "Enqueue pending stop if needed: %s wasStopping=%b visibleRequested=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-3777748052684097788": {
+      "message": "App died during pause, not stopping: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STATES",
+      "at": "com\/android\/server\/wm\/TaskFragment.java"
+    },
+    "-2808577027789344626": {
+      "message": "TaskFragment appeared name=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
+    "-3582112419663037270": {
+      "message": "TaskFragment vanished name=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
+    "3294593748816836746": {
+      "message": "TaskFragment info changed name=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
+    "5007230330523630579": {
+      "message": "TaskFragment parent info changed name=%s parentTaskId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
+    "6475066005515810081": {
+      "message": "Sending TaskFragment error exception=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
+    "-7893265697482064583": {
+      "message": "Activity=%s reparent to taskId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
+    "7048981249808281819": {
+      "message": "Defer transition id=%d for TaskFragmentTransaction=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
+    "-1315509853595025526": {
+      "message": "Deferred transition id=%d has been continued before the TaskFragmentTransaction=%s is finished",
+      "level": "WARN",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
+    "7421521217481553621": {
+      "message": "Continue transition id=%d for TaskFragmentTransaction=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
+    "3509684748201636981": {
+      "message": "Register task fragment organizer=%s uid=%d pid=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
+    "-6777461169027010201": {
+      "message": "Unregister task fragment organizer=%s uid=%d pid=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
+    "1327792561585467865": {
+      "message": "Register remote animations for organizer=%s uid=%d pid=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
+    "-2524361347368208519": {
+      "message": "Unregister remote animations for organizer=%s uid=%d pid=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+    },
+    "-6181189296332065162": {
+      "message": "Task appeared taskId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+    },
+    "6535296991997214354": {
+      "message": "Task vanished taskId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+    },
+    "-6638141753476761854": {
+      "message": "Task info changed taskId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+    },
+    "-8100069665346602959": {
+      "message": "Task back pressed on root taskId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+    },
+    "-610138383571469481": {
+      "message": "Register task organizer=%s uid=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+    },
+    "1705860547080436016": {
+      "message": "Unregister task organizer=%s uid=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+    },
+    "-2286607251115721394": {
+      "message": "createRootTask unknown displayId=%d",
+      "level": "ERROR",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+    },
+    "8466395828406204368": {
+      "message": "Create root task displayId=%d winMode=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+    },
+    "6867170298997192615": {
+      "message": "Delete root task display=%d winMode=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+    },
+    "-4296644831871159510": {
+      "message": "Set intercept back pressed on root=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+    },
+    "-558727273888268534": {
+      "message": "Restart top activity process of Task taskId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+    },
+    "-7064081458956324316": {
+      "message": "Update camera compat control state to %s for taskId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
+    },
+    "3007492640459931179": {
+      "message": "Pausing rotation during re-position",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/TaskPositioner.java"
+    },
+    "5478864901888225320": {
+      "message": "Resuming rotation after re-position",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/TaskPositioner.java"
+    },
+    "-2700498872917476567": {
+      "message": "Starting a Recents transition which can be parallel.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-8676279589273455859": {
+      "message": "Transition %d: Set %s as transient-launch",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "2734227875286695843": {
+      "message": "Override sync-method for %s because seamless rotating",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "2808217645990556209": {
+      "message": "Starting Transition %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-4672522645315112127": {
+      "message": "Collecting in transition %d: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "65881049096729394": {
+      "message": " Creating Ready-group for Transition %d with root=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "1101215730201607371": {
+      "message": "Existence Changed in transition %d: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-3942072270654590479": {
+      "message": "Set transition ready=%b %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-4688704756793656554": {
+      "message": "  Commit activity becoming invisible: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "1817207111271920503": {
+      "message": "  Skipping post-transition snapshot for task %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-2960171012238790176": {
+      "message": "  Commit wallpaper becoming invisible: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "1230784960534033968": {
+      "message": "Aborting Transition: %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-892865733969888022": {
+      "message": "Force Playing Transition: %d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-1354622424895965634": {
       "message": "#%d: Met condition: %s",
       "level": "VERBOSE",
       "group": "WM_DEBUG_WINDOW_TRANSITIONS",
       "at": "com\/android\/server\/wm\/Transition.java"
     },
-    "2128917433": {
-      "message": "onProposedRotationChanged, rotation=%d",
+    "-5350671621840749173": {
+      "message": "Calling onTransitionReady: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "1830385055586991567": {
+      "message": "Apply and finish immediately because player is disabled for transition #%d .",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-758501334967569539": {
+      "message": "      SKIP: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-2714847784842612086": {
+      "message": "      SKIP: is wallpaper",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "1855461834864671586": {
+      "message": "      check sibling %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-6292043690918793069": {
+      "message": "        SKIP: sibling is visible but not part of transition",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "7897657428993391672": {
+      "message": "        unrelated invisible sibling %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "3873493605120555608": {
+      "message": "        sibling is a participant with mode %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "7665553560859456426": {
+      "message": "          SKIP: common mode mismatch. was %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-8916099332247176657": {
+      "message": "    checking %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-6818387694968032301": {
+      "message": "      SKIP: its sibling was rejected",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-7326702978448933012": {
+      "message": "        keep as target %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "943961036184959431": {
+      "message": "        remove from targets %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "841543868388687804": {
+      "message": "      CAN PROMOTE: promoting to parent %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "743586316159041023": {
+      "message": "Start calculating TransitionInfo based on participants: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-7247430213293162757": {
+      "message": "  Rejecting as detached: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-5811837191094192313": {
+      "message": "  Rejecting as no-op: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-1153926883525904120": {
+      "message": "  Initial targets: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-9191328656870721224": {
+      "message": "  Final targets: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-2971560715211489406": {
+      "message": " Add condition %s for #%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "7631061720069910622": {
+      "message": " Met condition %s for #%d (%d left)",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-4770394322045550928": {
+      "message": " Setting Ready-group to %b. group=%s from %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "6039132370452820927": {
+      "message": " Setting allReady override",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-3263748870548668913": {
+      "message": " allReady query: used=%b override=%b defer=%d states=[%s]",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "2699903406935781477": {
+      "message": "Screenshotting %s [%s]",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/Transition.java"
+    },
+    "-233096875591058130": {
+      "message": "Creating Transition: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/TransitionController.java"
+    },
+    "2154694726162725342": {
+      "message": "Start collecting in Transition: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/TransitionController.java"
+    },
+    "-4235778637051052061": {
+      "message": "Disabling player for transition #%d because display isn't enabled yet",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/TransitionController.java"
+    },
+    "4005704720444963797": {
+      "message": "Requesting StartTransition: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/TransitionController.java"
+    },
+    "-6030030735787868329": {
+      "message": "Finish Transition: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/TransitionController.java"
+    },
+    "-1611886029896664304": {
+      "message": "Moving #%d from collecting to waiting.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
+      "at": "com\/android\/server\/wm\/TransitionController.java"
+    },
+    "-7097461682459496366": {
+      "message": "Playing #%d in parallel on track #%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/TransitionController.java"
+    },
+    "-7364464699035275052": {
+      "message": "Marking #%d animation as SYNC.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/TransitionController.java"
+    },
+    "-5509640937151643757": {
+      "message": "Queueing transition: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
+      "at": "com\/android\/server\/wm\/TransitionController.java"
+    },
+    "-2741593375634604522": {
+      "message": "Queueing legacy sync-set: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
+      "at": "com\/android\/server\/wm\/TransitionController.java"
+    },
+    "-5051723169912572741": {
+      "message": "%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
+      "at": "com\/android\/server\/wm\/TransitionController.java"
+    },
+    "4281568181321808508": {
+      "message": "    startWCT=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
+      "at": "com\/android\/server\/wm\/TransitionController.java"
+    },
+    "5141999957143860655": {
+      "message": "    info=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS_MIN",
+      "at": "com\/android\/server\/wm\/TransitionController.java"
+    },
+    "3445530300764535903": {
+      "message": "unregister failed, couldn't find deathRecipient for %s with id=%d",
+      "level": "ERROR",
+      "group": "WM_DEBUG_TPL",
+      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
+    },
+    "-6140852484700685564": {
+      "message": "Registering listener=%s with id=%d for window=%s with %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TPL",
+      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
+    },
+    "3691097873058247482": {
+      "message": "Unregistering listener=%s with id=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TPL",
+      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
+    },
+    "6408851516381868623": {
+      "message": "Checking %d windows",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_TPL",
+      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
+    },
+    "7718187745767272532": {
+      "message": "Skipping %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_TPL",
+      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
+    },
+    "-1135667737459933313": {
+      "message": "coveredRegionsAbove updated with %s frame:%s region:%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_TPL",
+      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
+    },
+    "854487339271667012": {
+      "message": "checkIfInThreshold fractionRendered=%f alpha=%f currTimeMs=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_TPL",
+      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
+    },
+    "-2248576188205088843": {
+      "message": "lastState=%s newState=%s alpha=%f minAlpha=%f fractionRendered=%f minFractionRendered=%f",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_TPL",
+      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
+    },
+    "6236170793308011579": {
+      "message": "Adding untrusted state listener=%s with id=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TPL",
+      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
+    },
+    "5405816744363636527": {
+      "message": "Adding trusted state listener=%s with id=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_TPL",
+      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
+    },
+    "-5162728346383863020": {
+      "message": "computeFractionRendered: visibleRegion=%s screenBounds=%s contentSize=%s scale=%f,%f",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_TPL",
+      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
+    },
+    "898769258643799441": {
+      "message": "fractionRendered scale=%f",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_TPL",
+      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
+    },
+    "-455501334697331596": {
+      "message": "fractionRendered boundsOverSource=%f",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_TPL",
+      "at": "com\/android\/server\/wm\/TrustedPresentationListenerController.java"
+    },
+    "1964980935866463086": {
+      "message": "\tWallpaper of display=%s is not visible",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java"
+    },
+    "8131665298937888044": {
+      "message": "startAnimation",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java"
+    },
+    "8030745595351281943": {
+      "message": "onAnimationCancelled",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_REMOTE_ANIMATIONS",
+      "at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java"
+    },
+    "-5254364639040552989": {
+      "message": "Hiding wallpaper %s from %s target=%s prev=%s callers=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WALLPAPER",
+      "at": "com\/android\/server\/wm\/WallpaperController.java"
+    },
+    "-3477087868568520027": {
+      "message": "No longer animating wallpaper targets!",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WALLPAPER",
+      "at": "com\/android\/server\/wm\/WallpaperController.java"
+    },
+    "-3751289048117070874": {
+      "message": "New wallpaper target: %s prevTarget: %s caller=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WALLPAPER",
+      "at": "com\/android\/server\/wm\/WallpaperController.java"
+    },
+    "5625223922466895079": {
+      "message": "New animation: %s old animation: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WALLPAPER",
+      "at": "com\/android\/server\/wm\/WallpaperController.java"
+    },
+    "7634524672408826188": {
+      "message": "Animating wallpapers: old: %s hidden=%b new: %s hidden=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WALLPAPER",
+      "at": "com\/android\/server\/wm\/WallpaperController.java"
+    },
+    "-4345077332231178044": {
+      "message": "Old wallpaper still the target.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WALLPAPER",
+      "at": "com\/android\/server\/wm\/WallpaperController.java"
+    },
+    "-2504764636812266719": {
+      "message": "New wallpaper: target=%s prev=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WALLPAPER",
+      "at": "com\/android\/server\/wm\/WallpaperController.java"
+    },
+    "-7936547457136708587": {
+      "message": "Wallpaper token %s visible=%b",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WALLPAPER",
+      "at": "com\/android\/server\/wm\/WallpaperWindowToken.java"
+    },
+    "7214407534407465113": {
+      "message": "commitVisibility: %s: visible=%b mVisibleRequested=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/WallpaperWindowToken.java"
+    },
+    "-5360147928134631656": {
+      "message": ">>> OPEN TRANSACTION animate",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowAnimator.java"
+    },
+    "-3993586364046165922": {
+      "message": "<<< CLOSE TRANSACTION animate",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowAnimator.java"
+    },
+    "-5231580410559054259": {
+      "message": "%s is requesting orientation %d (%s)",
       "level": "VERBOSE",
       "group": "WM_DEBUG_ORIENTATION",
-      "at": "com\/android\/server\/wm\/DisplayRotation.java"
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
+    "6949303417875346627": {
+      "message": "Starting animation on %s: type=%d, anim=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
+    "-8730310387200541562": {
+      "message": "applyAnimation: transition animation is disabled or skipped. container=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
+    "2363818604357955690": {
+      "message": "applyAnimation: transit=%s, enter=%b, wc=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
+    "2262119454684034794": {
+      "message": "applyAnimation: container=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS_ANIM",
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
+    "5857165752965610762": {
+      "message": "Loading animation for app transition. transit=%s enter=%b frame=%s insets=%s surfaceInsets=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
+    "9017113545720281233": {
+      "message": "Loaded animation %s for %s, duration: %d, stack=%s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
+    "5272307326252759722": {
+      "message": "onSyncFinishedDrawing %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
+    "-8311909671193661340": {
+      "message": "setSyncGroup #%d on %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
+    "-3871009616397322067": {
+      "message": "finishSync cancel=%b for %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
+    "-4267530270533009730": {
+      "message": "Error sending initial configuration change to WindowContainer overlay",
+      "level": "ERROR",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
+    "5179630990780610966": {
+      "message": "Error sending initial insets change to WindowContainer overlay",
+      "level": "ERROR",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowContainer.java"
+    },
+    "-131600102855790053": {
+      "message": "  THUMBNAIL %s: CREATE",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowContainerThumbnail.java"
+    },
+    "2163930285157267092": {
+      "message": "The listener does not exist.",
+      "level": "INFO",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowContextListenerController.java"
+    },
+    "6139364662459841509": {
+      "message": "Could not register window container listener token=%s, container=%s",
+      "level": "ERROR",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowContextListenerController.java"
+    },
+    "3655576047584951173": {
+      "message": "Window Manager Crash %s",
+      "level": "WTF",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-3029436704707366221": {
+      "message": "Attempted to add window with a client %s that is dead. Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1303710477998542095": {
+      "message": "Attempted to add window to a display that does not exist: %d. Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "8039410207325630747": {
+      "message": "Attempted to add window to a display for which the application does not have access: %d.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-3451016577701561221": {
+      "message": "Window %s is already added",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "7245919222637411747": {
+      "message": "Attempted to add window with token that is not a window: %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-8579305050440451727": {
+      "message": "Attempted to add window with token that is a sub-window: %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1075040941127814341": {
+      "message": "Attempted to add private presentation window to a non-private display.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "7599690046549866326": {
+      "message": "Attempted to add presentation window to a non-suitable display.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-2546047231197102533": {
+      "message": "Trying to add window with invalid user=%d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "3713874359318494804": {
+      "message": "Attempted to add window with non-application token .%s Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-6507147599943157469": {
+      "message": "Attempted to add window with exiting application token .%s Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1409483453189443362": {
+      "message": "Attempted to add starting window to token with already existing starting window",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1806907994917883598": {
+      "message": "Attempted to add starting window to token but already cleaned",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-5450131464624918523": {
+      "message": "Attempted to add input method window with bad token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-6484128707849211138": {
+      "message": "Attempted to add voice interaction window with bad token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "7768591536609704658": {
+      "message": "Attempted to add wallpaper window with bad token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "7497077135474110999": {
+      "message": "Attempted to add Accessibility overlay window with bad token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "8957851092580119204": {
+      "message": "Attempted to add a toast window with bad token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1945746969404688952": {
+      "message": "Attempted to add QS dialog window with bad token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "3419934373251134563": {
+      "message": "Non-null activity for system window of rootType=%d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1161056447389155729": {
+      "message": "Adding more than one toast window for UID at a time.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-7518552252637236411": {
+      "message": "Window types in WindowContext and LayoutParams.type should match! Type from LayoutParams is %d, but type from WindowContext is %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-6055615852717459196": {
+      "message": "addWindow: %s startingWindow=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-2829980616540274784": {
+      "message": "addWindow: New client %s: window=%s Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-7315179333005789167": {
+      "message": "Attempted to add application window with unknown token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-7547709658889961930": {
+      "message": "Attempted to add input method window with unknown token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "3009864422591182484": {
+      "message": "Attempted to add voice interaction window with unknown token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-2639914438438144071": {
+      "message": "Attempted to add wallpaper window with unknown token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-7529563697886120786": {
+      "message": "Attempted to add QS dialog window with unknown token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "4253401518117961686": {
+      "message": "Attempted to add Accessibility overlay window with unknown token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "5834230650841873680": {
+      "message": "Attempted to add a toast window with unknown token %s.  Aborting.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "5265273548711408921": {
+      "message": "postWindowRemoveCleanupLocked: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-3847568084407666790": {
+      "message": "Final remove of window: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_MOVEMENT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1419572818243106725": {
+      "message": "Removing %s from %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "8312693933819247897": {
+      "message": "Relayout %s: oldVis=%d newVis=%d. %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "8319702790708803735": {
+      "message": "Exception thrown when creating surface for client %s (%s). %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "212929172223901460": {
+      "message": "Relayout of %s: focusMayChange=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-255991894956556845": {
+      "message": "Set animatingExit: reason=startExitingAnimation\/%s win=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "6555160513135851764": {
+      "message": "OUT SURFACE %s: copied",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-196459205494031145": {
+      "message": "Failed to create surface control for %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-5512006943172316333": {
+      "message": "finishDrawingWindow: %s mDrawState=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-2577785761087081584": {
+      "message": "Permission Denial: %s from pid=%d, uid=%d requires %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "4547566763172245740": {
+      "message": "addWindowToken: Attempted to add token: %s for non-exiting displayId=%d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-972832559831959983": {
+      "message": "addWindowToken: Attempted to add binder token: %s for already created window token: %s displayId=%d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "8372202339190060748": {
+      "message": "attachWindowContextToDisplayArea: calling from non-existing process pid=%d uid=%d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1904306629015452865": {
+      "message": "attachWindowContextToDisplayArea: trying to attach to a non-existing display:%d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-6845859096032432107": {
+      "message": "attachWindowContextToDisplayContent: calling from non-existing process pid=%d uid=%d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1473791807245791604": {
+      "message": "attachWindowContextToWindowToken: calling from non-existing process pid=%d uid=%d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-2056866750160555704": {
+      "message": "Then token:%s is invalid. It might be removed",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1045756671264607145": {
+      "message": "removeWindowToken: Attempted to remove token: %s for non-exiting displayId=%d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "874825105313641295": {
+      "message": "removeWindowToken: Attempted to remove non-existing token: %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "5128669121055635771": {
+      "message": "moveWindowTokenToDisplay: Attempted to move token: %s to non-exiting displayId=%d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "6497954191906583839": {
+      "message": "moveWindowTokenToDisplay: Attempted to move non-existing token: %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "2865882097969084039": {
+      "message": "moveWindowTokenToDisplay: Cannot move to the original display for token: %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-886583195545553099": {
+      "message": "Not moving display (displayId=%d) to top. Top focused displayId=%d. Reason: FLAG_STEAL_TOP_FOCUS_DISABLED",
+      "level": "INFO",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1557387535886241553": {
+      "message": "enableScreenAfterBoot: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-6467850045030187736": {
+      "message": "enableScreenIfNeededLocked: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "179762478329442868": {
+      "message": "***** BOOT TIMEOUT: forcing display enabled",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-3417569256875279779": {
+      "message": "performEnableScreen: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-7516915153725082358": {
+      "message": "performEnableScreen: Waited %dms for all windows to be drawn",
+      "level": "INFO",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1541244520024033685": {
+      "message": "performEnableScreen: Waiting for anim complete",
+      "level": "INFO",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "2670150656385758826": {
+      "message": "performEnableScreen: bootFinished() failed.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "530628508916855904": {
+      "message": "******************** ENABLING SCREEN!",
+      "level": "INFO",
+      "group": "WM_DEBUG_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "5477889324043875194": {
+      "message": "Notified TransitionController that the display is ready.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-2061779801633179448": {
+      "message": "checkBootAnimationComplete: Waiting for anim complete",
+      "level": "INFO",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-8177456840019985809": {
+      "message": "checkBootAnimationComplete: Animation complete!",
+      "level": "INFO",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-333924817004774456": {
+      "message": "showBootMessage: msg=%s always=%b mAllowBootMessages=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "2994810644159608200": {
+      "message": "hideBootMessagesLocked: mDisplayEnabled=%b mForceDisplayEnabled=%b mShowingBootMessages=%b mSystemBooted=%b. %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-6625203651195752178": {
+      "message": "freezeDisplayRotation: current rotation=%d, new rotation=%d, caller=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "8988910478484254861": {
+      "message": "thawRotation: mRotation=%d, caller=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "7261084872394224738": {
+      "message": "updateRotationUnchecked: alwaysSendConfiguration=%b forceRelayout=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "8664813170125714536": {
+      "message": "View server did not start",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-8019372496359375449": {
+      "message": "Could not send command %s with parameters %s. %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1893303527772009363": {
+      "message": "Devices still not ready after waiting %d milliseconds before attempting to detect safe mode.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-3652974372240081071": {
+      "message": "SAFE MODE ENABLED (menu=%d s=%d dpad=%d trackball=%d)",
+      "level": "INFO",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "4945624619344146947": {
+      "message": "SAFE MODE not enabled",
+      "level": "INFO",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-3428027271337724889": {
+      "message": "Focus changing: %s -> %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1624328195833150047": {
+      "message": "App freeze timeout expired.",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "5830724144971462783": {
+      "message": "Timeout waiting for drawn: undrawn=%s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-2240705227895260140": {
+      "message": "CHECK_IF_BOOT_ANIMATION_FINISHED:",
+      "level": "INFO",
+      "group": "WM_DEBUG_BOOT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "8641557333789260779": {
+      "message": "FORCED DISPLAY SIZE: %dx%d",
+      "level": "INFO",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "3781141652793604337": {
+      "message": "FORCED DISPLAY SCALING DISABLED",
+      "level": "INFO",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "4117606810523219596": {
+      "message": "Failed looking up window session=%s callers=%s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1233670725456443473": {
+      "message": "Changing surface while display frozen: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1716033239040181528": {
+      "message": "Waiting for drawn %s: removed=%b visible=%b mHasSurface=%b drawState=%d",
+      "level": "INFO",
+      "group": "WM_DEBUG_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-4609828204247499633": {
+      "message": "Aborted waiting for drawn: %s",
+      "level": "WARN",
+      "group": "WM_DEBUG_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-7561054602203220590": {
+      "message": "Window drawn win=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "2809030008663191766": {
+      "message": "All windows drawn!",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_SCREEN_ON",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1615905649072328410": {
+      "message": "startFreezingDisplayLocked: exitAnim=%d enterAnim=%d called by %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "4565793239453546297": {
+      "message": "stopFreezingDisplayLocked: Returning waitingForConfig=%b, waitingForRemoteDisplayChange=%b, mAppsFreezingScreen=%d, mWindowsFreezingScreen=%d, mClientFreezingScreen=%b, mOpeningApps.size()=%d",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-6877112251967196129": {
+      "message": "stopFreezingDisplayLocked: Unfreezing now",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "721393258715103117": {
+      "message": "%s",
+      "level": "INFO",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-5706083447992207254": {
+      "message": "**** Dismissing screen rotation animation",
+      "level": "INFO",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "2233371241933584073": {
+      "message": "Performing post-rotate rotation",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1010635158502326025": {
+      "message": "unable to call receiver for empty keyboard shortcuts",
+      "level": "ERROR",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1278715281433572858": {
+      "message": "Bad requesting window %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-707915937966769475": {
+      "message": "unable to update pointer icon",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-8663841671650918687": {
+      "message": "unable to restore pointer icon",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-6186782212018913664": {
+      "message": "Invalid displayId for requestScrollCapture: %d",
+      "level": "ERROR",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "51378282333944649": {
+      "message": "requestScrollCapture: caught exception dispatching to window.token=%s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-8972916676375201577": {
+      "message": "requestScrollCapture: caught exception dispatching callback: %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-1875125162673622728": {
+      "message": "Attempted to get windowing mode of a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "3938331948687900219": {
+      "message": "Attempted to set windowing mode to a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "4200292050699107329": {
+      "message": "Attempted to get remove mode of a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-5574580669790275797": {
+      "message": "Attempted to set remove mode to a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "525945815055875796": {
+      "message": "Attempted to get flag of a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "8186524992939307511": {
+      "message": "Attempted to set flag to a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-600035824255550632": {
+      "message": "Attempted to get system decors flag of a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "3056518663346732662": {
+      "message": "Attempted to set system decors flag to a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "5177195624625618567": {
+      "message": "Attempted to get IME policy of a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "3932627933834459400": {
+      "message": "Attempted to set IME policy to a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "5770211341769258866": {
+      "message": "setWallpaperShowWhenLocked: non-existent wallpaper token: %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "698926505694016512": {
+      "message": "setWallpaperCropHints: non-existent wallpaper token: %s",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-7428028317216329062": {
+      "message": "hideIme target: %s ",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "1006302987953651112": {
+      "message": "hideIme Control target: %s ",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_IME",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "5213970642134448962": {
+      "message": "Attempted to get home support flag of a display that does not exist: %d",
+      "level": "WARN",
+      "group": "WM_ERROR",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-2065144681579661392": {
+      "message": "onPointerDownOutsideFocusLocked called on %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-7394143854567081754": {
+      "message": "grantEmbeddedWindowFocus win=%s dropped focus so setting focus to null since no candidate was found",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "-6056928081282320632": {
+      "message": "grantEmbeddedWindowFocus win=%s grantFocus=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/WindowManagerService.java"
+    },
+    "6110791601270766802": {
+      "message": "TaskFragmentTransaction changes are not collected in transition because there is an ongoing sync for applySyncTransaction().",
+      "level": "WARN",
+      "group": "WM_DEBUG_WINDOW_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/WindowOrganizerController.java"
+    },
+    "9200403125156001641": {
+      "message": "Apply window transaction, syncId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/WindowOrganizerController.java"
+    },
+    "433446585990132440": {
+      "message": "Set sync ready, syncId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/WindowOrganizerController.java"
+    },
+    "6552038620140878489": {
+      "message": "Transaction ready, syncId=%d",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_WINDOW_ORGANIZER",
+      "at": "com\/android\/server\/wm\/WindowOrganizerController.java"
+    },
+    "-4629255026637000251": {
+      "message": "Sending to proc %s new config %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_CONFIGURATION",
+      "at": "com\/android\/server\/wm\/WindowProcessController.java"
+    },
+    "-7237767461056267619": {
+      "message": "%s: Setting back callback %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "8135615413833185273": {
+      "message": "Adding %s to %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "8842744325264128950": {
+      "message": "Resize reasons for w=%s:  %s configChanged=%b didFrameInsetsChange=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_RESIZE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-8636590597069784069": {
+      "message": "Resizing window %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_RESIZE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-2710188685736986208": {
+      "message": "Orientation not waiting for draw in %s, surfaceController %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "5236278969232209904": {
+      "message": "onMovedByResize: Moving %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RESIZE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "7646042751617940718": {
+      "message": "Set animatingExit: reason=onAppVisibilityChanged win=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "1783521309242112490": {
+      "message": "onResize: Resizing %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_RESIZE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "1351053513466395411": {
+      "message": "WS.removeImmediately: %s Already removed...",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "3927343382258792268": {
+      "message": "removeIfPossible: %s callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-4831815184899821371": {
+      "message": "Starting window removed %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-5803097884846965819": {
+      "message": "Remove client=%x, surfaceController=%s Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-2547748024041128829": {
+      "message": "Remove %s: mSurfaceController=%s mAnimatingExit=%b mRemoveOnExit=%b mHasSurface=%b surfaceShowing=%b animating=%b app-animation=%b mDisplayFrozen=%b callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "7789778354950913237": {
+      "message": "Set animatingExit: reason=remove\/applyAnimation win=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-4143841388126586338": {
+      "message": "Not removing %s due to exit animation",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "4419190702135590390": {
+      "message": "Set animatingExit: reason=remove\/isAnimating win=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-6167820560758523840": {
+      "message": "setAnimationLocked: setting mFocusMayChange true",
+      "level": "INFO",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-208079497999140637": {
+      "message": "WindowState.hideLw: setting mFocusMayChange true",
+      "level": "INFO",
+      "group": "WM_DEBUG_FOCUS_LIGHT",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "8812513438749898553": {
+      "message": "set mOrientationChanging of %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-2964267636425934067": {
+      "message": "win=%s destroySurfaces: appStopped=%b win.mWindowRemovalAllowed=%b win.mRemoveOnExit=%b",
+      "level": "ERROR",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "7336961102428192483": {
+      "message": "Clear animatingExit: reason=destroySurface win=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-6920306331987525705": {
+      "message": "Reporting new frame to %s: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_RESIZE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "2714651498627020992": {
+      "message": "Resizing %s WITH DRAW PENDING",
+      "level": "INFO",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-5755338358883139945": {
+      "message": "Requested redraw for orientation change: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-5211036212243647844": {
+      "message": "notifyInsetsChanged for %s ",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WINDOW_INSETS",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-3186229270467822891": {
+      "message": "notifyInsetsControlChanged for %s ",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_WINDOW_INSETS",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-7413136364930452718": {
+      "message": "performShowLocked: mDrawState=HAS_DRAWN in %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "7624470121297688739": {
+      "message": "shouldWaitAnimatingExit: isTransition: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "810267895099109466": {
+      "message": "shouldWaitAnimatingExit: isAnimating: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-1760879391350377377": {
+      "message": "shouldWaitAnimatingExit: isWallpaperTarget: %s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "272960397873328729": {
+      "message": "Clear window stuck on animatingExit status: %s",
+      "level": "WARN",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-1007526574020149845": {
+      "message": "onExitAnimationDone in %s: exiting=%b remove=%b selfAnimating=%b anim=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "1738645946553610841": {
+      "message": "Exit animation finished in %s: remove=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-7737516306844862315": {
+      "message": "Clear animatingExit: reason=exitAnimationDone win=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-3153130647145726082": {
+      "message": "Clear animatingExit: reason=clearAnimatingFlags win=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-5202247309108694583": {
+      "message": "Clear animatingExit: reason=relayoutVisibleWindow win=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "6291563604478341956": {
+      "message": "Setting move animation on %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-5774445199273871848": {
+      "message": "Preparing to sync a window that was already in the sync, so try dropping buffer. win=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "8097934579596343476": {
+      "message": "Got a buffer for request id=%d but latest request is id=%d. Since the buffer is out-of-date, drop it. win=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_SYNC_ENGINE",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "8269653477215188641": {
+      "message": "SURFACE isSecure=%b: %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowState.java"
+    },
+    "-1495677286613044867": {
+      "message": "Animation done in %s: exiting=%b, reportedVisible=%b",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "3436877176443058520": {
+      "message": "Finishing drawing window %s: mDrawState=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "345647873457403698": {
+      "message": "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING %s in %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_DRAW",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "-2385558637577093121": {
+      "message": "Draw state now committed in %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_STARTING_WINDOW",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "-3490933626936411542": {
+      "message": "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW %s",
+      "level": "INFO",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "-6088246515441976339": {
+      "message": "createSurface %s: mDrawState=DRAW_PENDING",
+      "level": "INFO",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "2353125758087345363": {
+      "message": "  CREATE SURFACE %s IN SESSION %s: pid=%d format=%d flags=0x%x \/ %s",
+      "level": "INFO",
+      "group": "WM_SHOW_SURFACE_ALLOC",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "-4491856282178275074": {
+      "message": "SURFACE DESTROY: %s. %s",
+      "level": "INFO",
+      "group": "WM_SHOW_SURFACE_ALLOC",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "8602950884833508970": {
+      "message": "Orientation change skips hidden %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "-5079712802591263622": {
+      "message": "SURFACE controller=%s alpha=%f HScale=%f, VScale=%f: %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "-2824875917893878016": {
+      "message": "Orientation continue waiting for draw in %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "7457181879495900576": {
+      "message": "Orientation change complete in %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "-5668794009329913533": {
+      "message": "applyAnimation: win=%s anim=%d attr=0x%x a=%s transit=%d type=%d isEntrance=%b Callers %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ANIM",
+      "at": "com\/android\/server\/wm\/WindowStateAnimator.java"
+    },
+    "-2055407587764455051": {
+      "message": "SURFACE HIDE ( %s ): %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
+    },
+    "-5854683348829455340": {
+      "message": "Destroying surface %s called by %s",
+      "level": "INFO",
+      "group": "WM_SHOW_SURFACE_ALLOC",
+      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
+    },
+    "7813672046338784579": {
+      "message": "SURFACE isOpaque=%b: %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
+    },
+    "-8864150640874799238": {
+      "message": "SURFACE isColorSpaceAgnostic=%b: %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
+    },
+    "-8398940245851553814": {
+      "message": "SURFACE SHOW (performLayout): %s",
+      "level": "INFO",
+      "group": "WM_SHOW_TRANSACTIONS",
+      "at": "com\/android\/server\/wm\/WindowSurfaceController.java"
+    },
+    "8174298531248485625": {
+      "message": "removeAllWindowsIfPossible: removing win=%s",
+      "level": "WARN",
+      "group": "WM_DEBUG_WINDOW_MOVEMENT",
+      "at": "com\/android\/server\/wm\/WindowToken.java"
+    },
+    "2740931087734487464": {
+      "message": "addWindow: win=%s Callers=%s",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_FOCUS",
+      "at": "com\/android\/server\/wm\/WindowToken.java"
+    },
+    "2382798629637143561": {
+      "message": "Adding %s to %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/WindowToken.java"
+    },
+    "-7314975896738778749": {
+      "message": "setClientVisible: %s clientVisible=%b Callers=%s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_APP_TRANSITIONS",
+      "at": "com\/android\/server\/wm\/WindowToken.java"
     }
   },
   "groups": {
diff --git a/graphics/java/android/graphics/pdf/PdfEditor.java b/graphics/java/android/graphics/pdf/PdfEditor.java
index 69e1982..3cd709e 100644
--- a/graphics/java/android/graphics/pdf/PdfEditor.java
+++ b/graphics/java/android/graphics/pdf/PdfEditor.java
@@ -25,9 +25,7 @@
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.OsConstants;
-
 import dalvik.system.CloseGuard;
-
 import libcore.io.IoUtils;
 
 import java.io.IOException;
@@ -39,12 +37,6 @@
  */
 public final class PdfEditor {
 
-    /**
-     * Any call the native pdfium code has to be single threaded as the library does not support
-     * parallel use.
-     */
-    private static final Object sPdfiumLock = new Object();
-
     private final CloseGuard mCloseGuard = CloseGuard.get();
 
     private long mNativeDocument;
@@ -87,7 +79,7 @@
         }
         mInput = input;
 
-        synchronized (sPdfiumLock) {
+        synchronized (PdfRenderer.sPdfiumLock) {
             mNativeDocument = nativeOpen(mInput.getFd(), size);
             try {
                 mPageCount = nativeGetPageCount(mNativeDocument);
@@ -120,7 +112,7 @@
         throwIfClosed();
         throwIfPageNotInDocument(pageIndex);
 
-        synchronized (sPdfiumLock) {
+        synchronized (PdfRenderer.sPdfiumLock) {
             mPageCount = nativeRemovePage(mNativeDocument, pageIndex);
         }
     }
@@ -146,12 +138,12 @@
             Point size = new Point();
             getPageSize(pageIndex, size);
 
-            synchronized (sPdfiumLock) {
+            synchronized (PdfRenderer.sPdfiumLock) {
                 nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.ni(),
                         0, 0, size.x, size.y);
             }
         } else {
-            synchronized (sPdfiumLock) {
+            synchronized (PdfRenderer.sPdfiumLock) {
                 nativeSetTransformAndClip(mNativeDocument, pageIndex, transform.ni(),
                         clip.left, clip.top, clip.right, clip.bottom);
             }
@@ -169,7 +161,7 @@
         throwIfOutSizeNull(outSize);
         throwIfPageNotInDocument(pageIndex);
 
-        synchronized (sPdfiumLock) {
+        synchronized (PdfRenderer.sPdfiumLock) {
             nativeGetPageSize(mNativeDocument, pageIndex, outSize);
         }
     }
@@ -185,7 +177,7 @@
         throwIfOutMediaBoxNull(outMediaBox);
         throwIfPageNotInDocument(pageIndex);
 
-        synchronized (sPdfiumLock) {
+        synchronized (PdfRenderer.sPdfiumLock) {
             return nativeGetPageMediaBox(mNativeDocument, pageIndex, outMediaBox);
         }
     }
@@ -201,7 +193,7 @@
         throwIfMediaBoxNull(mediaBox);
         throwIfPageNotInDocument(pageIndex);
 
-        synchronized (sPdfiumLock) {
+        synchronized (PdfRenderer.sPdfiumLock) {
             nativeSetPageMediaBox(mNativeDocument, pageIndex, mediaBox);
         }
     }
@@ -217,7 +209,7 @@
         throwIfOutCropBoxNull(outCropBox);
         throwIfPageNotInDocument(pageIndex);
 
-        synchronized (sPdfiumLock) {
+        synchronized (PdfRenderer.sPdfiumLock) {
             return nativeGetPageCropBox(mNativeDocument, pageIndex, outCropBox);
         }
     }
@@ -233,7 +225,7 @@
         throwIfCropBoxNull(cropBox);
         throwIfPageNotInDocument(pageIndex);
 
-        synchronized (sPdfiumLock) {
+        synchronized (PdfRenderer.sPdfiumLock) {
             nativeSetPageCropBox(mNativeDocument, pageIndex, cropBox);
         }
     }
@@ -246,7 +238,7 @@
     public boolean shouldScaleForPrinting() {
         throwIfClosed();
 
-        synchronized (sPdfiumLock) {
+        synchronized (PdfRenderer.sPdfiumLock) {
             return nativeScaleForPrinting(mNativeDocument);
         }
     }
@@ -263,7 +255,7 @@
         try {
             throwIfClosed();
 
-            synchronized (sPdfiumLock) {
+            synchronized (PdfRenderer.sPdfiumLock) {
                 nativeWrite(mNativeDocument, output.getFd());
             }
         } finally {
@@ -295,7 +287,7 @@
 
     private void doClose() {
         if (mNativeDocument != 0) {
-            synchronized (sPdfiumLock) {
+            synchronized (PdfRenderer.sPdfiumLock) {
                 nativeClose(mNativeDocument);
             }
             mNativeDocument = 0;
diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java
new file mode 100644
index 0000000..4666963
--- /dev/null
+++ b/graphics/java/android/graphics/pdf/PdfRenderer.java
@@ -0,0 +1,502 @@
+/*
+ * Copyright (C) 2014 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 android.graphics.pdf;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.compat.annotation.UnsupportedAppUsage;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.Matrix;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.Build;
+import android.os.ParcelFileDescriptor;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+
+import com.android.internal.util.Preconditions;
+
+import dalvik.system.CloseGuard;
+
+import libcore.io.IoUtils;
+
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * <p>
+ * This class enables rendering a PDF document. This class is not thread safe.
+ * </p>
+ * <p>
+ * If you want to render a PDF, you create a renderer and for every page you want
+ * to render, you open the page, render it, and close the page. After you are done
+ * with rendering, you close the renderer. After the renderer is closed it should not
+ * be used anymore. Note that the pages are rendered one by one, i.e. you can have
+ * only a single page opened at any given time.
+ * </p>
+ * <p>
+ * A typical use of the APIs to render a PDF looks like this:
+ * </p>
+ * <pre>
+ * // create a new renderer
+ * PdfRenderer renderer = new PdfRenderer(getSeekableFileDescriptor());
+ *
+ * // let us just render all pages
+ * final int pageCount = renderer.getPageCount();
+ * for (int i = 0; i < pageCount; i++) {
+ *     Page page = renderer.openPage(i);
+ *
+ *     // say we render for showing on the screen
+ *     page.render(mBitmap, null, null, Page.RENDER_MODE_FOR_DISPLAY);
+ *
+ *     // do stuff with the bitmap
+ *
+ *     // close the page
+ *     page.close();
+ * }
+ *
+ * // close the renderer
+ * renderer.close();
+ * </pre>
+ *
+ * <h3>Print preview and print output</h3>
+ * <p>
+ * If you are using this class to rasterize a PDF for printing or show a print
+ * preview, it is recommended that you respect the following contract in order
+ * to provide a consistent user experience when seeing a preview and printing,
+ * i.e. the user sees a preview that is the same as the printout.
+ * </p>
+ * <ul>
+ * <li>
+ * Respect the property whether the document would like to be scaled for printing
+ * as per {@link #shouldScaleForPrinting()}.
+ * </li>
+ * <li>
+ * When scaling a document for printing the aspect ratio should be preserved.
+ * </li>
+ * <li>
+ * Do not inset the content with any margins from the {@link android.print.PrintAttributes}
+ * as the application is responsible to render it such that the margins are respected.
+ * </li>
+ * <li>
+ * If document page size is greater than the printed media size the content should
+ * be anchored to the upper left corner of the page for left-to-right locales and
+ * top right corner for right-to-left locales.
+ * </li>
+ * </ul>
+ *
+ * @see #close()
+ */
+public final class PdfRenderer implements AutoCloseable {
+    /**
+     * Any call the native pdfium code has to be single threaded as the library does not support
+     * parallel use.
+     */
+    final static Object sPdfiumLock = new Object();
+
+    private final CloseGuard mCloseGuard = CloseGuard.get();
+
+    private final Point mTempPoint = new Point();
+
+    private long mNativeDocument;
+
+    private final int mPageCount;
+
+    private ParcelFileDescriptor mInput;
+
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+    private Page mCurrentPage;
+
+    /** @hide */
+    @IntDef({
+        Page.RENDER_MODE_FOR_DISPLAY,
+        Page.RENDER_MODE_FOR_PRINT
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface RenderMode {}
+
+    /**
+     * Creates a new instance.
+     * <p>
+     * <strong>Note:</strong> The provided file descriptor must be <strong>seekable</strong>,
+     * i.e. its data being randomly accessed, e.g. pointing to a file.
+     * </p>
+     * <p>
+     * <strong>Note:</strong> This class takes ownership of the passed in file descriptor
+     * and is responsible for closing it when the renderer is closed.
+     * </p>
+     * <p>
+     * If the file is from an untrusted source it is recommended to run the renderer in a separate,
+     * isolated process with minimal permissions to limit the impact of security exploits.
+     * </p>
+     *
+     * @param input Seekable file descriptor to read from.
+     *
+     * @throws java.io.IOException If an error occurs while reading the file.
+     * @throws java.lang.SecurityException If the file requires a password or
+     *         the security scheme is not supported.
+     */
+    public PdfRenderer(@NonNull ParcelFileDescriptor input) throws IOException {
+        if (input == null) {
+            throw new NullPointerException("input cannot be null");
+        }
+
+        final long size;
+        try {
+            Os.lseek(input.getFileDescriptor(), 0, OsConstants.SEEK_SET);
+            size = Os.fstat(input.getFileDescriptor()).st_size;
+        } catch (ErrnoException ee) {
+            throw new IllegalArgumentException("file descriptor not seekable");
+        }
+        mInput = input;
+
+        synchronized (sPdfiumLock) {
+            mNativeDocument = nativeCreate(mInput.getFd(), size);
+            try {
+                mPageCount = nativeGetPageCount(mNativeDocument);
+            } catch (Throwable t) {
+                nativeClose(mNativeDocument);
+                mNativeDocument = 0;
+                throw t;
+            }
+        }
+
+        mCloseGuard.open("close");
+    }
+
+    /**
+     * Closes this renderer. You should not use this instance
+     * after this method is called.
+     */
+    public void close() {
+        throwIfClosed();
+        throwIfPageOpened();
+        doClose();
+    }
+
+    /**
+     * Gets the number of pages in the document.
+     *
+     * @return The page count.
+     */
+    public int getPageCount() {
+        throwIfClosed();
+        return mPageCount;
+    }
+
+    /**
+     * Gets whether the document prefers to be scaled for printing.
+     * You should take this info account if the document is rendered
+     * for printing and the target media size differs from the page
+     * size.
+     *
+     * @return If to scale the document.
+     */
+    public boolean shouldScaleForPrinting() {
+        throwIfClosed();
+
+        synchronized (sPdfiumLock) {
+            return nativeScaleForPrinting(mNativeDocument);
+        }
+    }
+
+    /**
+     * Opens a page for rendering.
+     *
+     * @param index The page index.
+     * @return A page that can be rendered.
+     *
+     * @see android.graphics.pdf.PdfRenderer.Page#close() PdfRenderer.Page.close()
+     */
+    public Page openPage(int index) {
+        throwIfClosed();
+        throwIfPageOpened();
+        throwIfPageNotInDocument(index);
+        mCurrentPage = new Page(index);
+        return mCurrentPage;
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            if (mCloseGuard != null) {
+                mCloseGuard.warnIfOpen();
+            }
+
+            doClose();
+        } finally {
+            super.finalize();
+        }
+    }
+
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+    private void doClose() {
+        if (mCurrentPage != null) {
+            mCurrentPage.close();
+            mCurrentPage = null;
+        }
+
+        if (mNativeDocument != 0) {
+            synchronized (sPdfiumLock) {
+                nativeClose(mNativeDocument);
+            }
+            mNativeDocument = 0;
+        }
+
+        if (mInput != null) {
+            IoUtils.closeQuietly(mInput);
+            mInput = null;
+        }
+        mCloseGuard.close();
+    }
+
+    private void throwIfClosed() {
+        if (mInput == null) {
+            throw new IllegalStateException("Already closed");
+        }
+    }
+
+    private void throwIfPageOpened() {
+        if (mCurrentPage != null) {
+            throw new IllegalStateException("Current page not closed");
+        }
+    }
+
+    private void throwIfPageNotInDocument(int pageIndex) {
+        if (pageIndex < 0 || pageIndex >= mPageCount) {
+            throw new IllegalArgumentException("Invalid page index");
+        }
+    }
+
+    /**
+     * This class represents a PDF document page for rendering.
+     */
+    public final class Page implements AutoCloseable {
+
+        private final CloseGuard mCloseGuard = CloseGuard.get();
+
+        /**
+         * Mode to render the content for display on a screen.
+         */
+        public static final int RENDER_MODE_FOR_DISPLAY = 1;
+
+        /**
+         * Mode to render the content for printing.
+         */
+        public static final int RENDER_MODE_FOR_PRINT = 2;
+
+        private final int mIndex;
+        private final int mWidth;
+        private final int mHeight;
+
+        private long mNativePage;
+
+        private Page(int index) {
+            Point size = mTempPoint;
+            synchronized (sPdfiumLock) {
+                mNativePage = nativeOpenPageAndGetSize(mNativeDocument, index, size);
+            }
+            mIndex = index;
+            mWidth = size.x;
+            mHeight = size.y;
+            mCloseGuard.open("close");
+        }
+
+        /**
+         * Gets the page index.
+         *
+         * @return The index.
+         */
+        public int getIndex() {
+            return  mIndex;
+        }
+
+        /**
+         * Gets the page width in points (1/72").
+         *
+         * @return The width in points.
+         */
+        public int getWidth() {
+            return mWidth;
+        }
+
+        /**
+         * Gets the page height in points (1/72").
+         *
+         * @return The height in points.
+         */
+        public int getHeight() {
+            return mHeight;
+        }
+
+        /**
+         * Renders a page to a bitmap.
+         * <p>
+         * You may optionally specify a rectangular clip in the bitmap bounds. No rendering
+         * outside the clip will be performed, hence it is your responsibility to initialize
+         * the bitmap outside the clip.
+         * </p>
+         * <p>
+         * You may optionally specify a matrix to transform the content from page coordinates
+         * which are in points (1/72") to bitmap coordinates which are in pixels. If this
+         * matrix is not provided this method will apply a transformation that will fit the
+         * whole page to the destination clip if provided or the destination bitmap if no
+         * clip is provided.
+         * </p>
+         * <p>
+         * The clip and transformation are useful for implementing tile rendering where the
+         * destination bitmap contains a portion of the image, for example when zooming.
+         * Another useful application is for printing where the size of the bitmap holding
+         * the page is too large and a client can render the page in stripes.
+         * </p>
+         * <p>
+         * <strong>Note: </strong> The destination bitmap format must be
+         * {@link Config#ARGB_8888 ARGB}.
+         * </p>
+         * <p>
+         * <strong>Note: </strong> The optional transformation matrix must be affine as per
+         * {@link android.graphics.Matrix#isAffine() Matrix.isAffine()}. Hence, you can specify
+         * rotation, scaling, translation but not a perspective transformation.
+         * </p>
+         *
+         * @param destination Destination bitmap to which to render.
+         * @param destClip Optional clip in the bitmap bounds.
+         * @param transform Optional transformation to apply when rendering.
+         * @param renderMode The render mode.
+         *
+         * @see #RENDER_MODE_FOR_DISPLAY
+         * @see #RENDER_MODE_FOR_PRINT
+         */
+        public void render(@NonNull Bitmap destination, @Nullable Rect destClip,
+                           @Nullable Matrix transform, @RenderMode int renderMode) {
+            if (mNativePage == 0) {
+                throw new NullPointerException();
+            }
+
+            destination = Preconditions.checkNotNull(destination, "bitmap null");
+
+            if (destination.getConfig() != Config.ARGB_8888) {
+                throw new IllegalArgumentException("Unsupported pixel format");
+            }
+
+            if (destClip != null) {
+                if (destClip.left < 0 || destClip.top < 0
+                        || destClip.right > destination.getWidth()
+                        || destClip.bottom > destination.getHeight()) {
+                    throw new IllegalArgumentException("destBounds not in destination");
+                }
+            }
+
+            if (transform != null && !transform.isAffine()) {
+                 throw new IllegalArgumentException("transform not affine");
+            }
+
+            if (renderMode != RENDER_MODE_FOR_PRINT && renderMode != RENDER_MODE_FOR_DISPLAY) {
+                throw new IllegalArgumentException("Unsupported render mode");
+            }
+
+            if (renderMode == RENDER_MODE_FOR_PRINT && renderMode == RENDER_MODE_FOR_DISPLAY) {
+                throw new IllegalArgumentException("Only single render mode supported");
+            }
+
+            final int contentLeft = (destClip != null) ? destClip.left : 0;
+            final int contentTop = (destClip != null) ? destClip.top : 0;
+            final int contentRight = (destClip != null) ? destClip.right
+                    : destination.getWidth();
+            final int contentBottom = (destClip != null) ? destClip.bottom
+                    : destination.getHeight();
+
+            // If transform is not set, stretch page to whole clipped area
+            if (transform == null) {
+                int clipWidth = contentRight - contentLeft;
+                int clipHeight = contentBottom - contentTop;
+
+                transform = new Matrix();
+                transform.postScale((float)clipWidth / getWidth(),
+                        (float)clipHeight / getHeight());
+                transform.postTranslate(contentLeft, contentTop);
+            }
+
+            // FIXME: This code is planned to be outside the UI rendering module, so it should not
+            // be able to access native instances from Bitmap, Matrix, etc.
+            final long transformPtr = transform.ni();
+
+            synchronized (sPdfiumLock) {
+                nativeRenderPage(mNativeDocument, mNativePage, destination.getNativeInstance(),
+                        contentLeft, contentTop, contentRight, contentBottom, transformPtr,
+                        renderMode);
+            }
+        }
+
+        /**
+         * Closes this page.
+         *
+         * @see android.graphics.pdf.PdfRenderer#openPage(int)
+         */
+        @Override
+        public void close() {
+            throwIfClosed();
+            doClose();
+        }
+
+        @Override
+        protected void finalize() throws Throwable {
+            try {
+                if (mCloseGuard != null) {
+                    mCloseGuard.warnIfOpen();
+                }
+
+                doClose();
+            } finally {
+                super.finalize();
+            }
+        }
+
+        private void doClose() {
+            if (mNativePage != 0) {
+                synchronized (sPdfiumLock) {
+                    nativeClosePage(mNativePage);
+                }
+                mNativePage = 0;
+            }
+
+            mCloseGuard.close();
+            mCurrentPage = null;
+        }
+
+        private void throwIfClosed() {
+            if (mNativePage == 0) {
+                throw new IllegalStateException("Already closed");
+            }
+        }
+    }
+
+    private static native long nativeCreate(int fd, long size);
+    private static native void nativeClose(long documentPtr);
+    private static native int nativeGetPageCount(long documentPtr);
+    private static native boolean nativeScaleForPrinting(long documentPtr);
+    private static native void nativeRenderPage(long documentPtr, long pagePtr, long bitmapHandle,
+            int clipLeft, int clipTop, int clipRight, int clipBottom, long transformPtr,
+            int renderMode);
+    private static native long nativeOpenPageAndGetSize(long documentPtr, int pageIndex,
+            Point outSize);
+    private static native void nativeClosePage(long pagePtr);
+}
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 11b8271..bd9abec 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -21,12 +21,14 @@
 import android.os.StrictMode;
 
 /**
- * @hide This should not be made public in its present form because it
- * assumes that private and secret key bytes are available and would
- * preclude the use of hardware crypto.
+ * This class provides some constants and helper methods related to Android's Keystore service.
+ * This class was originally much larger, but its functionality was superseded by other classes.
+ * It now just contains a few remaining pieces for which the users haven't been updated yet.
+ * You may be looking for {@link java.security.KeyStore} instead.
+ *
+ * @hide
  */
 public class KeyStore {
-    private static final String TAG = "KeyStore";
 
     // ResponseCodes - see system/security/keystore/include/keystore/keystore.h
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -42,50 +44,6 @@
         return KEY_STORE;
     }
 
-    /** @hide */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public byte[] get(String key) {
-        return null;
-    }
-
-    /** @hide */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public boolean delete(String key) {
-        return false;
-    }
-
-    /**
-     * List uids of all keys that are auth bound to the current user.
-     * Only system is allowed to call this method.
-     * @hide
-     * @deprecated This function always returns null.
-     */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public int[] listUidsOfAuthBoundKeys() {
-        return null;
-    }
-
-
-    /**
-     * @hide
-     * @deprecated This function has no effect.
-     */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public boolean unlock(String password) {
-        return false;
-    }
-
-    /**
-     *
-     * @return
-     * @deprecated This function always returns true.
-     * @hide
-     */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
-    public boolean isEmpty() {
-        return true;
-    }
-
     /**
      * Add an authentication record to the keystore authorization table.
      *
@@ -105,13 +63,4 @@
     public void onDeviceOffBody() {
         AndroidKeyStoreMaintenance.onDeviceOffBody();
     }
-
-    /**
-     * Returns a {@link KeyStoreException} corresponding to the provided keystore/keymaster error
-     * code.
-     */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public static KeyStoreException getKeyStoreException(int errorCode) {
-        return new KeyStoreException(-10000, "Should not be called.");
-    }
 }
diff --git a/keystore/java/android/security/keystore/KeyInfo.java b/keystore/java/android/security/keystore/KeyInfo.java
index f50efd2..5cffe46 100644
--- a/keystore/java/android/security/keystore/KeyInfo.java
+++ b/keystore/java/android/security/keystore/KeyInfo.java
@@ -16,6 +16,7 @@
 
 package android.security.keystore;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 
@@ -81,6 +82,7 @@
     private final @KeyProperties.AuthEnum int mUserAuthenticationType;
     private final boolean mUserAuthenticationRequirementEnforcedBySecureHardware;
     private final boolean mUserAuthenticationValidWhileOnBody;
+    private final boolean mUnlockedDeviceRequired;
     private final boolean mTrustedUserPresenceRequired;
     private final boolean mInvalidatedByBiometricEnrollment;
     private final boolean mUserConfirmationRequired;
@@ -107,6 +109,7 @@
             @KeyProperties.AuthEnum int userAuthenticationType,
             boolean userAuthenticationRequirementEnforcedBySecureHardware,
             boolean userAuthenticationValidWhileOnBody,
+            boolean unlockedDeviceRequired,
             boolean trustedUserPresenceRequired,
             boolean invalidatedByBiometricEnrollment,
             boolean userConfirmationRequired,
@@ -132,6 +135,7 @@
         mUserAuthenticationRequirementEnforcedBySecureHardware =
                 userAuthenticationRequirementEnforcedBySecureHardware;
         mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
+        mUnlockedDeviceRequired = unlockedDeviceRequired;
         mTrustedUserPresenceRequired = trustedUserPresenceRequired;
         mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
         mUserConfirmationRequired = userConfirmationRequired;
@@ -275,6 +279,20 @@
     }
 
     /**
+     * Returns {@code true} if the key is authorized to be used only when the device is unlocked.
+     *
+     * <p>This authorization applies only to secret key and private key operations. Public key
+     * operations are not restricted.
+     *
+     * @see KeyGenParameterSpec.Builder#setUnlockedDeviceRequired(boolean)
+     * @see KeyProtection.Builder#setUnlockedDeviceRequired(boolean)
+     */
+    @FlaggedApi(android.security.Flags.FLAG_KEYINFO_UNLOCKED_DEVICE_REQUIRED)
+    public boolean isUnlockedDeviceRequired() {
+        return mUnlockedDeviceRequired;
+    }
+
+    /**
      * Returns {@code true} if the key is authorized to be used only for messages confirmed by the
      * user.
      *
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java
index 97592b4..2682eb6 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java
@@ -93,6 +93,7 @@
         long userAuthenticationValidityDurationSeconds = 0;
         boolean userAuthenticationRequired = true;
         boolean userAuthenticationValidWhileOnBody = false;
+        boolean unlockedDeviceRequired = false;
         boolean trustedUserPresenceRequired = false;
         boolean trustedUserConfirmationRequired = false;
         int remainingUsageCount = KeyProperties.UNRESTRICTED_USAGE_COUNT;
@@ -184,6 +185,9 @@
                                     + userAuthenticationValidityDurationSeconds + " seconds");
                         }
                         break;
+                    case KeymasterDefs.KM_TAG_UNLOCKED_DEVICE_REQUIRED:
+                        unlockedDeviceRequired = true;
+                        break;
                     case KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY:
                         userAuthenticationValidWhileOnBody =
                                 KeyStore2ParameterUtils.isSecureHardware(a.securityLevel);
@@ -257,6 +261,7 @@
                         : keymasterSwEnforcedUserAuthenticators,
                 userAuthenticationRequirementEnforcedBySecureHardware,
                 userAuthenticationValidWhileOnBody,
+                unlockedDeviceRequired,
                 trustedUserPresenceRequired,
                 invalidatedByBiometricEnrollment,
                 trustedUserConfirmationRequired,
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java b/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java
index 65955b1..e37dea4 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/common/CommonFoldingFeature.java
@@ -126,7 +126,7 @@
      * @see #FEATURE_PATTERN
      * @return {@link List} of {@link CommonFoldingFeature}.
      */
-    static List<CommonFoldingFeature> parseListFromString(@NonNull String value,
+    public static List<CommonFoldingFeature> parseListFromString(@NonNull String value,
             @State int hingeState) {
         List<CommonFoldingFeature> features = new ArrayList<>();
         String[] featureStrings =  value.split(";");
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java b/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java
index a184dff..88fd461 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/common/DeviceStateManagerFoldingFeatureProducer.java
@@ -36,6 +36,7 @@
 import com.android.internal.R;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
@@ -78,7 +79,9 @@
     private int mCurrentBaseDeviceState = INVALID_DEVICE_STATE;
 
     @NonNull
-    private final BaseDataProducer<String> mRawFoldSupplier;
+    private final RawFoldingFeatureProducer mRawFoldSupplier;
+
+    private final boolean mIsHalfOpenedSupported;
 
     private final DeviceStateCallback mDeviceStateCallback = new DeviceStateCallback() {
         @Override
@@ -101,10 +104,12 @@
     };
 
     public DeviceStateManagerFoldingFeatureProducer(@NonNull Context context,
-            @NonNull BaseDataProducer<String> rawFoldSupplier) {
+            @NonNull RawFoldingFeatureProducer rawFoldSupplier,
+            @NonNull DeviceStateManager deviceStateManager) {
         mRawFoldSupplier = rawFoldSupplier;
         String[] deviceStatePosturePairs = context.getResources()
                 .getStringArray(R.array.config_device_state_postures);
+        boolean isHalfOpenedSupported = false;
         for (String deviceStatePosturePair : deviceStatePosturePairs) {
             String[] deviceStatePostureMapping = deviceStatePosturePair.split(":");
             if (deviceStatePostureMapping.length != 2) {
@@ -128,12 +133,13 @@
                 }
                 continue;
             }
-
+            isHalfOpenedSupported = isHalfOpenedSupported
+                    || posture == CommonFoldingFeature.COMMON_STATE_HALF_OPENED;
             mDeviceStateToPostureMap.put(deviceState, posture);
         }
-
+        mIsHalfOpenedSupported = isHalfOpenedSupported;
         if (mDeviceStateToPostureMap.size() > 0) {
-            Objects.requireNonNull(context.getSystemService(DeviceStateManager.class))
+            Objects.requireNonNull(deviceStateManager)
                     .registerCallback(context.getMainExecutor(), mDeviceStateCallback);
         }
     }
@@ -188,6 +194,31 @@
     }
 
     /**
+     * Returns a {@link List} of all the {@link CommonFoldingFeature} with the state set to
+     * {@link CommonFoldingFeature#COMMON_STATE_UNKNOWN}. This method parses a {@link String} so a
+     * caller should consider caching the value or the derived value.
+     */
+    @NonNull
+    public List<CommonFoldingFeature> getFoldsWithUnknownState() {
+        Optional<String> optionalFoldingFeatureString = mRawFoldSupplier.getCurrentData();
+
+        if (optionalFoldingFeatureString.isPresent()) {
+            return CommonFoldingFeature.parseListFromString(
+                    optionalFoldingFeatureString.get(), CommonFoldingFeature.COMMON_STATE_UNKNOWN
+            );
+        }
+        return Collections.emptyList();
+    }
+
+
+    /**
+     * Returns {@code true} if the device supports half-opened mode, {@code false} otherwise.
+     */
+    public boolean isHalfOpenedSupported() {
+        return mIsHalfOpenedSupported;
+    }
+
+    /**
      * Adds the data to the storeFeaturesConsumer when the data is ready.
      * @param storeFeaturesConsumer a consumer to collect the data when it is first available.
      */
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
index 29cf054..6714263 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
@@ -20,6 +20,7 @@
 import android.app.ActivityThread;
 import android.app.Application;
 import android.content.Context;
+import android.hardware.devicestate.DeviceStateManager;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
@@ -64,6 +65,11 @@
     }
 
     @NonNull
+    private DeviceStateManager getDeviceStateManager() {
+        return Objects.requireNonNull(getApplication().getSystemService(DeviceStateManager.class));
+    }
+
+    @NonNull
     private DeviceStateManagerFoldingFeatureProducer getFoldingFeatureProducer() {
         if (mFoldingFeatureProducer == null) {
             synchronized (mLock) {
@@ -73,7 +79,7 @@
                             new RawFoldingFeatureProducer(context);
                     mFoldingFeatureProducer =
                             new DeviceStateManagerFoldingFeatureProducer(context,
-                                    foldingFeatureProducer);
+                                    foldingFeatureProducer, getDeviceStateManager());
                 }
             }
         }
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index b2e5b75..ae3a854 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -72,6 +72,7 @@
 import android.util.Size;
 import android.util.SparseArray;
 import android.view.WindowMetrics;
+import android.window.ActivityWindowInfo;
 import android.window.TaskFragmentAnimationParams;
 import android.window.TaskFragmentInfo;
 import android.window.TaskFragmentOperation;
@@ -2864,11 +2865,27 @@
      */
     @Override
     public boolean isActivityEmbedded(@NonNull Activity activity) {
+        Objects.requireNonNull(activity);
         synchronized (mLock) {
+            if (Flags.activityWindowInfoFlag()) {
+                final ActivityWindowInfo activityWindowInfo = getActivityWindowInfo(activity);
+                return activityWindowInfo != null && activityWindowInfo.isEmbedded();
+            }
             return mPresenter.isActivityEmbedded(activity.getActivityToken());
         }
     }
 
+    @Nullable
+    private static ActivityWindowInfo getActivityWindowInfo(@NonNull Activity activity) {
+        if (activity.isFinishing()) {
+            return null;
+        }
+        final ActivityThread.ActivityClientRecord record =
+                ActivityThread.currentActivityThread()
+                        .getActivityClient(activity.getActivityToken());
+        return record != null ? record.getActivityWindowInfo() : null;
+    }
+
     /**
      * If the two rules have the same presentation, and the calculated {@link SplitAttributes}
      * matches the {@link SplitAttributes} of {@link SplitContainer}, we can reuse the same
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/DisplayFoldFeatureUtil.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/DisplayFoldFeatureUtil.java
new file mode 100644
index 0000000..a0f481a
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/DisplayFoldFeatureUtil.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2024 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 androidx.window.extensions.layout;
+
+import androidx.window.common.CommonFoldingFeature;
+import androidx.window.common.DeviceStateManagerFoldingFeatureProducer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Util functions for working with {@link androidx.window.extensions.layout.DisplayFoldFeature}.
+ */
+public class DisplayFoldFeatureUtil {
+
+    private DisplayFoldFeatureUtil() {}
+
+    private static DisplayFoldFeature create(CommonFoldingFeature foldingFeature,
+            boolean isHalfOpenedSupported) {
+        final int foldType;
+        if (foldingFeature.getType() == CommonFoldingFeature.COMMON_TYPE_HINGE) {
+            foldType = DisplayFoldFeature.TYPE_HINGE;
+        } else {
+            foldType = DisplayFoldFeature.TYPE_SCREEN_FOLD_IN;
+        }
+        DisplayFoldFeature.Builder featureBuilder = new DisplayFoldFeature.Builder(foldType);
+
+        if (isHalfOpenedSupported) {
+            featureBuilder.addProperty(DisplayFoldFeature.FOLD_PROPERTY_SUPPORTS_HALF_OPENED);
+        }
+        return featureBuilder.build();
+    }
+
+    /**
+     * Returns the list of supported {@link DisplayFeature} calculated from the
+     * {@link DeviceStateManagerFoldingFeatureProducer}.
+     */
+    public static List<DisplayFoldFeature> extractDisplayFoldFeatures(
+            DeviceStateManagerFoldingFeatureProducer producer) {
+        List<DisplayFoldFeature> foldFeatures = new ArrayList<>();
+        List<CommonFoldingFeature> folds = producer.getFoldsWithUnknownState();
+
+        final boolean isHalfOpenedSupported = producer.isHalfOpenedSupported();
+        for (CommonFoldingFeature fold : folds) {
+            foldFeatures.add(DisplayFoldFeatureUtil.create(fold, isHalfOpenedSupported));
+        }
+        return foldFeatures;
+    }
+}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
index 6e704f3..4fd11c4 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
@@ -45,7 +45,6 @@
 import androidx.window.common.DeviceStateManagerFoldingFeatureProducer;
 import androidx.window.common.EmptyLifecycleCallbacksAdapter;
 import androidx.window.extensions.core.util.function.Consumer;
-import androidx.window.util.DataProducer;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -56,10 +55,6 @@
 /**
  * Reference implementation of androidx.window.extensions.layout OEM interface for use with
  * WindowManager Jetpack.
- *
- * NOTE: This version is a work in progress and under active development. It MUST NOT be used in
- * production builds since the interface can still change before reaching stable version.
- * Please refer to {@link androidx.window.sidecar.SampleSidecarImpl} instead.
  */
 public class WindowLayoutComponentImpl implements WindowLayoutComponent {
     private static final String TAG = WindowLayoutComponentImpl.class.getSimpleName();
@@ -71,7 +66,7 @@
             new ArrayMap<>();
 
     @GuardedBy("mLock")
-    private final DataProducer<List<CommonFoldingFeature>> mFoldingFeatureProducer;
+    private final DeviceStateManagerFoldingFeatureProducer mFoldingFeatureProducer;
 
     @GuardedBy("mLock")
     private final List<CommonFoldingFeature> mLastReportedFoldingFeatures = new ArrayList<>();
@@ -87,12 +82,17 @@
     private final RawConfigurationChangedListener mRawConfigurationChangedListener =
             new RawConfigurationChangedListener();
 
+    private final SupportedWindowFeatures mSupportedWindowFeatures;
+
     public WindowLayoutComponentImpl(@NonNull Context context,
             @NonNull DeviceStateManagerFoldingFeatureProducer foldingFeatureProducer) {
         ((Application) context.getApplicationContext())
                 .registerActivityLifecycleCallbacks(new NotifyOnConfigurationChanged());
         mFoldingFeatureProducer = foldingFeatureProducer;
         mFoldingFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged);
+        final List<DisplayFoldFeature> displayFoldFeatures =
+                DisplayFoldFeatureUtil.extractDisplayFoldFeatures(mFoldingFeatureProducer);
+        mSupportedWindowFeatures = new SupportedWindowFeatures.Builder(displayFoldFeatures).build();
     }
 
     /**
@@ -283,6 +283,15 @@
         }
     }
 
+    /**
+     * Returns the {@link SupportedWindowFeatures} for the device. This list does not change over
+     * time.
+     */
+    @NonNull
+    public SupportedWindowFeatures getSupportedWindowFeatures() {
+        return mSupportedWindowFeatures;
+    }
+
     /** @see #getWindowLayoutInfo(Context, List) */
     private WindowLayoutInfo getWindowLayoutInfo(int displayId,
             @NonNull WindowConfiguration windowConfiguration,
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java
index a836e05..56c3bce 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java
@@ -17,6 +17,7 @@
 package androidx.window.sidecar;
 
 import static android.view.Display.DEFAULT_DISPLAY;
+
 import static androidx.window.util.ExtensionHelper.rotateRectToDisplayRotation;
 import static androidx.window.util.ExtensionHelper.transformToWindowSpaceRect;
 
@@ -25,6 +26,7 @@
 import android.app.Application;
 import android.content.Context;
 import android.graphics.Rect;
+import android.hardware.devicestate.DeviceStateManager;
 import android.os.Bundle;
 import android.os.IBinder;
 
@@ -49,10 +51,11 @@
     SampleSidecarImpl(Context context) {
         ((Application) context.getApplicationContext())
                 .registerActivityLifecycleCallbacks(new NotifyOnConfigurationChanged());
-        BaseDataProducer<String> settingsFeatureProducer = new RawFoldingFeatureProducer(context);
+        RawFoldingFeatureProducer settingsFeatureProducer = new RawFoldingFeatureProducer(context);
         BaseDataProducer<List<CommonFoldingFeature>> foldingFeatureProducer =
                 new DeviceStateManagerFoldingFeatureProducer(context,
-                        settingsFeatureProducer);
+                        settingsFeatureProducer,
+                        context.getSystemService(DeviceStateManager.class));
 
         foldingFeatureProducer.addDataChangedCallback(this::onDisplayFeaturesChanged);
     }
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index d66c925..0ecf1f8 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -82,16 +82,18 @@
 genrule {
     name: "wm_shell_protolog_src",
     srcs: [
+        ":protolog-impl",
         ":wm_shell_protolog-groups",
         ":wm_shell-sources",
     ],
     tools: ["protologtool"],
     cmd: "$(location protologtool) transform-protolog-calls " +
         "--protolog-class com.android.internal.protolog.common.ProtoLog " +
-        "--protolog-impl-class com.android.wm.shell.protolog.ShellProtoLogImpl " +
-        "--protolog-cache-class com.android.wm.shell.protolog.ShellProtoLogCache " +
         "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " +
         "--loggroups-jar $(location :wm_shell_protolog-groups) " +
+        "--viewer-config-file-path /system_ext/etc/wmshell.protolog.pb " +
+        "--legacy-viewer-config-file-path /system_ext/etc/wmshell.protolog.json.gz " +
+        "--legacy-output-file-path /data/misc/wmtrace/shell_log.winscope " +
         "--output-srcjar $(out) " +
         "$(locations :wm_shell-sources)",
     out: ["wm_shell_protolog.srcjar"],
@@ -108,12 +110,30 @@
         "--protolog-class com.android.internal.protolog.common.ProtoLog " +
         "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " +
         "--loggroups-jar $(location :wm_shell_protolog-groups) " +
-        "--viewer-conf $(out) " +
+        "--viewer-config-type json " +
+        "--viewer-config $(out) " +
         "$(locations :wm_shell-sources)",
     out: ["wm_shell_protolog.json"],
 }
 
 genrule {
+    name: "gen-wmshell.protolog.pb",
+    srcs: [
+        ":wm_shell_protolog-groups",
+        ":wm_shell-sources",
+    ],
+    tools: ["protologtool"],
+    cmd: "$(location protologtool) generate-viewer-config " +
+        "--protolog-class com.android.internal.protolog.common.ProtoLog " +
+        "--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " +
+        "--loggroups-jar $(location :wm_shell_protolog-groups) " +
+        "--viewer-config-type proto " +
+        "--viewer-config $(out) " +
+        "$(locations :wm_shell-sources)",
+    out: ["wmshell.protolog.pb"],
+}
+
+genrule {
     name: "protolog.json.gz",
     srcs: [":generate-wm_shell_protolog.json"],
     out: ["wmshell.protolog.json.gz"],
@@ -127,6 +147,13 @@
     filename_from_src: true,
 }
 
+prebuilt_etc {
+    name: "wmshell.protolog.pb",
+    system_ext_specific: true,
+    src: ":gen-wmshell.protolog.pb",
+    filename_from_src: true,
+}
+
 // End ProtoLog
 
 java_library {
diff --git a/libs/WindowManager/Shell/res/color/desktop_mode_caption_button_color_selector_dark.xml b/libs/WindowManager/Shell/res/color/desktop_mode_caption_button_color_selector_dark.xml
new file mode 100644
index 0000000..52a5967
--- /dev/null
+++ b/libs/WindowManager/Shell/res/color/desktop_mode_caption_button_color_selector_dark.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 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.
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_hovered="true"
+        android:color="@color/desktop_mode_caption_button_on_hover_dark"/>
+    <item android:color="@color/desktop_mode_caption_button"/>
+</selector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/color/desktop_mode_caption_button_color_selector_light.xml b/libs/WindowManager/Shell/res/color/desktop_mode_caption_button_color_selector_light.xml
new file mode 100644
index 0000000..6d8a51c
--- /dev/null
+++ b/libs/WindowManager/Shell/res/color/desktop_mode_caption_button_color_selector_light.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 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.
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_hovered="true"
+        android:color="@color/desktop_mode_caption_button_on_hover_light"/>
+    <item android:color="@color/desktop_mode_caption_button"/>
+</selector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/circular_progress.xml b/libs/WindowManager/Shell/res/drawable/circular_progress.xml
new file mode 100644
index 0000000..9482645
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/circular_progress.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@android:id/progress">
+        <rotate
+            android:pivotX="50%"
+            android:pivotY="50%"
+            android:fromDegrees="275"
+            android:toDegrees="275">
+            <shape
+                android:shape="ring"
+                android:thickness="3dp"
+                android:innerRadius="17dp"
+                android:useLevel="true">
+            </shape>
+        </rotate>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/rounded_button.xml b/libs/WindowManager/Shell/res/drawable/rounded_button.xml
new file mode 100644
index 0000000..17a0bab
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/rounded_button.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 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.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <corners  android:radius="20dp" />
+</shape>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml
index e4f793c..d1b1af3 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml
@@ -74,17 +74,11 @@
         android:layout_height="40dp"
         android:layout_weight="1"/>
 
-    <ImageButton
-        android:id="@+id/maximize_window"
-        android:layout_width="40dp"
-        android:layout_height="40dp"
-        android:padding="9dp"
-        android:layout_marginEnd="8dp"
-        android:contentDescription="@string/maximize_button_text"
-        android:src="@drawable/decor_desktop_mode_maximize_button_dark"
-        android:scaleType="fitCenter"
-        android:gravity="end"
-        android:background="@null"/>
+    <com.android.wm.shell.windowdecor.MaximizeButtonView
+        android:id="@+id/maximize_button_view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="end"/>
 
     <ImageButton
         android:id="@+id/close_window"
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml
index 0db72f7..dbfd6e5 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_maximize_menu.xml
@@ -15,6 +15,7 @@
   ~ limitations under the License.
   -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/maximize_menu"
     style="?android:attr/buttonBarStyle"
     android:layout_width="@dimen/desktop_mode_maximize_menu_width"
     android:layout_height="@dimen/desktop_mode_maximize_menu_height"
diff --git a/libs/WindowManager/Shell/res/layout/maximize_menu_button.xml b/libs/WindowManager/Shell/res/layout/maximize_menu_button.xml
new file mode 100644
index 0000000..bb6efce
--- /dev/null
+++ b/libs/WindowManager/Shell/res/layout/maximize_menu_button.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 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.
+  -->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+    <ProgressBar
+        android:id="@+id/progress_bar"
+        style="?android:attr/progressBarStyleHorizontal"
+        android:progressDrawable="@drawable/circular_progress"
+        android:layout_width="40dp"
+        android:layout_height="40dp"
+        android:indeterminate="false"
+        android:visibility="invisible"/>
+
+    <ImageButton
+        android:id="@+id/maximize_window"
+        android:layout_width="40dp"
+        android:layout_height="40dp"
+        android:padding="9dp"
+        android:contentDescription="@string/maximize_button_text"
+        android:src="@drawable/decor_desktop_mode_maximize_button_dark"
+        android:scaleType="fitCenter"
+        android:background="@drawable/rounded_button"/>
+</merge>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml
index fae71ef..758dbfd 100644
--- a/libs/WindowManager/Shell/res/values/colors.xml
+++ b/libs/WindowManager/Shell/res/values/colors.xml
@@ -66,4 +66,9 @@
     <color name="desktop_mode_maximize_menu_button_outline">#797869</color>
     <color name="desktop_mode_maximize_menu_button_outline_on_hover">#606219</color>
     <color name="desktop_mode_maximize_menu_button_on_hover">#E7E790</color>
+    <color name="desktop_mode_maximize_menu_progress_light">#33000000</color>
+    <color name="desktop_mode_maximize_menu_progress_dark">#33FFFFFF</color>
+    <color name="desktop_mode_caption_button_on_hover_light">#11000000</color>
+    <color name="desktop_mode_caption_button_on_hover_dark">#11FFFFFF</color>
+    <color name="desktop_mode_caption_button">#00000000</color>
 </resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java
index 88525aa..93893e3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ProtoLogController.java
@@ -16,7 +16,10 @@
 
 package com.android.wm.shell;
 
-import com.android.wm.shell.protolog.ShellProtoLogImpl;
+import com.android.internal.protolog.LegacyProtoLogImpl;
+import com.android.internal.protolog.common.ILogger;
+import com.android.internal.protolog.common.IProtoLog;
+import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellInit;
 
@@ -24,19 +27,19 @@
 import java.util.Arrays;
 
 /**
- * Controls the {@link ShellProtoLogImpl} in WMShell via adb shell commands.
+ * Controls the {@link ProtoLog} in WMShell via adb shell commands.
  *
  * Use with {@code adb shell dumpsys activity service SystemUIService WMShell protolog ...}.
  */
 public class ProtoLogController implements ShellCommandHandler.ShellCommandActionHandler {
     private final ShellCommandHandler mShellCommandHandler;
-    private final ShellProtoLogImpl mShellProtoLog;
+    private final IProtoLog mShellProtoLog;
 
     public ProtoLogController(ShellInit shellInit,
             ShellCommandHandler shellCommandHandler) {
         shellInit.addInitCallback(this::onInit, this);
         mShellCommandHandler = shellCommandHandler;
-        mShellProtoLog = ShellProtoLogImpl.getSingleInstance();
+        mShellProtoLog = ProtoLog.getSingleInstance();
     }
 
     void onInit() {
@@ -45,22 +48,35 @@
 
     @Override
     public boolean onShellCommand(String[] args, PrintWriter pw) {
+        final ILogger logger = pw::println;
         switch (args[0]) {
             case "status": {
-                pw.println(mShellProtoLog.getStatus());
+                if (android.tracing.Flags.perfettoProtolog()) {
+                    pw.println("(Deprecated) legacy command. Use Perfetto commands instead.");
+                    return false;
+                }
+                ((LegacyProtoLogImpl) mShellProtoLog).getStatus();
                 return true;
             }
             case "start": {
-                mShellProtoLog.startProtoLog(pw);
+                if (android.tracing.Flags.perfettoProtolog()) {
+                    pw.println("(Deprecated) legacy command. Use Perfetto commands instead.");
+                    return false;
+                }
+                ((LegacyProtoLogImpl) mShellProtoLog).startProtoLog(pw);
                 return true;
             }
             case "stop": {
-                mShellProtoLog.stopProtoLog(pw, true /* writeToFile */);
+                if (android.tracing.Flags.perfettoProtolog()) {
+                    pw.println("(Deprecated) legacy command. Use Perfetto commands instead.");
+                    return false;
+                }
+                ((LegacyProtoLogImpl) mShellProtoLog).stopProtoLog(pw, true);
                 return true;
             }
             case "enable-text": {
                 String[] groups = Arrays.copyOfRange(args, 1, args.length);
-                int result = mShellProtoLog.startTextLogging(groups, pw);
+                int result = mShellProtoLog.startLoggingToLogcat(groups, logger);
                 if (result == 0) {
                     pw.println("Starting logging on groups: " + Arrays.toString(groups));
                     return true;
@@ -69,7 +85,7 @@
             }
             case "disable-text": {
                 String[] groups = Arrays.copyOfRange(args, 1, args.length);
-                int result = mShellProtoLog.stopTextLogging(groups, pw);
+                int result = mShellProtoLog.stopLoggingToLogcat(groups, logger);
                 if (result == 0) {
                     pw.println("Stopping logging on groups: " + Arrays.toString(groups));
                     return true;
@@ -78,19 +94,23 @@
             }
             case "enable": {
                 String[] groups = Arrays.copyOfRange(args, 1, args.length);
-                return mShellProtoLog.startTextLogging(groups, pw) == 0;
+                return mShellProtoLog.startLoggingToLogcat(groups, logger) == 0;
             }
             case "disable": {
                 String[] groups = Arrays.copyOfRange(args, 1, args.length);
-                return mShellProtoLog.stopTextLogging(groups, pw) == 0;
+                return mShellProtoLog.stopLoggingToLogcat(groups, logger) == 0;
             }
             case "save-for-bugreport": {
+                if (android.tracing.Flags.perfettoProtolog()) {
+                    pw.println("(Deprecated) legacy command");
+                    return false;
+                }
                 if (!mShellProtoLog.isProtoEnabled()) {
                     pw.println("Logging to proto is not enabled for WMShell.");
                     return false;
                 }
-                mShellProtoLog.stopProtoLog(pw, true /* writeToFile */);
-                mShellProtoLog.startProtoLog(pw);
+                ((LegacyProtoLogImpl) mShellProtoLog).stopProtoLog(pw, true /* writeToFile */);
+                ((LegacyProtoLogImpl) mShellProtoLog).startProtoLog(pw);
                 return true;
             }
             default: {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index e0f0556..15350fb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -122,6 +122,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
@@ -247,6 +248,9 @@
     /** Saved font scale, used to detect font size changes in {@link #onConfigurationChanged}. */
     private float mFontScale = 0;
 
+    /** Saved locale, used to detect local changes in {@link #onConfigurationChanged}. */
+    private Locale mLocale = null;
+
     /** Saved direction, used to detect layout direction changes @link #onConfigChanged}. */
     private int mLayoutDirection = View.LAYOUT_DIRECTION_UNDEFINED;
 
@@ -683,6 +687,17 @@
         mDataRepository.removeBubblesForUser(removedUserId, parentUserId);
     }
 
+    /** Called when sensitive notification state has changed */
+    public void onSensitiveNotificationProtectionStateChanged(
+            boolean sensitiveNotificationProtectionActive) {
+        if (mStackView != null) {
+            mStackView.onSensitiveNotificationProtectionStateChanged(
+                    sensitiveNotificationProtectionActive);
+            ProtoLog.d(WM_SHELL_BUBBLES, "onSensitiveNotificationProtectionStateChanged=%b",
+                    sensitiveNotificationProtectionActive);
+        }
+    }
+
     /** Whether bubbles are showing in the bubble bar. */
     public boolean isShowingAsBubbleBar() {
         return canShowAsBubbleBar() && mBubbleStateListener != null;
@@ -1057,6 +1072,11 @@
                 mLayoutDirection = newConfig.getLayoutDirection();
                 mStackView.onLayoutDirectionChanged(mLayoutDirection);
             }
+            Locale newLocale = newConfig.locale;
+            if (newLocale != null && !newLocale.equals(mLocale)) {
+                mLocale = newLocale;
+                mStackView.updateLocale();
+            }
         }
     }
 
@@ -2583,6 +2603,14 @@
             mMainExecutor.execute(
                     () -> BubbleController.this.onNotificationPanelExpandedChanged(expanded));
         }
+
+        @Override
+        public void onSensitiveNotificationProtectionStateChanged(
+                boolean sensitiveNotificationProtectionActive) {
+            mMainExecutor.execute(
+                    () -> BubbleController.this.onSensitiveNotificationProtectionStateChanged(
+                            sensitiveNotificationProtectionActive));
+        }
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
index 123693d..74f087b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java
@@ -517,6 +517,15 @@
         }
     }
 
+    void updateLocale() {
+        if (mManageButton != null) {
+            mManageButton.setText(mContext.getString(R.string.manage_bubbles_text));
+        }
+        if (mOverflowView != null) {
+            mOverflowView.updateLocale();
+        }
+    }
+
     void applyThemeAttrs() {
         final TypedArray ta = mContext.obtainStyledAttributes(new int[]{
                 android.R.attr.dialogCornerRadius,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
index b06de4f..633b01b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleOverflowContainerView.java
@@ -242,6 +242,11 @@
         mEmptyStateSubtitle.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize);
     }
 
+    public void updateLocale() {
+        mEmptyStateTitle.setText(mContext.getString(R.string.bubble_overflow_empty_title));
+        mEmptyStateSubtitle.setText(mContext.getString(R.string.bubble_overflow_empty_subtitle));
+    }
+
     private final BubbleData.Listener mDataListener = new BubbleData.Listener() {
 
         @Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index b23fd52..8fd6ffe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -291,6 +291,11 @@
      */
     private boolean mRemovingLastBubbleWhileExpanded = false;
 
+    /**
+     * Whether sensitive notification protection should disable flyout
+     */
+    private boolean mSensitiveNotificationProtectionActive = false;
+
     /** Animator for animating the expanded view's alpha (including the TaskView inside it). */
     private final ValueAnimator mExpandedViewAlphaAnimator = ValueAnimator.ofFloat(0f, 1f);
 
@@ -1447,6 +1452,12 @@
         }
     }
 
+    void updateLocale() {
+        if (mBubbleOverflow != null && mBubbleOverflow.getExpandedView() != null) {
+            mBubbleOverflow.getExpandedView().updateLocale();
+        }
+    }
+
     private void updateOverflow() {
         mBubbleOverflow.update();
         mBubbleContainer.reorderView(mBubbleOverflow.getIconView(),
@@ -2199,6 +2210,11 @@
         }
     }
 
+    void onSensitiveNotificationProtectionStateChanged(
+            boolean sensitiveNotificationProtectionActive) {
+        mSensitiveNotificationProtectionActive = sensitiveNotificationProtectionActive;
+    }
+
     /**
      * Asks the BubbleController to hide the IME from anywhere, whether it's focused on Bubbles or
      * not.
@@ -2842,6 +2858,7 @@
                 || isExpanded()
                 || mIsExpansionAnimating
                 || mIsGestureInProgress
+                || mSensitiveNotificationProtectionActive
                 || mBubbleToExpandAfterFlyoutCollapse != null
                 || bubbleView == null) {
             if (bubbleView != null && mFlyout.getVisibility() != VISIBLE) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
index 28af0ca..26077cf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
@@ -286,6 +286,16 @@
     void onUserRemoved(int removedUserId);
 
     /**
+     * Called when the Sensitive notification protection state has changed, such as when media
+     * projection starts and stops.
+     *
+     * @param sensitiveNotificationProtectionActive {@code true} if notifications should be
+     *     protected
+     */
+    void onSensitiveNotificationProtectionStateChanged(
+            boolean sensitiveNotificationProtectionActive);
+
+    /**
      * A listener to be notified of bubble state changes, used by launcher to render bubbles in
      * its process.
      */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/OWNERS
index 8271014..08c7031 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/OWNERS
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/OWNERS
@@ -1,2 +1,6 @@
 # WM shell sub-module bubble owner
 madym@google.com
+atsjenk@google.com
+liranb@google.com
+sukeshram@google.com
+mpodolian@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java
index b57e2d2..b87c2f6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipBoundsState.java
@@ -228,6 +228,14 @@
         mExpandedMovementBounds.set(bounds);
     }
 
+    /** Updates the min and max sizes based on the size spec and aspect ratio. */
+    public void updateMinMaxSize(float aspectRatio) {
+        final Size minSize = mSizeSpecSource.getMinSize(aspectRatio);
+        mMinSize.set(minSize.getWidth(), minSize.getHeight());
+        final Size maxSize = mSizeSpecSource.getMaxSize(aspectRatio);
+        mMaxSize.set(maxSize.getWidth(), maxSize.getHeight());
+    }
+
     /** Sets the max possible size for resize. */
     public void setMaxSize(int width, int height) {
         mMaxSize.set(width, height);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt
new file mode 100644
index 0000000..95d4714
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeEventLogger.kt
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.desktopmode
+
+import com.android.internal.util.FrameworkStatsLog
+import com.android.wm.shell.protolog.ShellProtoLogGroup
+import com.android.wm.shell.util.KtProtoLog
+
+/**
+ * Event logger for logging desktop mode session events
+ */
+class DesktopModeEventLogger {
+    /**
+     * Logs the enter of desktop mode having session id [sessionId] and the reason [enterReason] for
+     * entering desktop mode
+     */
+    fun logSessionEnter(sessionId: Int, enterReason: EnterReason) {
+        KtProtoLog.v(
+            ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
+            "DesktopModeLogger: Logging session enter, session: %s reason: %s",
+            sessionId, enterReason.name
+        )
+        FrameworkStatsLog.write(DESKTOP_MODE_ATOM_ID,
+            /* event */ FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EVENT__ENTER,
+            /* enterReason */ enterReason.reason,
+            /* exitReason */ 0,
+            /* session_id */ sessionId)
+    }
+
+    /**
+     * Logs the exit of desktop mode having session id [sessionId] and the reason [exitReason] for
+     * exiting desktop mode
+     */
+    fun logSessionExit(sessionId: Int, exitReason: ExitReason) {
+        KtProtoLog.v(
+            ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
+            "DesktopModeLogger: Logging session exit, session: %s reason: %s",
+            sessionId, exitReason.name
+        )
+        FrameworkStatsLog.write(DESKTOP_MODE_ATOM_ID,
+            /* event */ FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EVENT__EXIT,
+            /* enterReason */ 0,
+            /* exitReason */ exitReason.reason,
+            /* session_id */ sessionId)
+    }
+
+    /**
+     * Logs that the task with update [taskUpdate] was added in the desktop mode session having
+     * session id [sessionId]
+     */
+    fun logTaskAdded(sessionId: Int, taskUpdate: TaskUpdate) {
+        KtProtoLog.v(
+            ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
+            "DesktopModeLogger: Logging task added, session: %s taskId: %s",
+            sessionId, taskUpdate.instanceId
+        )
+        FrameworkStatsLog.write(DESKTOP_MODE_TASK_UPDATE_ATOM_ID,
+            /* task_event */
+            FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_ADDED,
+            /* instance_id */
+            taskUpdate.instanceId,
+            /* uid */
+            taskUpdate.uid,
+            /* task_height */
+            taskUpdate.taskHeight,
+            /* task_width */
+            taskUpdate.taskWidth,
+            /* task_x */
+            taskUpdate.taskX,
+            /* task_y */
+            taskUpdate.taskY,
+            /* session_id */
+            sessionId)
+    }
+
+    /**
+     * Logs that the task with update [taskUpdate] was removed in the desktop mode session having
+     * session id [sessionId]
+     */
+    fun logTaskRemoved(sessionId: Int, taskUpdate: TaskUpdate) {
+        KtProtoLog.v(
+            ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
+            "DesktopModeLogger: Logging task remove, session: %s taskId: %s",
+            sessionId, taskUpdate.instanceId
+        )
+        FrameworkStatsLog.write(DESKTOP_MODE_TASK_UPDATE_ATOM_ID,
+            /* task_event */
+            FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_REMOVED,
+            /* instance_id */
+            taskUpdate.instanceId,
+            /* uid */
+            taskUpdate.uid,
+            /* task_height */
+            taskUpdate.taskHeight,
+            /* task_width */
+            taskUpdate.taskWidth,
+            /* task_x */
+            taskUpdate.taskX,
+            /* task_y */
+            taskUpdate.taskY,
+            /* session_id */
+            sessionId)
+    }
+
+    /**
+     * Logs that the task with update [taskUpdate] had it's info changed in the desktop mode session
+     * having session id [sessionId]
+     */
+    fun logTaskInfoChanged(sessionId: Int, taskUpdate: TaskUpdate) {
+        KtProtoLog.v(
+            ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
+            "DesktopModeLogger: Logging task info changed, session: %s taskId: %s",
+            sessionId, taskUpdate.instanceId
+        )
+        FrameworkStatsLog.write(DESKTOP_MODE_TASK_UPDATE_ATOM_ID,
+            /* task_event */
+            FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_INFO_CHANGED,
+            /* instance_id */
+            taskUpdate.instanceId,
+            /* uid */
+            taskUpdate.uid,
+            /* task_height */
+            taskUpdate.taskHeight,
+            /* task_width */
+            taskUpdate.taskWidth,
+            /* task_x */
+            taskUpdate.taskX,
+            /* task_y */
+            taskUpdate.taskY,
+            /* session_id */
+            sessionId)
+    }
+
+    companion object {
+        data class TaskUpdate(
+            val instanceId: Int,
+            val uid: Int,
+            val taskHeight: Int = Int.MIN_VALUE,
+            val taskWidth: Int = Int.MIN_VALUE,
+            val taskX: Int = Int.MIN_VALUE,
+            val taskY: Int = Int.MIN_VALUE,
+        )
+
+        /**
+         * Enum EnterReason mapped to the EnterReason definition in
+         * stats/atoms/desktopmode/desktopmode_extensions_atoms.proto
+         */
+        enum class EnterReason(val reason: Int) {
+            UNKNOWN_ENTER(
+                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__UNKNOWN_ENTER
+            ),
+            OVERVIEW(
+                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__OVERVIEW
+            ),
+            APP_HANDLE_DRAG(
+                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__APP_HANDLE_DRAG
+            ),
+            APP_HANDLE_MENU_BUTTON(
+                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__APP_HANDLE_MENU_BUTTON
+            ),
+            APP_FREEFORM_INTENT(
+                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__APP_FREEFORM_INTENT
+            ),
+            KEYBOARD_SHORTCUT_ENTER(
+                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__KEYBOARD_SHORTCUT_ENTER
+            ),
+            SCREEN_ON(
+                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__SCREEN_ON
+            );
+        }
+
+        /**
+         * Enum ExitReason mapped to the ExitReason definition in
+         * stats/atoms/desktopmode/desktopmode_extensions_atoms.proto
+         */
+        enum class ExitReason(val reason: Int) {
+            UNKNOWN_EXIT(
+                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__UNKNOWN_EXIT
+            ),
+            DRAG_TO_EXIT(
+                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__DRAG_TO_EXIT
+            ),
+            APP_HANDLE_MENU_BUTTON_EXIT(
+                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__APP_HANDLE_MENU_BUTTON_EXIT
+            ),
+            KEYBOARD_SHORTCUT_EXIT(
+                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__KEYBOARD_SHORTCUT_EXIT
+            ),
+            RETURN_HOME_OR_OVERVIEW(
+                FrameworkStatsLog.SPLITSCREEN_UICHANGED__EXIT_REASON__RETURN_HOME
+            ),
+            TASK_FINISHED(
+                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__TASK_FINISHED
+            ),
+            SCREEN_OFF(
+                FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__SCREEN_OFF
+            )
+        }
+
+        private const val DESKTOP_MODE_ATOM_ID = FrameworkStatsLog.DESKTOP_MODE_UI_CHANGED
+        private const val DESKTOP_MODE_TASK_UPDATE_ATOM_ID =
+            FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
index 4053418..7091c4b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
@@ -22,8 +22,6 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 
-import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FINAL_FREEFORM_SCALE;
-
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.RectEvaluator;
@@ -389,7 +387,8 @@
                             layout.width() - padding,
                             layout.height() - padding);
                 case TO_DESKTOP_INDICATOR:
-                    final float adjustmentPercentage = 1f - FINAL_FREEFORM_SCALE;
+                    final float adjustmentPercentage = 1f
+                            - DesktopTasksController.DESKTOP_MODE_INITIAL_BOUNDS_SCALE;
                     return new Rect((int) (adjustmentPercentage * layout.width() / 2),
                             (int) (adjustmentPercentage * layout.height() / 2),
                             (int) (layout.width() - (adjustmentPercentage * layout.width() / 2)),
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 98f9988..dcffb2d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.desktopmode
 
-import android.app.ActivityManager
 import android.app.ActivityManager.RunningTaskInfo
 import android.app.ActivityOptions
 import android.app.PendingIntent
@@ -35,7 +34,6 @@
 import android.graphics.Region
 import android.os.IBinder
 import android.os.SystemProperties
-import android.util.DisplayMetrics.DENSITY_DEFAULT
 import android.view.Display.DEFAULT_DISPLAY
 import android.view.SurfaceControl
 import android.view.WindowManager.TRANSIT_CHANGE
@@ -51,6 +49,7 @@
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer
 import com.android.wm.shell.ShellTaskOrganizer
 import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.common.DisplayLayout
 import com.android.wm.shell.common.ExecutorUtils
 import com.android.wm.shell.common.ExternalInterfaceBinder
 import com.android.wm.shell.common.LaunchAdjacentController
@@ -68,7 +67,6 @@
 import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler.DragToDesktopStateListener
 import com.android.wm.shell.draganddrop.DragAndDropController
 import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
-import com.android.wm.shell.recents.RecentTasksController
 import com.android.wm.shell.recents.RecentsTransitionHandler
 import com.android.wm.shell.recents.RecentsTransitionStateListener
 import com.android.wm.shell.splitscreen.SplitScreenController
@@ -85,7 +83,6 @@
 import java.io.PrintWriter
 import java.util.concurrent.Executor
 import java.util.function.Consumer
-import java.util.function.Function
 
 /** Handles moving tasks in and out of desktop */
 class DesktopTasksController(
@@ -551,11 +548,7 @@
         if (taskInfo.configuration.windowConfiguration.bounds == stableBounds) {
             // The desktop task is currently occupying the whole stable bounds, toggle to the
             // default bounds.
-            getDefaultDesktopTaskBounds(
-                density = taskInfo.configuration.densityDpi.toFloat() / DENSITY_DEFAULT,
-                stableBounds = stableBounds,
-                outBounds = destinationBounds
-            )
+            getDefaultDesktopTaskBounds(displayLayout, destinationBounds)
         } else {
             // Toggle to the stable bounds.
             destinationBounds.set(stableBounds)
@@ -610,15 +603,17 @@
         }
     }
 
-    private fun getDefaultDesktopTaskBounds(density: Float, stableBounds: Rect, outBounds: Rect) {
-        val width = (DESKTOP_MODE_DEFAULT_WIDTH_DP * density + 0.5f).toInt()
-        val height = (DESKTOP_MODE_DEFAULT_HEIGHT_DP * density + 0.5f).toInt()
-        outBounds.set(0, 0, width, height)
-        // Center the task in stable bounds
+    private fun getDefaultDesktopTaskBounds(displayLayout: DisplayLayout, outBounds: Rect) {
+        // TODO(b/319819547): Account for app constraints so apps do not become letterboxed
+        val screenBounds = Rect(0, 0, displayLayout.width(), displayLayout.height())
+        // Update width and height with default desktop mode values
+        val desiredWidth = screenBounds.width().times(DESKTOP_MODE_INITIAL_BOUNDS_SCALE).toInt()
+        val desiredHeight = screenBounds.height().times(DESKTOP_MODE_INITIAL_BOUNDS_SCALE).toInt()
+        outBounds.set(0, 0, desiredWidth, desiredHeight)
+        // Center the task in screen bounds
         outBounds.offset(
-            stableBounds.centerX() - outBounds.centerX(),
-            stableBounds.centerY() - outBounds.centerY()
-        )
+                screenBounds.centerX() - outBounds.centerX(),
+                screenBounds.centerY() - outBounds.centerY())
     }
 
     /**
@@ -1233,13 +1228,9 @@
             SystemProperties.getInt("persist.wm.debug.desktop_mode_density", 284)
         private val DESKTOP_DENSITY_ALLOWED_RANGE = (100..1000)
 
-        // Override default freeform task width when desktop mode is enabled. In dips.
-        private val DESKTOP_MODE_DEFAULT_WIDTH_DP =
-            SystemProperties.getInt("persist.wm.debug.desktop_mode.default_width", 840)
-
-        // Override default freeform task height when desktop mode is enabled. In dips.
-        private val DESKTOP_MODE_DEFAULT_HEIGHT_DP =
-            SystemProperties.getInt("persist.wm.debug.desktop_mode.default_height", 630)
+        @JvmField
+        val DESKTOP_MODE_INITIAL_BOUNDS_SCALE = SystemProperties
+                .getInt("persist.wm.debug.freeform_initial_bounds_scale", 75) / 100f
 
         /**
          * Check if desktop density override is enabled
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
index 07cf202..79bb540 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/EnterDesktopTaskTransitionHandler.java
@@ -54,8 +54,6 @@
     private final Transitions mTransitions;
     private final Supplier<SurfaceControl.Transaction> mTransactionSupplier;
 
-    // The size of the screen after drag relative to the fullscreen size
-    public static final float FINAL_FREEFORM_SCALE = 0.6f;
     public static final int FREEFORM_ANIMATION_DURATION = 336;
 
     private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index e018ecc..6a1a62ea 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -1037,6 +1037,7 @@
     private void computeEnterPipRotatedBounds(int rotationDelta, int startRotation, int endRotation,
             TaskInfo taskInfo, Rect outDestinationBounds, @Nullable Rect outSourceHintRect) {
         mPipDisplayLayoutState.rotateTo(endRotation);
+        mPipBoundsState.updateMinMaxSize(mPipBoundsState.getAspectRatio());
 
         final Rect displayBounds = mPipDisplayLayoutState.getDisplayBounds();
         outDestinationBounds.set(mPipBoundsAlgorithm.getEntryDestinationBounds());
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 4684077..2cdec81 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -976,8 +976,16 @@
         mPipBoundsState.addNamedUnrestrictedKeepClearArea(LAUNCHER_KEEP_CLEAR_AREA_TAG,
                 hotseatKeepClearArea);
         onDisplayRotationChangedNotInPip(mContext, launcherRotation);
+        // cache current min/max size
+        Point minSize = mPipBoundsState.getMinSize();
+        Point maxSize = mPipBoundsState.getMaxSize();
+        mPipBoundsState.updateMinMaxSize(pictureInPictureParams.getAspectRatioFloat());
         final Rect entryBounds = mPipTaskOrganizer.startSwipePipToHome(componentName, activityInfo,
                 pictureInPictureParams);
+        // restore min/max size, as this is referenced later in OnDisplayChangingListener and needs
+        // to reflect the pre-rotation state for it to work
+        mPipBoundsState.setMinSize(minSize.x, minSize.y);
+        mPipBoundsState.setMaxSize(maxSize.x, maxSize.y);
         // sync mPipBoundsState with the newly calculated bounds.
         mPipBoundsState.setNormalBounds(entryBounds);
         return entryBounds;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index e7dd31c..c1adfff 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -467,17 +467,11 @@
     }
 
     private void updatePinchResizeSizeConstraints(float aspectRatio) {
-        final int minWidth, minHeight, maxWidth, maxHeight;
-
-        minWidth = mSizeSpecSource.getMinSize(aspectRatio).getWidth();
-        minHeight = mSizeSpecSource.getMinSize(aspectRatio).getHeight();
-        maxWidth = mSizeSpecSource.getMaxSize(aspectRatio).getWidth();
-        maxHeight = mSizeSpecSource.getMaxSize(aspectRatio).getHeight();
-
-        mPipResizeGestureHandler.updateMinSize(minWidth, minHeight);
-        mPipResizeGestureHandler.updateMaxSize(maxWidth, maxHeight);
-        mPipBoundsState.setMaxSize(maxWidth, maxHeight);
-        mPipBoundsState.setMinSize(minWidth, minHeight);
+        mPipBoundsState.updateMinMaxSize(aspectRatio);
+        mPipResizeGestureHandler.updateMinSize(mPipBoundsState.getMinSize().x,
+                mPipBoundsState.getMinSize().y);
+        mPipResizeGestureHandler.updateMaxSize(mPipBoundsState.getMaxSize().x,
+                mPipBoundsState.getMaxSize().y);
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogImpl.java
deleted file mode 100644
index 93ffb3d..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogImpl.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2020 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.wm.shell.protolog;
-
-import android.annotation.Nullable;
-
-import com.android.internal.protolog.BaseProtoLogImpl;
-import com.android.internal.protolog.ProtoLogViewerConfigReader;
-import com.android.internal.protolog.common.IProtoLogGroup;
-
-import java.io.File;
-import java.io.PrintWriter;
-
-
-/**
- * A service for the ProtoLog logging system.
- */
-public class ShellProtoLogImpl extends BaseProtoLogImpl {
-    private static final String TAG = "ProtoLogImpl";
-    private static final int BUFFER_CAPACITY = 1024 * 1024;
-    // TODO: find a proper location to save the protolog message file
-    private static final String LOG_FILENAME = "/data/misc/wmtrace/shell_log.winscope";
-    private static final String VIEWER_CONFIG_FILENAME = "/system_ext/etc/wmshell.protolog.json.gz";
-
-    private static ShellProtoLogImpl sServiceInstance = null;
-
-    static {
-        addLogGroupEnum(ShellProtoLogGroup.values());
-    }
-
-    /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
-    public static void d(IProtoLogGroup group, int messageHash, int paramsMask,
-            @Nullable String messageString,
-            Object... args) {
-        getSingleInstance()
-                .log(LogLevel.DEBUG, group, messageHash, paramsMask, messageString, args);
-    }
-
-    /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
-    public static void v(IProtoLogGroup group, int messageHash, int paramsMask,
-            @Nullable String messageString,
-            Object... args) {
-        getSingleInstance().log(LogLevel.VERBOSE, group, messageHash, paramsMask, messageString,
-                args);
-    }
-
-    /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
-    public static void i(IProtoLogGroup group, int messageHash, int paramsMask,
-            @Nullable String messageString,
-            Object... args) {
-        getSingleInstance().log(LogLevel.INFO, group, messageHash, paramsMask, messageString, args);
-    }
-
-    /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
-    public static void w(IProtoLogGroup group, int messageHash, int paramsMask,
-            @Nullable String messageString,
-            Object... args) {
-        getSingleInstance().log(LogLevel.WARN, group, messageHash, paramsMask, messageString, args);
-    }
-
-    /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
-    public static void e(IProtoLogGroup group, int messageHash, int paramsMask,
-            @Nullable String messageString,
-            Object... args) {
-        getSingleInstance()
-                .log(LogLevel.ERROR, group, messageHash, paramsMask, messageString, args);
-    }
-
-    /** Used by the ProtoLogTool, do not call directly - use {@code ProtoLog} class instead. */
-    public static void wtf(IProtoLogGroup group, int messageHash, int paramsMask,
-            @Nullable String messageString,
-            Object... args) {
-        getSingleInstance().log(LogLevel.WTF, group, messageHash, paramsMask, messageString, args);
-    }
-
-    /** Returns true iff logging is enabled for the given {@code IProtoLogGroup}. */
-    public static boolean isEnabled(IProtoLogGroup group) {
-        return group.isLogToLogcat()
-                || (group.isLogToProto() && getSingleInstance().isProtoEnabled());
-    }
-
-    /**
-     * Returns the single instance of the ProtoLogImpl singleton class.
-     */
-    public static synchronized ShellProtoLogImpl getSingleInstance() {
-        if (sServiceInstance == null) {
-            sServiceInstance = new ShellProtoLogImpl();
-        }
-        return sServiceInstance;
-    }
-
-    public int startTextLogging(String[] groups, PrintWriter pw) {
-        mViewerConfig.loadViewerConfig(pw, VIEWER_CONFIG_FILENAME);
-        return setLogging(true /* setTextLogging */, true, pw, groups);
-    }
-
-    public int stopTextLogging(String[] groups, PrintWriter pw) {
-        return setLogging(true /* setTextLogging */, false, pw, groups);
-    }
-
-    private ShellProtoLogImpl() {
-        super(new File(LOG_FILENAME), VIEWER_CONFIG_FILENAME, BUFFER_CAPACITY,
-                new ProtoLogViewerConfigReader());
-    }
-}
-
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index fa14b4c..2933cf4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -3396,6 +3396,7 @@
                 final int stageType = isMainStage ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
                 final WindowContainerTransaction wct = new WindowContainerTransaction();
                 prepareExitSplitScreen(stageType, wct);
+                clearSplitPairedInRecents(EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW);
                 mSplitTransitions.startDismissTransition(wct, StageCoordinator.this, stageType,
                         EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW);
                 Log.w(TAG, splitFailureMessage("onNoLongerSupportMultiWindow",
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index c70a821..9130edf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -470,10 +470,12 @@
                 }
 
                 final float cornerRadius;
-                if (a.hasRoundedCorners() && isTask) {
-                    // hasRoundedCorners is currently only enabled for tasks
+                if (a.hasRoundedCorners()) {
+                    final int displayId = isTask ? change.getTaskInfo().displayId
+                            : info.getRoot(TransitionUtil.rootIndexFor(change, info))
+                                    .getDisplayId();
                     final Context displayContext =
-                            mDisplayController.getDisplayContext(change.getTaskInfo().displayId);
+                            mDisplayController.getDisplayContext(displayId);
                     cornerRadius = displayContext == null ? 0
                             : ScreenDecorationsUtils.getWindowCornerRadius(displayContext);
                 } else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/KtProtoLog.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/util/KtProtoLog.kt
index 9b48a54..7a50814 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/util/KtProtoLog.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/KtProtoLog.kt
@@ -18,7 +18,7 @@
 
 import android.util.Log
 import com.android.internal.protolog.common.IProtoLogGroup
-import com.android.wm.shell.protolog.ShellProtoLogImpl
+import com.android.internal.protolog.common.ProtoLog
 
 /**
  * Log messages using an API similar to [com.android.internal.protolog.common.ProtoLog]. Useful for
@@ -31,42 +31,42 @@
     companion object {
         /** @see [com.android.internal.protolog.common.ProtoLog.d] */
         fun d(group: IProtoLogGroup, messageString: String, vararg args: Any) {
-            if (ShellProtoLogImpl.isEnabled(group)) {
+            if (ProtoLog.isEnabled(group)) {
                 Log.d(group.tag, String.format(messageString, *args))
             }
         }
 
         /** @see [com.android.internal.protolog.common.ProtoLog.v] */
         fun v(group: IProtoLogGroup, messageString: String, vararg args: Any) {
-            if (ShellProtoLogImpl.isEnabled(group)) {
+            if (ProtoLog.isEnabled(group)) {
                 Log.v(group.tag, String.format(messageString, *args))
             }
         }
 
         /** @see [com.android.internal.protolog.common.ProtoLog.i] */
         fun i(group: IProtoLogGroup, messageString: String, vararg args: Any) {
-            if (ShellProtoLogImpl.isEnabled(group)) {
+            if (ProtoLog.isEnabled(group)) {
                 Log.i(group.tag, String.format(messageString, *args))
             }
         }
 
         /** @see [com.android.internal.protolog.common.ProtoLog.w] */
         fun w(group: IProtoLogGroup, messageString: String, vararg args: Any) {
-            if (ShellProtoLogImpl.isEnabled(group)) {
+            if (ProtoLog.isEnabled(group)) {
                 Log.w(group.tag, String.format(messageString, *args))
             }
         }
 
         /** @see [com.android.internal.protolog.common.ProtoLog.e] */
         fun e(group: IProtoLogGroup, messageString: String, vararg args: Any) {
-            if (ShellProtoLogImpl.isEnabled(group)) {
+            if (ProtoLog.isEnabled(group)) {
                 Log.e(group.tag, String.format(messageString, *args))
             }
         }
 
         /** @see [com.android.internal.protolog.common.ProtoLog.wtf] */
         fun wtf(group: IProtoLogGroup, messageString: String, vararg args: Any) {
-            if (ShellProtoLogImpl.isEnabled(group)) {
+            if (ProtoLog.isEnabled(group)) {
                 Log.wtf(group.tag, String.format(messageString, *args))
             }
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 57e964f..c1406d0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -22,11 +22,12 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.view.InputDevice.SOURCE_TOUCHSCREEN;
+import static android.view.MotionEvent.ACTION_HOVER_ENTER;
+import static android.view.MotionEvent.ACTION_HOVER_EXIT;
 import static android.view.WindowInsets.Type.statusBars;
 
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
 import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
-import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FINAL_FREEFORM_SCALE;
 import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FREEFORM_ANIMATION_DURATION;
 import static com.android.wm.shell.windowdecor.MoveToDesktopAnimator.DRAG_FREEFORM_SCALE;
 
@@ -311,8 +312,8 @@
 
     private class DesktopModeTouchEventListener extends GestureDetector.SimpleOnGestureListener
             implements View.OnClickListener, View.OnTouchListener, View.OnLongClickListener,
-            DragDetector.MotionEventHandler {
-
+            View.OnGenericMotionListener , DragDetector.MotionEventHandler {
+        private static final int CLOSE_MAXIMIZE_MENU_DELAY_MS = 150;
         private final int mTaskId;
         private final WindowContainerToken mTaskToken;
         private final DragPositioningCallback mDragPositioningCallback;
@@ -323,6 +324,7 @@
         private boolean mHasLongClicked;
         private boolean mShouldClick;
         private int mDragPointerId = -1;
+        private final Runnable mCloseMaximizeWindowRunnable;
 
         private DesktopModeTouchEventListener(
                 RunningTaskInfo taskInfo,
@@ -332,6 +334,11 @@
             mDragPositioningCallback = dragPositioningCallback;
             mDragDetector = new DragDetector(this);
             mGestureDetector = new GestureDetector(mContext, this);
+            mCloseMaximizeWindowRunnable = () -> {
+                final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
+                if (decoration == null) return;
+                decoration.closeMaximizeMenu();
+            };
         }
 
         @Override
@@ -387,13 +394,10 @@
                     mDesktopTasksController.ifPresent(c -> c.moveToNextDisplay(mTaskId));
                 }
             } else if (id == R.id.maximize_window) {
-                if (decoration.isMaximizeMenuActive()) {
-                    decoration.closeMaximizeMenu();
-                    return;
-                }
                 final RunningTaskInfo taskInfo = decoration.mTaskInfo;
-                mDesktopTasksController.ifPresent(c -> c.toggleDesktopTaskSize(taskInfo));
                 decoration.closeHandleMenu();
+                decoration.closeMaximizeMenu();
+                mDesktopTasksController.ifPresent(c -> c.toggleDesktopTaskSize(taskInfo));
             } else if (id == R.id.maximize_menu_maximize_button) {
                 final RunningTaskInfo taskInfo = decoration.mTaskInfo;
                 mDesktopTasksController.ifPresent(c -> c.toggleDesktopTaskSize(taskInfo));
@@ -460,6 +464,36 @@
             return false;
         }
 
+        @Override
+        public boolean onGenericMotion(View v, MotionEvent ev) {
+            final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
+            final int id = v.getId();
+            if (ev.getAction() == ACTION_HOVER_ENTER) {
+                if (!decoration.isMaximizeMenuActive() && id == R.id.maximize_window) {
+                    decoration.onMaximizeWindowHoverEnter();
+                } else if (id == R.id.maximize_window
+                        || MaximizeMenu.Companion.isMaximizeMenuView(id)) {
+                    // Re-hovering over any of the maximize menu views should keep the menu open by
+                    // cancelling any attempts to close the menu.
+                    mMainHandler.removeCallbacks(mCloseMaximizeWindowRunnable);
+                }
+                return true;
+            } else if (ev.getAction() == ACTION_HOVER_EXIT) {
+                if (!decoration.isMaximizeMenuActive() && id == R.id.maximize_window) {
+                    decoration.onMaximizeWindowHoverExit();
+                } else if (id == R.id.maximize_window
+                        || MaximizeMenu.Companion.isMaximizeMenuView(id)) {
+                    // Close menu if not hovering over maximize menu or maximize button after a
+                    // delay to give user a chance to re-enter view or to move from one maximize
+                    // menu view to another.
+                    mMainHandler.postDelayed(mCloseMaximizeWindowRunnable,
+                            CLOSE_MAXIMIZE_MENU_DELAY_MS);
+                }
+                return true;
+            }
+            return false;
+        }
+
         private void moveTaskToFront(RunningTaskInfo taskInfo) {
             if (!taskInfo.isFocused) {
                 mDesktopTasksController.ifPresent(c -> c.moveTaskToFront(taskInfo));
@@ -789,16 +823,16 @@
      * @param scale the amount to scale to relative to the Screen Bounds
      */
     private Rect calculateFreeformBounds(int displayId, float scale) {
+        // TODO(b/319819547): Account for app constraints so apps do not become letterboxed
         final DisplayLayout displayLayout = mDisplayController.getDisplayLayout(displayId);
         final int screenWidth = displayLayout.width();
         final int screenHeight = displayLayout.height();
 
         final float adjustmentPercentage = (1f - scale) / 2;
-        final Rect endBounds = new Rect((int) (screenWidth * adjustmentPercentage),
+        return new Rect((int) (screenWidth * adjustmentPercentage),
                 (int) (screenHeight * adjustmentPercentage),
                 (int) (screenWidth * (adjustmentPercentage + scale)),
                 (int) (screenHeight * (adjustmentPercentage + scale)));
-        return endBounds;
     }
 
     /**
@@ -840,7 +874,8 @@
                         c -> {
                             c.onDragPositioningEndThroughStatusBar(relevantDecor.mTaskInfo,
                                     calculateFreeformBounds(ev.getDisplayId(),
-                                            FINAL_FREEFORM_SCALE));
+                                            DesktopTasksController
+                                                    .DESKTOP_MODE_INITIAL_BOUNDS_SCALE));
                         });
             }
         });
@@ -990,7 +1025,7 @@
                 new DesktopModeTouchEventListener(taskInfo, dragPositioningCallback);
 
         windowDecoration.setCaptionListeners(
-                touchEventListener, touchEventListener, touchEventListener);
+                touchEventListener, touchEventListener, touchEventListener, touchEventListener);
         windowDecoration.setExclusionRegionListener(mExclusionRegionListener);
         windowDecoration.setDragPositioningCallback(dragPositioningCallback);
         windowDecoration.setDragDetector(touchEventListener.mDragDetector);
@@ -1036,6 +1071,7 @@
                 return;
             }
             decoration.showResizeVeil(t, bounds);
+            decoration.setAnimatingTaskResize(true);
         }
 
         @Override
@@ -1050,6 +1086,7 @@
             final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId);
             if (decoration == null) return;
             decoration.hideResizeVeil();
+            decoration.setAnimatingTaskResize(false);
         }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index 185365b..74f460b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -60,6 +60,8 @@
 import com.android.wm.shell.windowdecor.viewholder.DesktopModeFocusedWindowDecorationViewHolder;
 import com.android.wm.shell.windowdecor.viewholder.DesktopModeWindowDecorationViewHolder;
 
+import kotlin.Unit;
+
 import java.util.function.Supplier;
 
 /**
@@ -79,6 +81,7 @@
     private View.OnClickListener mOnCaptionButtonClickListener;
     private View.OnTouchListener mOnCaptionTouchListener;
     private View.OnLongClickListener mOnCaptionLongClickListener;
+    private View.OnGenericMotionListener mOnCaptionGenericMotionListener;
     private DragPositioningCallback mDragPositioningCallback;
     private DragResizeInputListener mDragResizeListener;
     private DragDetector mDragDetector;
@@ -152,10 +155,12 @@
     void setCaptionListeners(
             View.OnClickListener onCaptionButtonClickListener,
             View.OnTouchListener onCaptionTouchListener,
-            View.OnLongClickListener onLongClickListener) {
+            View.OnLongClickListener onLongClickListener,
+            View.OnGenericMotionListener onGenericMotionListener) {
         mOnCaptionButtonClickListener = onCaptionButtonClickListener;
         mOnCaptionTouchListener = onCaptionTouchListener;
         mOnCaptionLongClickListener = onLongClickListener;
+        mOnCaptionGenericMotionListener = onGenericMotionListener;
     }
 
     void setExclusionRegionListener(ExclusionRegionListener exclusionRegionListener) {
@@ -225,9 +230,15 @@
                         mOnCaptionTouchListener,
                         mOnCaptionButtonClickListener,
                         mOnCaptionLongClickListener,
+                        mOnCaptionGenericMotionListener,
                         mAppName,
-                        mAppIconBitmap
-                );
+                        mAppIconBitmap,
+                        () -> {
+                            if (!isMaximizeMenuActive()) {
+                                createMaximizeMenu();
+                            }
+                            return Unit.INSTANCE;
+                        });
             } else {
                 throw new IllegalArgumentException("Unexpected layout resource id");
             }
@@ -548,7 +559,8 @@
      */
     void createMaximizeMenu() {
         mMaximizeMenu = new MaximizeMenu(mSyncQueue, mRootTaskDisplayAreaOrganizer,
-                mDisplayController, mTaskInfo, mOnCaptionButtonClickListener, mContext,
+                mDisplayController, mTaskInfo, mOnCaptionButtonClickListener,
+                mOnCaptionGenericMotionListener, mOnCaptionTouchListener, mContext,
                 calculateMaximizeMenuPosition(), mSurfaceControlTransactionSupplier);
         mMaximizeMenu.show();
     }
@@ -776,6 +788,22 @@
         return R.id.desktop_mode_caption;
     }
 
+    void setAnimatingTaskResize(boolean animatingTaskResize) {
+        if (mRelayoutParams.mLayoutResId == R.layout.desktop_mode_focused_window_decor) return;
+        ((DesktopModeAppControlsWindowDecorationViewHolder) mWindowDecorViewHolder)
+                .setAnimatingTaskResize(animatingTaskResize);
+    }
+
+    void onMaximizeWindowHoverExit() {
+        ((DesktopModeAppControlsWindowDecorationViewHolder) mWindowDecorViewHolder)
+                .onMaximizeWindowHoverExit();
+    }
+
+    void onMaximizeWindowHoverEnter() {
+        ((DesktopModeAppControlsWindowDecorationViewHolder) mWindowDecorViewHolder)
+                .onMaximizeWindowHoverEnter();
+    }
+
     @Override
     public String toString() {
         return "{"
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt
new file mode 100644
index 0000000..b2f8cfd
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.windowdecor
+
+import android.animation.AnimatorSet
+import android.animation.ObjectAnimator
+import android.animation.ValueAnimator
+import android.content.Context
+import android.content.res.ColorStateList
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.FrameLayout
+import android.widget.ImageButton
+import android.widget.ProgressBar
+import androidx.core.animation.doOnEnd
+import androidx.core.animation.doOnStart
+import androidx.core.content.ContextCompat
+import com.android.wm.shell.R
+
+private const val OPEN_MAXIMIZE_MENU_DELAY_ON_HOVER_MS = 350
+private const val MAX_DRAWABLE_ALPHA = 255
+
+class MaximizeButtonView(
+        context: Context,
+        attrs: AttributeSet
+) : FrameLayout(context, attrs) {
+    lateinit var onHoverAnimationFinishedListener: () -> Unit
+    private val hoverProgressAnimatorSet = AnimatorSet()
+    var hoverDisabled = false
+
+    private val progressBar: ProgressBar
+    private val maximizeWindow: ImageButton
+
+    init {
+        LayoutInflater.from(context).inflate(R.layout.maximize_menu_button, this, true)
+
+        progressBar = requireViewById(R.id.progress_bar)
+        maximizeWindow = requireViewById(R.id.maximize_window)
+    }
+
+    fun startHoverAnimation() {
+        if (hoverDisabled) return
+        if (hoverProgressAnimatorSet.isRunning) {
+            cancelHoverAnimation()
+        }
+
+        maximizeWindow.background.alpha = 0
+
+        hoverProgressAnimatorSet.playSequentially(
+                ValueAnimator.ofInt(0, MAX_DRAWABLE_ALPHA)
+                        .setDuration(50)
+                        .apply {
+                            addUpdateListener {
+                                maximizeWindow.background.alpha = animatedValue as Int
+                            }
+                        },
+                ObjectAnimator.ofInt(progressBar, "progress", 100)
+                        .setDuration(OPEN_MAXIMIZE_MENU_DELAY_ON_HOVER_MS.toLong())
+                        .apply {
+                            doOnStart {
+                                progressBar.setProgress(0, false)
+                                progressBar.visibility = View.VISIBLE
+                            }
+                            doOnEnd {
+                                progressBar.visibility = View.INVISIBLE
+                                onHoverAnimationFinishedListener()
+                            }
+                        }
+        )
+        hoverProgressAnimatorSet.start()
+    }
+
+    fun cancelHoverAnimation() {
+        hoverProgressAnimatorSet.removeAllListeners()
+        hoverProgressAnimatorSet.cancel()
+        progressBar.visibility = View.INVISIBLE
+    }
+
+    fun setAnimationTints(darkMode: Boolean) {
+        if (darkMode) {
+            progressBar.progressTintList = ColorStateList.valueOf(
+                    resources.getColor(R.color.desktop_mode_maximize_menu_progress_dark))
+            maximizeWindow.background?.setTintList(ContextCompat.getColorStateList(context,
+                    R.color.desktop_mode_caption_button_color_selector_dark))
+        } else {
+            progressBar.progressTintList = ColorStateList.valueOf(
+                    resources.getColor(R.color.desktop_mode_maximize_menu_progress_light))
+            maximizeWindow.background?.setTintList(ContextCompat.getColorStateList(context,
+                    R.color.desktop_mode_caption_button_color_selector_light))
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt
index 794b357..b82f7ca 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeMenu.kt
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.windowdecor
 
+import android.annotation.IdRes
 import android.app.ActivityManager.RunningTaskInfo
 import android.content.Context
 import android.content.res.Resources
@@ -27,6 +28,8 @@
 import android.view.SurfaceControl.Transaction
 import android.view.SurfaceControlViewHost
 import android.view.View.OnClickListener
+import android.view.View.OnGenericMotionListener
+import android.view.View.OnTouchListener
 import android.view.WindowManager
 import android.view.WindowlessWindowManager
 import android.widget.Button
@@ -49,6 +52,8 @@
         private val displayController: DisplayController,
         private val taskInfo: RunningTaskInfo,
         private val onClickListener: OnClickListener,
+        private val onGenericMotionListener: OnGenericMotionListener,
+        private val onTouchListener: OnTouchListener,
         private val decorWindowContext: Context,
         private val menuPosition: PointF,
         private val transactionSupplier: Supplier<Transaction> = Supplier { Transaction() }
@@ -142,15 +147,26 @@
     private fun setupMaximizeMenu() {
         val maximizeMenuView = maximizeMenu?.mWindowViewHost?.view ?: return
 
-        maximizeMenuView.requireViewById<Button>(
+        maximizeMenuView.setOnGenericMotionListener(onGenericMotionListener)
+        maximizeMenuView.setOnTouchListener(onTouchListener)
+
+        val maximizeButton = maximizeMenuView.requireViewById<Button>(
                 R.id.maximize_menu_maximize_button
-        ).setOnClickListener(onClickListener)
-        maximizeMenuView.requireViewById<Button>(
+        )
+        maximizeButton.setOnClickListener(onClickListener)
+        maximizeButton.setOnGenericMotionListener(onGenericMotionListener)
+
+        val snapRightButton = maximizeMenuView.requireViewById<Button>(
                 R.id.maximize_menu_snap_right_button
-        ).setOnClickListener(onClickListener)
-        maximizeMenuView.requireViewById<Button>(
+        )
+        snapRightButton.setOnClickListener(onClickListener)
+        snapRightButton.setOnGenericMotionListener(onGenericMotionListener)
+
+        val snapLeftButton = maximizeMenuView.requireViewById<Button>(
                 R.id.maximize_menu_snap_left_button
-        ).setOnClickListener(onClickListener)
+        )
+        snapLeftButton.setOnClickListener(onClickListener)
+        snapLeftButton.setOnGenericMotionListener(onGenericMotionListener)
     }
 
     /**
@@ -173,4 +189,12 @@
     private fun viewsLaidOut(): Boolean {
         return maximizeMenu?.mWindowViewHost?.view?.isLaidOut ?: false
     }
+
+    companion object {
+        fun isMaximizeMenuView(@IdRes viewId: Int): Boolean {
+            return viewId == R.id.maximize_menu || viewId == R.id.maximize_menu_maximize_button ||
+                    viewId == R.id.maximize_menu_snap_left_button ||
+                    viewId == R.id.maximize_menu_snap_right_button
+        }
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt
index 2309c54..7e5b9bd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt
@@ -21,6 +21,7 @@
 import com.android.internal.R.attr.materialColorSurfaceContainerLow
 import com.android.internal.R.attr.materialColorSurfaceDim
 import com.android.wm.shell.R
+import com.android.wm.shell.windowdecor.MaximizeButtonView
 
 /**
  * A desktop mode window decoration used when the window is floating (i.e. freeform). It hosts
@@ -32,8 +33,10 @@
         onCaptionTouchListener: View.OnTouchListener,
         onCaptionButtonClickListener: View.OnClickListener,
         onLongClickListener: OnLongClickListener,
+        onCaptionGenericMotionListener: View.OnGenericMotionListener,
         appName: CharSequence,
-        appIconBitmap: Bitmap
+        appIconBitmap: Bitmap,
+        onMaximizeHoverAnimationFinishedListener: () -> Unit
 ) : DesktopModeWindowDecorationViewHolder(rootView) {
 
     private val captionView: View = rootView.requireViewById(R.id.desktop_mode_caption)
@@ -41,6 +44,8 @@
     private val openMenuButton: View = rootView.requireViewById(R.id.open_menu_button)
     private val closeWindowButton: ImageButton = rootView.requireViewById(R.id.close_window)
     private val expandMenuButton: ImageButton = rootView.requireViewById(R.id.expand_menu_button)
+    private val maximizeButtonView: MaximizeButtonView =
+            rootView.requireViewById(R.id.maximize_button_view)
     private val maximizeWindowButton: ImageButton = rootView.requireViewById(R.id.maximize_window)
     private val appNameTextView: TextView = rootView.requireViewById(R.id.application_name)
     private val appIconImageView: ImageView = rootView.requireViewById(R.id.application_icon)
@@ -55,10 +60,13 @@
         closeWindowButton.setOnClickListener(onCaptionButtonClickListener)
         maximizeWindowButton.setOnClickListener(onCaptionButtonClickListener)
         maximizeWindowButton.setOnTouchListener(onCaptionTouchListener)
+        maximizeWindowButton.setOnGenericMotionListener(onCaptionGenericMotionListener)
         maximizeWindowButton.onLongClickListener = onLongClickListener
         closeWindowButton.setOnTouchListener(onCaptionTouchListener)
         appNameTextView.text = appName
         appIconImageView.setImageBitmap(appIconBitmap)
+        maximizeButtonView.onHoverAnimationFinishedListener =
+                onMaximizeHoverAnimationFinishedListener
     }
 
     override fun bindData(taskInfo: RunningTaskInfo) {
@@ -73,12 +81,30 @@
         maximizeWindowButton.imageAlpha = alpha
         closeWindowButton.imageAlpha = alpha
         expandMenuButton.imageAlpha = alpha
+
+        maximizeButtonView.setAnimationTints(isDarkMode())
     }
 
     override fun onHandleMenuOpened() {}
 
     override fun onHandleMenuClosed() {}
 
+    fun setAnimatingTaskResize(animatingTaskResize: Boolean) {
+        // If animating a task resize, cancel any running hover animations
+        if (animatingTaskResize) {
+            maximizeButtonView.cancelHoverAnimation()
+        }
+        maximizeButtonView.hoverDisabled = animatingTaskResize
+    }
+
+    fun onMaximizeWindowHoverExit() {
+        maximizeButtonView.cancelHoverAnimation()
+    }
+
+    fun onMaximizeWindowHoverEnter() {
+        maximizeButtonView.startHoverAnimation()
+    }
+
     @ColorInt
     private fun getCaptionBackgroundColor(taskInfo: RunningTaskInfo): Int {
         if (isTransparentBackgroundRequested(taskInfo)) {
diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
index adf92d8..3380adac 100644
--- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
+++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/BaseAppCompat.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.appcompat
 
 import android.content.Context
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTestData
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.FlickerTestData
+import android.tools.flicker.legacy.LegacyFlickerTest
 import com.android.server.wm.flicker.helpers.LetterboxAppHelper
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.wm.shell.flicker.BaseTest
diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
index 1e5e42f..f08eba5 100644
--- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenAppInSizeCompatModeTest.kt
@@ -17,12 +17,12 @@
 package com.android.wm.shell.flicker.appcompat
 
 import android.platform.test.annotations.Postsubmit
-import android.tools.common.flicker.assertions.FlickerTest
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.assertions.FlickerTest
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt
index 2fa1ec3..826fc54 100644
--- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/OpenTransparentActivityTest.kt
@@ -17,13 +17,13 @@
 package com.android.wm.shell.flicker.appcompat
 
 import android.platform.test.annotations.Postsubmit
-import android.tools.common.Rotation
-import android.tools.common.flicker.assertions.FlickerTest
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.flicker.assertions.FlickerTest
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt
index b74aa1d..26e78bf 100644
--- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/QuickSwitchLauncherToLetterboxAppTest.kt
@@ -18,15 +18,15 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.RequiresDevice
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.datatypes.Rect
-import android.tools.common.flicker.assertions.FlickerTest
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.datatypes.Rect
+import android.tools.flicker.assertions.FlickerTest
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt
index 68fa8d2..2aa84b4 100644
--- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RepositionFixedPortraitAppTest.kt
@@ -17,13 +17,13 @@
 package com.android.wm.shell.flicker.appcompat
 
 import android.platform.test.annotations.Postsubmit
-import android.tools.common.Rotation
-import android.tools.common.flicker.assertions.FlickerTest
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.WindowUtils
+import android.tools.Rotation
+import android.tools.flicker.assertions.FlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.helpers.WindowUtils
 import androidx.test.filters.RequiresDevice
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
index fcb6931a..443fac1 100644
--- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RestartAppInSizeCompatModeTest.kt
@@ -17,12 +17,12 @@
 package com.android.wm.shell.flicker.appcompat
 
 import android.platform.test.annotations.Postsubmit
-import android.tools.common.flicker.assertions.FlickerTest
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.WindowUtils
+import android.tools.flicker.assertions.FlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.helpers.WindowUtils
 import androidx.test.filters.RequiresDevice
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt
index 446aad8..7ffa233 100644
--- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/RotateImmersiveAppInFullscreenTest.kt
@@ -19,17 +19,17 @@
 import android.os.Build
 import android.platform.test.annotations.Postsubmit
 import android.system.helpers.CommandsHelper
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.datatypes.Rect
-import android.tools.common.flicker.assertions.FlickerTest
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.FIND_TIMEOUT
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.datatypes.Rect
+import android.tools.flicker.assertions.FlickerTest
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.helpers.FIND_TIMEOUT
+import android.tools.traces.parsers.toFlickerComponent
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.UiDevice
 import androidx.test.uiautomator.Until
diff --git a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/TransparentBaseAppCompat.kt b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/TransparentBaseAppCompat.kt
index 9792c85..2c0f837 100644
--- a/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/TransparentBaseAppCompat.kt
+++ b/libs/WindowManager/Shell/tests/flicker/appcompat/src/com/android/wm/shell/flicker/appcompat/TransparentBaseAppCompat.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.appcompat
 
 import android.content.Context
-import android.tools.device.flicker.legacy.FlickerTestData
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.helpers.FIND_TIMEOUT
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.flicker.legacy.FlickerTestData
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.helpers.FIND_TIMEOUT
+import android.tools.traces.parsers.toFlickerComponent
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.UiObject2
 import androidx.test.uiautomator.Until
diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
index 0c36e29..8eca456 100644
--- a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
@@ -21,12 +21,12 @@
 import android.content.Context
 import android.content.pm.PackageManager
 import android.os.ServiceManager
-import android.tools.common.Rotation
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTestData
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.SYSTEMUI_PACKAGE
+import android.tools.Rotation
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.FlickerTestData
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.helpers.SYSTEMUI_PACKAGE
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.UiObject2
 import androidx.test.uiautomator.Until
diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt
index 55039f5..bc486c2 100644
--- a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/ChangeActiveActivityFromBubbleTest.kt
@@ -18,9 +18,9 @@
 
 import android.os.SystemClock
 import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import androidx.test.filters.FlakyTest
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.UiObject2
diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt
index 9ca7bf1..521c0d0 100644
--- a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/DragToDismissBubbleScreenTest.kt
@@ -19,11 +19,11 @@
 import android.content.Context
 import android.graphics.Point
 import android.platform.test.annotations.Presubmit
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.subject.layers.LayersTraceSubject
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import android.util.DisplayMetrics
 import android.view.WindowManager
 import androidx.test.uiautomator.By
diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt
index b007e6b..e059ac7 100644
--- a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleOnLocksreenTest.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.bubble
 
 import android.platform.test.annotations.Postsubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import android.view.WindowInsets
 import android.view.WindowManager
 import androidx.test.filters.FlakyTest
diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt
index 4959672..ef7fbfb 100644
--- a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/OpenActivityFromBubbleTest.kt
@@ -17,9 +17,9 @@
 package com.android.wm.shell.flicker.bubble
 
 import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Until
 import org.junit.Test
diff --git a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt
index 0d95574..87224b15 100644
--- a/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/bubble/src/com/android/wm/shell/flicker/bubble/SendBubbleNotificationTest.kt
@@ -17,9 +17,9 @@
 package com.android.wm.shell.flicker.bubble
 
 import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Until
 import org.junit.Test
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
index af2db12..d64bfed 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
@@ -17,9 +17,9 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.pip.common.EnterPipTransition
@@ -46,7 +46,7 @@
  * ```
  *     1. All assertions are inherited from [EnterPipTest]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt
index 8c0a524..a0edcfb 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -44,7 +44,7 @@
  * ```
  *     1. All assertions are inherited from [AutoEnterPipOnGoToHomeTest]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
index 9256725..031acf4 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import com.android.wm.shell.flicker.pip.common.ClosePipTransition
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -44,7 +44,7 @@
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited [PipTransition]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt
index 002c019..860307f 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt
@@ -17,9 +17,9 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import com.android.wm.shell.flicker.pip.common.ClosePipTransition
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -44,7 +44,7 @@
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited [PipTransition]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
index 4cc9547..c554161 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
@@ -17,9 +17,9 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import com.android.wm.shell.flicker.pip.common.EnterPipTransition
 import org.junit.Assume
 import org.junit.FixMethodOrder
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
index 07cd682..ac7380f 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt
@@ -19,14 +19,14 @@
 import android.app.Activity
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.flicker.assertions.FlickerTest
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.WindowUtils
+import android.tools.Rotation
+import android.tools.flicker.assertions.FlickerTest
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.helpers.WindowUtils
 import androidx.test.filters.FlakyTest
 import com.android.server.wm.flicker.entireScreenCovered
 import com.android.server.wm.flicker.helpers.FixedOrientationAppHelper
@@ -60,7 +60,7 @@
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited [PipTransition]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt
index cc94367..f97d8d1 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt
@@ -16,9 +16,9 @@
 
 package com.android.wm.shell.flicker.pip
 
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import com.android.wm.shell.flicker.pip.common.EnterPipTransition
 import org.junit.FixMethodOrder
 import org.junit.runner.RunWith
@@ -41,7 +41,7 @@
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited from [PipTransition]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt
index 7da4429..47bf418 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt
@@ -16,9 +16,9 @@
 
 package com.android.wm.shell.flicker.pip
 
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import com.android.wm.shell.flicker.pip.common.ExitPipToAppTransition
 import org.junit.FixMethodOrder
 import org.junit.runner.RunWith
@@ -43,7 +43,7 @@
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited [PipTransition]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt
index 0ad9e4c..a356e68 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt
@@ -16,9 +16,9 @@
 
 package com.android.wm.shell.flicker.pip
 
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import com.android.wm.shell.flicker.pip.common.ExitPipToAppTransition
 import org.junit.FixMethodOrder
 import org.junit.runner.RunWith
@@ -42,7 +42,7 @@
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited from [PipTransition]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
index 89a6c93..25614ef 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
@@ -17,12 +17,12 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import com.android.wm.shell.flicker.pip.common.PipTransition
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -46,7 +46,7 @@
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited [PipTransition]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt
index 8978af0..1964e3c 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt
@@ -17,11 +17,11 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import com.android.wm.shell.flicker.pip.common.PipTransition
 import org.junit.FixMethodOrder
 import org.junit.Test
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt
index 2792298..b94989d 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt
@@ -17,13 +17,13 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.WindowUtils
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.helpers.WindowUtils
+import android.tools.traces.parsers.toFlickerComponent
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import com.android.server.wm.flicker.testapp.ActivityOptions
@@ -52,7 +52,7 @@
  * ```
  *     1. All assertions are inherited from [EnterPipTest]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt
index 4c23153..1ccc7d8 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt
@@ -17,13 +17,13 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.WindowUtils
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.helpers.WindowUtils
+import android.tools.traces.parsers.toFlickerComponent
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import com.android.server.wm.flicker.testapp.ActivityOptions
@@ -53,7 +53,7 @@
  * ```
  *     1. All assertions are inherited from [EnterPipTest]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt
index 4776206..9b74622 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt
@@ -17,9 +17,9 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.pip.common.MovePipShelfHeightTransition
 import com.android.wm.shell.flicker.utils.Direction
@@ -47,7 +47,7 @@
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited [PipTransition]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt
index 425cbfaff..e184cf0 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt
@@ -17,14 +17,14 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.flicker.assertions.FlickerTest
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.WindowUtils
+import android.tools.Rotation
+import android.tools.flicker.assertions.FlickerTest
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.helpers.WindowUtils
 import com.android.server.wm.flicker.helpers.ImeAppHelper
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.wm.shell.flicker.pip.common.PipTransition
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt
index 18f30d9..490ebd1 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt
@@ -17,9 +17,9 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.pip.common.MovePipShelfHeightTransition
 import com.android.wm.shell.flicker.utils.Direction
@@ -47,7 +47,7 @@
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited [PipTransition]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt
index 36047cc..70be58f 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt
@@ -17,11 +17,11 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import com.android.wm.shell.flicker.pip.common.PipTransition
 import org.junit.FixMethodOrder
 import org.junit.Test
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt
index c7f2786..a4df69f 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt
@@ -18,10 +18,10 @@
 
 import android.platform.test.annotations.Presubmit
 import android.platform.test.annotations.RequiresDevice
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import com.android.server.wm.flicker.testapp.ActivityOptions
 import com.android.wm.shell.flicker.pip.common.PipTransition
 import org.junit.FixMethodOrder
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
index cabc1cc..90b9798 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt
@@ -17,12 +17,12 @@
 package com.android.wm.shell.flicker.pip
 
 import android.graphics.Rect
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.rules.RemoveAllTasksButHomeRule
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.helpers.setRotation
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt
index 381f947..6841706 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt
@@ -17,12 +17,12 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.flicker.subject.exceptions.IncorrectRegionException
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.flicker.subject.exceptions.IncorrectRegionException
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.pip.common.PipTransition
 import org.junit.FixMethodOrder
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt
index 1f69847..9a6dacb 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt
@@ -19,13 +19,13 @@
 import android.app.Activity
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.flicker.assertions.FlickerTest
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.WindowUtils
+import android.tools.Rotation
+import android.tools.flicker.assertions.FlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.helpers.WindowUtils
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.testapp.ActivityOptions
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt
index 308ece4..d2f803e 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt
@@ -17,12 +17,12 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.flicker.assertions.FlickerTest
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.WindowUtils
+import android.tools.flicker.assertions.FlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.helpers.WindowUtils
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.wm.shell.flicker.pip.common.PipTransition
@@ -50,7 +50,7 @@
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited from [PipTransition]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt
index be77171..c9f4a6c 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/AppsEnterPipTransition.kt
@@ -17,13 +17,13 @@
 package com.android.wm.shell.flicker.pip.apps
 
 import android.platform.test.annotations.Postsubmit
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.Rotation
+import android.tools.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.flicker.junit.FlickerBuilderProvider
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerBuilderProvider
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import com.android.wm.shell.flicker.pip.common.EnterPipTransition
 import org.junit.Test
 import org.junit.runners.Parameterized
@@ -101,8 +101,9 @@
     override fun pipLayerReduces() {
         flicker.assertLayers {
             val pipLayerList =
-                this.layers { standardAppHelper.packageNameMatcher.layerMatchesAnyOf(it)
-                        && it.isVisible }
+                this.layers {
+                    standardAppHelper.packageNameMatcher.layerMatchesAnyOf(it) && it.isVisible
+                }
             pipLayerList.zipWithNext { previous, current ->
                 current.visibleRegion.notBiggerThan(previous.visibleRegion.region)
             }
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt
index 4c2eff3..8865010 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/MapsEnterPipTest.kt
@@ -26,9 +26,9 @@
 import android.os.SystemClock
 import android.platform.test.annotations.Postsubmit
 import android.tools.device.apphelpers.MapsAppHelper
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import androidx.test.filters.RequiresDevice
 import org.junit.Assume
 import org.junit.FixMethodOrder
@@ -53,7 +53,7 @@
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited from [PipTransition]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt
index 143f7a7..9b51538 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/NetflixEnterPipTest.kt
@@ -18,14 +18,14 @@
 
 import android.Manifest
 import android.platform.test.annotations.Postsubmit
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.NetflixAppHelper
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.statusBarLayerPositionAtEnd
 import org.junit.Assume
@@ -51,7 +51,7 @@
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited from [PipTransition]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt
index 509b32c..3ae5937 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/apps/YouTubeEnterPipTest.kt
@@ -18,11 +18,11 @@
 
 import android.Manifest
 import android.platform.test.annotations.Postsubmit
-import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.YouTubeAppHelper
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import androidx.test.filters.RequiresDevice
 import org.junit.Assume
 import org.junit.FixMethodOrder
@@ -47,7 +47,7 @@
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited from [PipTransition]
  *     2. Part of the test setup occurs automatically via
- *        [android.tools.device.flicker.legacy.runner.TransitionRunner],
+ *        [android.tools.flicker.legacy.runner.TransitionRunner],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
  * ```
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt
index 751f2bc..dc12259 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ClosePipTransition.kt
@@ -17,11 +17,11 @@
 package com.android.wm.shell.flicker.pip.common
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher.Companion.LAUNCHER
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.traces.component.ComponentNameMatcher.Companion.LAUNCHER
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import com.android.server.wm.flicker.helpers.setRotation
 import org.junit.Test
 import org.junit.runners.Parameterized
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt
index 9c129e4..3d9eae6 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/EnterPipTransition.kt
@@ -17,11 +17,11 @@
 package com.android.wm.shell.flicker.pip.common
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import org.junit.Test
 import org.junit.runners.Parameterized
 
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt
index 9450bdd..7b6839d 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/ExitPipToAppTransition.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.pip.common
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import org.junit.Test
 import org.junit.runners.Parameterized
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/MovePipShelfHeightTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/MovePipShelfHeightTransition.kt
index 7e42bc1..f4baf5f 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/MovePipShelfHeightTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/MovePipShelfHeightTransition.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.pip.common
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.flicker.subject.region.RegionSubject
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.flicker.subject.region.RegionSubject
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import com.android.server.wm.flicker.helpers.FixedOrientationAppHelper
 import com.android.wm.shell.flicker.utils.Direction
 import org.junit.Test
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt
index 7b7f1d7..fd467e3 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt
@@ -19,12 +19,12 @@
 import android.app.Instrumentation
 import android.content.Intent
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
-import android.tools.device.helpers.WindowUtils
+import android.tools.Rotation
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
+import android.tools.helpers.WindowUtils
 import com.android.server.wm.flicker.helpers.PipAppHelper
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.testapp.ActivityOptions
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/PipAppHelperTv.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/PipAppHelperTv.kt
index c6cbcd0..4e1a8ff 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/PipAppHelperTv.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/PipAppHelperTv.kt
@@ -17,7 +17,7 @@
 package com.android.wm.shell.flicker.pip.tv
 
 import android.app.Instrumentation
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.BySelector
 import androidx.test.uiautomator.UiObject2
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt
index 0d18535..2854222 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/tv/TvPipTestBase.kt
@@ -20,8 +20,8 @@
 import android.app.IActivityManager
 import android.app.IProcessObserver
 import android.os.SystemClock
-import android.tools.device.helpers.wakeUpAndGoToHomeScreen
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.helpers.wakeUpAndGoToHomeScreen
+import android.tools.traces.parsers.WindowManagerStateHelper
 import android.view.Surface.ROTATION_0
 import android.view.Surface.rotationToString
 import com.android.wm.shell.flicker.utils.SYSTEM_UI_PACKAGE_NAME
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/common/Utils.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/common/Utils.kt
index 4bd7954..4c6c6cc 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/common/Utils.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/common/Utils.kt
@@ -20,13 +20,13 @@
 import android.platform.test.rule.NavigationModeRule
 import android.platform.test.rule.PressHomeRule
 import android.platform.test.rule.UnlockScreenRule
-import android.tools.common.NavBar
-import android.tools.common.Rotation
+import android.tools.NavBar
+import android.tools.Rotation
 import android.tools.device.apphelpers.MessagingAppHelper
-import android.tools.device.flicker.rules.ArtifactSaverRule
-import android.tools.device.flicker.rules.ChangeDisplayOrientationRule
-import android.tools.device.flicker.rules.LaunchAppRule
-import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
+import android.tools.flicker.rules.ArtifactSaverRule
+import android.tools.flicker.rules.ChangeDisplayOrientationRule
+import android.tools.flicker.rules.LaunchAppRule
+import android.tools.flicker.rules.RemoveAllTasksButHomeRule
 import androidx.test.platform.app.InstrumentationRegistry
 import org.junit.rules.RuleChain
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavLandscape.kt
index a5c5122..1684a26 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 package com.android.wm.shell.flicker.service.splitscreen.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.CopyContentInSplit
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavPortrait.kt
index 092fb67..3b5fad6 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/CopyContentInSplitGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 package com.android.wm.shell.flicker.service.splitscreen.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.CopyContentInSplit
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavLandscape.kt
index 69499b9..2b8a903 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 package com.android.wm.shell.flicker.service.splitscreen.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByDivider
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavPortrait.kt
index bd627f4..b284fe1 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByDividerGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 package com.android.wm.shell.flicker.service.splitscreen.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByDivider
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavLandscape.kt
index a8f4d0a..a400ee4 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 package com.android.wm.shell.flicker.service.splitscreen.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByGoHome
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavPortrait.kt
index cee9bbf..7f5ee4c 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DismissSplitScreenByGoHomeGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 package com.android.wm.shell.flicker.service.splitscreen.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByGoHome
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavLandscape.kt
index c1b3aad..1b075c4 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 package com.android.wm.shell.flicker.service.splitscreen.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.DragDividerToResize
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavPortrait.kt
index c6e2e85..6ca3737 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/DragDividerToResizeGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 package com.android.wm.shell.flicker.service.splitscreen.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.DragDividerToResize
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt
index 169b5cf..f7d231f0 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 package com.android.wm.shell.flicker.service.splitscreen.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromAllApps
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt
index 412c011..ab819fa 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 package com.android.wm.shell.flicker.service.splitscreen.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromAllApps
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt
index 6e4cf9f..a6b732c 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 package com.android.wm.shell.flicker.service.splitscreen.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromNotification
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt
index cc28702..07e5f4b 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 package com.android.wm.shell.flicker.service.splitscreen.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromNotification
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt
index 736604f..2725694 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 package com.android.wm.shell.flicker.service.splitscreen.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromShortcut
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt
index 8df8dfa..58cc4d7 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 package com.android.wm.shell.flicker.service.splitscreen.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromShortcut
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt
index 378f055..85897a1 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 package com.android.wm.shell.flicker.service.splitscreen.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromTaskbar
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt
index b33d262..891b6df 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 package com.android.wm.shell.flicker.service.splitscreen.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromTaskbar
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavLandscape.kt
index b1d3858..7983652 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 package com.android.wm.shell.flicker.service.splitscreen.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenFromOverview
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavPortrait.kt
index 6d824c7..1bdea66 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/EnterSplitScreenFromOverviewGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 package com.android.wm.shell.flicker.service.splitscreen.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenFromOverview
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt
index f1d3d0c..bab0c0a 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 package com.android.wm.shell.flicker.service.splitscreen.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchAppByDoubleTapDivider
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt
index a867bac..17a59ab 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 package com.android.wm.shell.flicker.service.splitscreen.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchAppByDoubleTapDivider
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt
index 76247ba..2c36d64 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 package com.android.wm.shell.flicker.service.splitscreen.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromAnotherApp
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt
index e179da8..6e91d04 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 package com.android.wm.shell.flicker.service.splitscreen.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromAnotherApp
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavLandscape.kt
index 20f554f..a921b46 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 package com.android.wm.shell.flicker.service.splitscreen.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromHome
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavPortrait.kt
index f7776ee..05f8912 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromHomeGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 package com.android.wm.shell.flicker.service.splitscreen.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromHome
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavLandscape.kt
index 4ff0b4362..1ae1f53 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 package com.android.wm.shell.flicker.service.splitscreen.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromRecent
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavPortrait.kt
index 930f31d..e14ca55 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBackToSplitFromRecentGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 package com.android.wm.shell.flicker.service.splitscreen.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromRecent
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavLandscape.kt
index 3da61e5..ce0c4c4 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 package com.android.wm.shell.flicker.service.splitscreen.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBetweenSplitPairs
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavPortrait.kt
index 627ae18..5a8d2d5 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/SwitchBetweenSplitPairsGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 package com.android.wm.shell.flicker.service.splitscreen.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBetweenSplitPairs
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt
index c744103..d442615 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavLandscape.kt
@@ -16,12 +16,12 @@
 
 package com.android.wm.shell.flicker.service.splitscreen.flicker
 
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.UnlockKeyguardToSplitScreen
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt
index 11a4e02..ddc8a06 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/flicker/UnlockKeyguardToSplitScreenGesturalNavPortrait.kt
@@ -16,12 +16,12 @@
 
 package com.android.wm.shell.flicker.service.splitscreen.flicker
 
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.UnlockKeyguardToSplitScreen
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt
index e37d806..64293b2 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavLandscape.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.CopyContentInSplit
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt
index 2a50912..517ba2d 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/CopyContentInSplitGesturalNavPortrait.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.CopyContentInSplit
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt
index d5da1a8..1bafe3b 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavLandscape.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByDivider
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt
index 7fdcb9b..fd0100f 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByDividerGesturalNavPortrait.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByDivider
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt
index 308e954..850b3d8 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavLandscape.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByGoHome
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt
index 39e75bd..0b752bf 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DismissSplitScreenByGoHomeGesturalNavPortrait.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.DismissSplitScreenByGoHome
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt
index e18da17..3c52aa7 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavLandscape.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.DragDividerToResize
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt
index 00d60e7..c2e21b8 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/DragDividerToResizeGesturalNavPortrait.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.DragDividerToResize
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt
index d7efbc8..bf85ab4 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavLandscape.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromAllApps
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt
index 4eece3f..0ac4ca2 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromAllAppsGesturalNavPortrait.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromAllApps
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt
index d96b056..80bd088 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavLandscape.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromNotification
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt
index 809b690..0dffb4a 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromNotificationGesturalNavPortrait.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromNotification
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt
index bbdf2d7..b721f2f 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavLandscape.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromShortcut
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt
index 5c29fd8..22cbc77 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromShortcutGesturalNavPortrait.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromShortcut
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt
index a7398eb..ac0f9e2 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavLandscape.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromTaskbar
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt
index eae88ad..f7a229d 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenByDragFromTaskbarGesturalNavPortrait.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenByDragFromTaskbar
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt
index 7e8ee04..6dbbcb0 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavLandscape.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenFromOverview
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt
index 9295c33..bd69ea9 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/EnterSplitScreenFromOverviewGesturalNavPortrait.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.EnterSplitScreenFromOverview
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt
index 4b59e9f..404b96f 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavLandscape.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchAppByDoubleTapDivider
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt
index 5ff36d4..a79687d 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchAppByDoubleTapDividerGesturalNavPortrait.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchAppByDoubleTapDivider
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt
index c0cb721..b52eb4c 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavLandscape.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromAnotherApp
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt
index 8c14088..d79620c 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromAnotherAppGesturalNavPortrait.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromAnotherApp
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt
index 7b6614b..d27bfa1 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavLandscape.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromHome
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt
index 5df5be9..3c7d4d4 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromHomeGesturalNavPortrait.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromHome
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt
index 9d63003..26a2034 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavLandscape.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromRecent
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt
index 9fa04b2..5154b35 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBackToSplitFromRecentGesturalNavPortrait.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBackToSplitFromRecent
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt
index 9386aa2..86451c5 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavLandscape.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBetweenSplitPairs
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt
index 5ef2167..baf72b4 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/platinum/SwitchBetweenSplitPairsGesturalNavPortrait.kt
@@ -18,7 +18,7 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
+import android.tools.Rotation
 import com.android.wm.shell.flicker.service.splitscreen.scenarios.SwitchBetweenSplitPairs
 import org.junit.Test
 
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/CopyContentInSplit.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/CopyContentInSplit.kt
index 824e454..89ef91e 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/CopyContentInSplit.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/CopyContentInSplit.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.service.splitscreen.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.AndroidLoggerSetupRule
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.AndroidLoggerSetupRule
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByDivider.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByDivider.kt
index 4c39104..c1a8ee7 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByDivider.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByDivider.kt
@@ -17,9 +17,9 @@
 package com.android.wm.shell.flicker.service.splitscreen.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByGoHome.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByGoHome.kt
index f6d1afc..600855a 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByGoHome.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DismissSplitScreenByGoHome.kt
@@ -17,9 +17,9 @@
 package com.android.wm.shell.flicker.service.splitscreen.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt
index db5a32a..c671fbe 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/DragDividerToResize.kt
@@ -17,9 +17,9 @@
 package com.android.wm.shell.flicker.service.splitscreen.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt
index 03170a3..a189325 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromAllApps.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.service.splitscreen.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.flicker.rules.ChangeDisplayOrientationRule
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.rules.ChangeDisplayOrientationRule
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt
index c52ada3b..4336692 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromNotification.kt
@@ -17,11 +17,11 @@
 package com.android.wm.shell.flicker.service.splitscreen.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.AndroidLoggerSetupRule
-import android.tools.device.flicker.rules.ChangeDisplayOrientationRule
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.AndroidLoggerSetupRule
+import android.tools.flicker.rules.ChangeDisplayOrientationRule
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt
index 479d01d..8c7e63f 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromShortcut.kt
@@ -17,11 +17,11 @@
 package com.android.wm.shell.flicker.service.splitscreen.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.AndroidLoggerSetupRule
-import android.tools.device.flicker.rules.ChangeDisplayOrientationRule
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.AndroidLoggerSetupRule
+import android.tools.flicker.rules.ChangeDisplayOrientationRule
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt
index 625c56b..2072831 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenByDragFromTaskbar.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.service.splitscreen.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.AndroidLoggerSetupRule
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.AndroidLoggerSetupRule
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt
index f1a011c..09e77cc 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/EnterSplitScreenFromOverview.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.service.splitscreen.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.AndroidLoggerSetupRule
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.AndroidLoggerSetupRule
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt
index c9b1c91..babdae1 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchAppByDoubleTapDivider.kt
@@ -18,11 +18,11 @@
 
 import android.app.Instrumentation
 import android.graphics.Point
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.AndroidLoggerSetupRule
-import android.tools.device.helpers.WindowUtils
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.AndroidLoggerSetupRule
+import android.tools.helpers.WindowUtils
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromAnotherApp.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromAnotherApp.kt
index 72f2db3..3e85479 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromAnotherApp.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromAnotherApp.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.service.splitscreen.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.AndroidLoggerSetupRule
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.AndroidLoggerSetupRule
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromHome.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromHome.kt
index 511de4f..655ae4e 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromHome.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromHome.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.service.splitscreen.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.AndroidLoggerSetupRule
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.AndroidLoggerSetupRule
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt
index 558d2bf..2208258 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBackToSplitFromRecent.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.service.splitscreen.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.AndroidLoggerSetupRule
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.AndroidLoggerSetupRule
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBetweenSplitPairs.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBetweenSplitPairs.kt
index ecd68295..2ac63c2 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBetweenSplitPairs.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/SwitchBetweenSplitPairs.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.service.splitscreen.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.AndroidLoggerSetupRule
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.AndroidLoggerSetupRule
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/UnlockKeyguardToSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/UnlockKeyguardToSplitScreen.kt
index f50d5c7..35b122d 100644
--- a/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/UnlockKeyguardToSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/service/src/com/android/wm/shell/flicker/service/splitscreen/scenarios/UnlockKeyguardToSplitScreen.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.service.splitscreen.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.AndroidLoggerSetupRule
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.AndroidLoggerSetupRule
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
index 6b97169..d74c59e 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
@@ -17,12 +17,12 @@
 package com.android.wm.shell.flicker.splitscreen
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.common.traces.component.EdgeExtensionComponentMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.component.EdgeExtensionComponentMatcher
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.splitscreen.benchmark.CopyContentInSplitBenchmark
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt
index 51588569..dd45f65 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt
@@ -18,10 +18,10 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.helpers.WindowUtils
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.helpers.WindowUtils
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.splitscreen.benchmark.DismissSplitScreenByDividerBenchmark
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
index fc6c2b3..6d396ea 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.splitscreen
 
 import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.splitscreen.benchmark.DismissSplitScreenByGoHomeBenchmark
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
index 8b1689a..2ed916e 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.splitscreen
 
 import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.splitscreen.benchmark.DragDividerToResizeBenchmark
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
index 99613f3..1a455311 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
@@ -18,11 +18,11 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.splitscreen.benchmark.EnterSplitScreenByDragFromAllAppsBenchmark
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt
index 756a7fa..0cb1e40 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt
@@ -18,11 +18,11 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.splitscreen.benchmark.EnterSplitScreenByDragFromNotificationBenchmark
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt
index 121b46a..ff406b7 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt
@@ -17,11 +17,11 @@
 package com.android.wm.shell.flicker.splitscreen
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.splitscreen.benchmark.EnterSplitScreenByDragFromShortcutBenchmark
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt
index 99deb92..2b81798 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt
@@ -18,11 +18,11 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.splitscreen.benchmark.EnterSplitScreenByDragFromTaskbarBenchmark
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt
index 212a4e3..186af54 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.splitscreen
 
 import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.splitscreen.benchmark.EnterSplitScreenFromOverviewBenchmark
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
index fac97c8..9dde490 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
@@ -18,11 +18,11 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchAppByDoubleTapDividerBenchmark
 import com.android.wm.shell.flicker.utils.ICommonAssertions
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt
index 284c32e..5222b08 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt
@@ -17,11 +17,11 @@
 package com.android.wm.shell.flicker.splitscreen
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchBackToSplitFromAnotherAppBenchmark
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt
index 9e6448f..a8a8ae8 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt
@@ -17,11 +17,11 @@
 package com.android.wm.shell.flicker.splitscreen
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchBackToSplitFromHomeBenchmark
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt
index 8e28712..836f664 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt
@@ -17,11 +17,11 @@
 package com.android.wm.shell.flicker.splitscreen
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchBackToSplitFromRecentBenchmark
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt
index fb0193b..3c4a1ca 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt
@@ -17,10 +17,10 @@
 package com.android.wm.shell.flicker.splitscreen
 
 import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.splitscreen.benchmark.SwitchBetweenSplitPairsBenchmark
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairsNoPip.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairsNoPip.kt
index 715a533..8724346 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairsNoPip.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairsNoPip.kt
@@ -17,12 +17,12 @@
 package com.android.wm.shell.flicker.splitscreen
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.helpers.PipAppHelper
 import com.android.wm.shell.flicker.splitscreen.benchmark.SplitScreenBase
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt
index e6a2022..16d7331 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/UnlockKeyguardToSplitScreen.kt
@@ -18,14 +18,14 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
-import android.tools.common.flicker.subject.region.RegionSubject
-import android.tools.common.traces.component.ComponentNameMatcher.Companion.WALLPAPER_BBQ_WRAPPER
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.subject.layers.LayersTraceSubject
+import android.tools.flicker.subject.region.RegionSubject
+import android.tools.traces.component.ComponentNameMatcher.Companion.WALLPAPER_BBQ_WRAPPER
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.splitscreen.benchmark.UnlockKeyguardToSplitScreenBenchmark
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt
index df1c9a2..9c5a3fe 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/CopyContentInSplitBenchmark.kt
@@ -16,11 +16,11 @@
 
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.FixMethodOrder
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt
index d01eab0..c99fcc4 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByDividerBenchmark.kt
@@ -16,10 +16,10 @@
 
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.FixMethodOrder
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt
index e36bd33..ef3a879 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DismissSplitScreenByGoHomeBenchmark.kt
@@ -16,10 +16,10 @@
 
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.FixMethodOrder
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt
index 050d389..18550d7 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/DragDividerToResizeBenchmark.kt
@@ -16,10 +16,10 @@
 
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.Assume
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt
index 5c43cbd..d16c5d7 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromAllAppsBenchmark.kt
@@ -16,11 +16,11 @@
 
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.After
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt
index cd3fbab..f8be6be 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromNotificationBenchmark.kt
@@ -16,11 +16,11 @@
 
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.Assume
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt
index 15ad0c1..a99ef64 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromShortcutBenchmark.kt
@@ -16,11 +16,11 @@
 
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.After
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt
index ca8adb1..f584009 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenByDragFromTaskbarBenchmark.kt
@@ -16,11 +16,11 @@
 
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.After
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt
index 5e5e7d7..7084f6a 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/EnterSplitScreenFromOverviewBenchmark.kt
@@ -16,10 +16,10 @@
 
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.FixMethodOrder
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SplitScreenBase.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SplitScreenBase.kt
index a0e437c..4b10603 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SplitScreenBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SplitScreenBase.kt
@@ -17,8 +17,8 @@
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
 import android.content.Context
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.wm.shell.flicker.BaseBenchmarkTest
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt
index e39c3c9..38206c3 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt
@@ -16,14 +16,14 @@
 
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.WindowUtils
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.helpers.WindowUtils
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.FixMethodOrder
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt
index 32284ba..3a2316f 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromAnotherAppBenchmark.kt
@@ -16,11 +16,11 @@
 
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.FixMethodOrder
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt
index a926ec9..ded0b07 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromHomeBenchmark.kt
@@ -16,11 +16,11 @@
 
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.FixMethodOrder
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt
index d2e1d52..7b1397b 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBackToSplitFromRecentBenchmark.kt
@@ -16,11 +16,11 @@
 
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.FixMethodOrder
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt
index 9d6b251..457288f 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchBetweenSplitPairsBenchmark.kt
@@ -16,10 +16,10 @@
 
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.FixMethodOrder
diff --git a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/UnlockKeyguardToSplitScreenBenchmark.kt b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/UnlockKeyguardToSplitScreenBenchmark.kt
index e71834d..7493538 100644
--- a/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/UnlockKeyguardToSplitScreenBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/flicker/splitscreen/src/com/android/wm/shell/flicker/splitscreen/benchmark/UnlockKeyguardToSplitScreenBenchmark.kt
@@ -16,11 +16,11 @@
 
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
-import android.tools.common.NavBar
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
 import org.junit.FixMethodOrder
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseBenchmarkTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseBenchmarkTest.kt
index e9363f7..d03c2f1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseBenchmarkTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseBenchmarkTest.kt
@@ -17,9 +17,9 @@
 package com.android.wm.shell.flicker
 
 import android.app.Instrumentation
-import android.tools.device.flicker.junit.FlickerBuilderProvider
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.junit.FlickerBuilderProvider
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.tapl.LauncherInstrumentation
 
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt
index 568650d..a19d232 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt
@@ -17,8 +17,8 @@
 package com.android.wm.shell.flicker
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.legacy.LegacyFlickerTest
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.tapl.LauncherInstrumentation
 import com.android.wm.shell.flicker.utils.ICommonAssertions
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonAssertions.kt
index f1cb37e..3df0954 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonAssertions.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonAssertions.kt
@@ -18,13 +18,13 @@
 
 package com.android.wm.shell.flicker.utils
 
-import android.tools.common.Rotation
-import android.tools.common.datatypes.Region
-import android.tools.common.flicker.subject.layers.LayerTraceEntrySubject
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
-import android.tools.common.traces.component.IComponentMatcher
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.helpers.WindowUtils
+import android.tools.Rotation
+import android.tools.datatypes.Region
+import android.tools.flicker.subject.layers.LayerTraceEntrySubject
+import android.tools.flicker.subject.layers.LayersTraceSubject
+import android.tools.traces.component.IComponentMatcher
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.helpers.WindowUtils
 
 fun LegacyFlickerTest.appPairsDividerIsVisibleAtEnd() {
     assertLayersEnd { this.isVisible(APP_PAIR_SPLIT_DIVIDER_COMPONENT) }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonConstants.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonConstants.kt
index 3b66d6a..fb21fcc 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonConstants.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/CommonConstants.kt
@@ -18,7 +18,7 @@
 
 package com.android.wm.shell.flicker.utils
 
-import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.traces.component.ComponentNameMatcher
 
 const val SYSTEM_UI_PACKAGE_NAME = "com.android.systemui"
 const val LAUNCHER_UI_PACKAGE_NAME = "com.google.android.apps.nexuslauncher"
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/ICommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/ICommonAssertions.kt
index 7f58ced..50c0435 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/ICommonAssertions.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/ICommonAssertions.kt
@@ -17,8 +17,8 @@
 package com.android.wm.shell.flicker.utils
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.flicker.legacy.LegacyFlickerTest
 import com.android.server.wm.flicker.entireScreenCovered
 import com.android.server.wm.flicker.navBarLayerIsVisibleAtStartAndEnd
 import com.android.server.wm.flicker.navBarLayerPositionAtStartAndEnd
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt
index 3244ebc..4e9a9d6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt
@@ -19,14 +19,14 @@
 import android.app.Instrumentation
 import android.graphics.Point
 import android.os.SystemClock
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.common.traces.component.IComponentMatcher
-import android.tools.common.traces.component.IComponentNameMatcher
+import android.tools.Rotation
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.component.IComponentMatcher
+import android.tools.traces.component.IComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.flicker.rules.ChangeDisplayOrientationRule
-import android.tools.device.traces.parsers.WindowManagerStateHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.flicker.rules.ChangeDisplayOrientationRule
+import android.tools.traces.parsers.WindowManagerStateHelper
+import android.tools.traces.parsers.toFlickerComponent
 import android.view.InputDevice
 import android.view.MotionEvent
 import android.view.ViewConfiguration
diff --git a/libs/WindowManager/Shell/tests/unittest/Android.bp b/libs/WindowManager/Shell/tests/unittest/Android.bp
index 8c47116..32c0703 100644
--- a/libs/WindowManager/Shell/tests/unittest/Android.bp
+++ b/libs/WindowManager/Shell/tests/unittest/Android.bp
@@ -24,7 +24,10 @@
 
 android_test {
     name: "WMShellUnitTests",
-
+    defaults: [
+        // For ExtendedMockito dependencies.
+        "modules-utils-testable-device-config-defaults",
+    ],
     srcs: [
         "**/*.java",
         "**/*.kt",
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeEventLoggerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeEventLoggerTest.kt
new file mode 100644
index 0000000..4548fcb
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeEventLoggerTest.kt
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2024 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.wm.shell.desktopmode
+
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.internal.util.FrameworkStatsLog
+import com.android.modules.utils.testing.ExtendedMockitoRule
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.EnterReason
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ExitReason
+import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.TaskUpdate
+import kotlinx.coroutines.runBlocking
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.mockito.kotlin.eq
+
+/**
+ * Tests for [DesktopModeEventLogger].
+ */
+class DesktopModeEventLoggerTest {
+
+    private val desktopModeEventLogger  = DesktopModeEventLogger()
+
+    @JvmField
+    @Rule
+    val extendedMockitoRule = ExtendedMockitoRule.Builder(this)
+            .mockStatic(FrameworkStatsLog::class.java).build()!!
+
+    @Test
+    fun logSessionEnter_enterReason() = runBlocking {
+        desktopModeEventLogger.logSessionEnter(sessionId = SESSION_ID, EnterReason.UNKNOWN_ENTER)
+
+        ExtendedMockito.verify {
+            FrameworkStatsLog.write(
+                eq(FrameworkStatsLog.DESKTOP_MODE_UI_CHANGED),
+                /* event */
+                eq(FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EVENT__ENTER),
+                /* enter_reason */
+                eq(FrameworkStatsLog.DESKTOP_MODE_UICHANGED__ENTER_REASON__UNKNOWN_ENTER),
+                /* exit_reason */
+                eq(0),
+                /* sessionId */
+                eq(SESSION_ID)
+            )
+        }
+    }
+
+    @Test
+    fun logSessionExit_exitReason() = runBlocking {
+        desktopModeEventLogger.logSessionExit(sessionId = SESSION_ID, ExitReason.UNKNOWN_EXIT)
+
+        ExtendedMockito.verify {
+            FrameworkStatsLog.write(
+                eq(FrameworkStatsLog.DESKTOP_MODE_UI_CHANGED),
+                /* event */
+                eq(FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EVENT__EXIT),
+                /* enter_reason */
+                eq(0),
+                /* exit_reason */
+                eq(FrameworkStatsLog.DESKTOP_MODE_UICHANGED__EXIT_REASON__UNKNOWN_EXIT),
+                /* sessionId */
+                eq(SESSION_ID)
+            )
+        }
+    }
+
+    @Test
+    fun logTaskAdded_taskUpdate() = runBlocking {
+        desktopModeEventLogger.logTaskAdded(sessionId = SESSION_ID, TASK_UPDATE)
+
+        ExtendedMockito.verify {
+            FrameworkStatsLog.write(eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE),
+                /* task_event */
+                eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_ADDED),
+                /* instance_id */
+                eq(TASK_UPDATE.instanceId),
+                /* uid */
+                eq(TASK_UPDATE.uid),
+                /* task_height */
+                eq(TASK_UPDATE.taskHeight),
+                /* task_width */
+                eq(TASK_UPDATE.taskWidth),
+                /* task_x */
+                eq(TASK_UPDATE.taskX),
+                /* task_y */
+                eq(TASK_UPDATE.taskY),
+                /* session_id */
+                eq(SESSION_ID))
+        }
+    }
+
+    @Test
+    fun logTaskRemoved_taskUpdate() = runBlocking {
+        desktopModeEventLogger.logTaskRemoved(sessionId = SESSION_ID, TASK_UPDATE)
+
+        ExtendedMockito.verify {
+            FrameworkStatsLog.write(eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE),
+                /* task_event */
+                eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_REMOVED),
+                /* instance_id */
+                eq(TASK_UPDATE.instanceId),
+                /* uid */
+                eq(TASK_UPDATE.uid),
+                /* task_height */
+                eq(TASK_UPDATE.taskHeight),
+                /* task_width */
+                eq(TASK_UPDATE.taskWidth),
+                /* task_x */
+                eq(TASK_UPDATE.taskX),
+                /* task_y */
+                eq(TASK_UPDATE.taskY),
+                /* session_id */
+                eq(SESSION_ID))
+        }
+    }
+
+    @Test
+    fun logTaskInfoChanged_taskUpdate() = runBlocking {
+        desktopModeEventLogger.logTaskInfoChanged(sessionId = SESSION_ID, TASK_UPDATE)
+
+        ExtendedMockito.verify {
+            FrameworkStatsLog.write(eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE),
+                /* task_event */
+                eq(FrameworkStatsLog.DESKTOP_MODE_SESSION_TASK_UPDATE__TASK_EVENT__TASK_INFO_CHANGED),
+                /* instance_id */
+                eq(TASK_UPDATE.instanceId),
+                /* uid */
+                eq(TASK_UPDATE.uid),
+                /* task_height */
+                eq(TASK_UPDATE.taskHeight),
+                /* task_width */
+                eq(TASK_UPDATE.taskWidth),
+                /* task_x */
+                eq(TASK_UPDATE.taskX),
+                /* task_y */
+                eq(TASK_UPDATE.taskY),
+                /* session_id */
+                eq(SESSION_ID))
+        }
+    }
+
+    companion object {
+        private const val SESSION_ID = 1
+        private const val TASK_ID = 1
+        private const val TASK_UID = 1
+        private const val TASK_X = 0
+        private const val TASK_Y = 0
+        private const val TASK_HEIGHT = 100
+        private const val TASK_WIDTH = 100
+
+        private val TASK_UPDATE = TaskUpdate(
+            TASK_ID, TASK_UID, TASK_HEIGHT, TASK_WIDTH, TASK_X, TASK_Y
+        )
+    }
+}
\ No newline at end of file
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index abd84de..40239b8 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -428,6 +428,7 @@
                 "jni/MovieImpl.cpp",
                 "jni/pdf/PdfDocument.cpp",
                 "jni/pdf/PdfEditor.cpp",
+                "jni/pdf/PdfRenderer.cpp",
                 "jni/pdf/PdfUtils.cpp",
             ],
             shared_libs: [
diff --git a/libs/hwui/DisplayListOps.in b/libs/hwui/DisplayListOps.in
index d21f07ef..b12486e 100644
--- a/libs/hwui/DisplayListOps.in
+++ b/libs/hwui/DisplayListOps.in
@@ -26,6 +26,7 @@
 X(ClipRect)
 X(ClipRRect)
 X(ClipRegion)
+X(ClipShader)
 X(ResetClip)
 X(DrawPaint)
 X(DrawBehind)
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 3b694c5..54aef55 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -207,6 +207,13 @@
     SkClipOp op;
     void draw(SkCanvas* c, const SkMatrix&) const { c->clipRegion(region, op); }
 };
+struct ClipShader final : Op {
+    static const auto kType = Type::ClipShader;
+    ClipShader(const sk_sp<SkShader>& shader, SkClipOp op) : shader(shader), op(op) {}
+    sk_sp<SkShader> shader;
+    SkClipOp op;
+    void draw(SkCanvas* c, const SkMatrix&) const { c->clipShader(shader, op); }
+};
 struct ResetClip final : Op {
     static const auto kType = Type::ResetClip;
     ResetClip() {}
@@ -822,6 +829,9 @@
 void DisplayListData::clipRegion(const SkRegion& region, SkClipOp op) {
     this->push<ClipRegion>(0, region, op);
 }
+void DisplayListData::clipShader(const sk_sp<SkShader>& shader, SkClipOp op) {
+    this->push<ClipShader>(0, shader, op);
+}
 void DisplayListData::resetClip() {
     this->push<ResetClip>(0);
 }
@@ -1134,6 +1144,11 @@
     fDL->clipRegion(region, op);
     this->INHERITED::onClipRegion(region, op);
 }
+void RecordingCanvas::onClipShader(sk_sp<SkShader> shader, SkClipOp op) {
+    setClipMayBeComplex();
+    fDL->clipShader(shader, op);
+    this->INHERITED::onClipShader(shader, op);
+}
 void RecordingCanvas::onResetClip() {
     // This is part of "replace op" emulation, but rely on the following intersection
     // clip to potentially mark the clip as complex. If we are already complex, we do
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index afadbfd..965264f 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -140,6 +140,7 @@
     void translateZ(SkScalar);
 
     void clipPath(const SkPath&, SkClipOp, bool aa);
+    void clipShader(const sk_sp<SkShader>& shader, SkClipOp);
     void clipRect(const SkRect&, SkClipOp, bool aa);
     void clipRRect(const SkRRect&, SkClipOp, bool aa);
     void clipRegion(const SkRegion&, SkClipOp);
@@ -216,6 +217,7 @@
     void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override;
     void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override;
     void onClipPath(const SkPath&, SkClipOp, ClipEdgeStyle) override;
+    void onClipShader(sk_sp<SkShader>, SkClipOp) override;
     void onClipRegion(const SkRegion&, SkClipOp) override;
     void onResetClip() override;
 
diff --git a/libs/hwui/apex/jni_runtime.cpp b/libs/hwui/apex/jni_runtime.cpp
index fb0cdb0..883f273 100644
--- a/libs/hwui/apex/jni_runtime.cpp
+++ b/libs/hwui/apex/jni_runtime.cpp
@@ -70,6 +70,7 @@
 extern int register_android_graphics_fonts_FontFamily(JNIEnv* env);
 extern int register_android_graphics_pdf_PdfDocument(JNIEnv* env);
 extern int register_android_graphics_pdf_PdfEditor(JNIEnv* env);
+extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env);
 extern int register_android_graphics_text_MeasuredText(JNIEnv* env);
 extern int register_android_graphics_text_LineBreaker(JNIEnv *env);
 extern int register_android_graphics_text_TextShaper(JNIEnv *env);
@@ -141,6 +142,7 @@
             REG_JNI(register_android_graphics_fonts_FontFamily),
             REG_JNI(register_android_graphics_pdf_PdfDocument),
             REG_JNI(register_android_graphics_pdf_PdfEditor),
+            REG_JNI(register_android_graphics_pdf_PdfRenderer),
             REG_JNI(register_android_graphics_text_MeasuredText),
             REG_JNI(register_android_graphics_text_LineBreaker),
             REG_JNI(register_android_graphics_text_TextShaper),
diff --git a/libs/hwui/jni/pdf/PdfRenderer.cpp b/libs/hwui/jni/pdf/PdfRenderer.cpp
new file mode 100644
index 0000000..cc1f961
--- /dev/null
+++ b/libs/hwui/jni/pdf/PdfRenderer.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#include "PdfUtils.h"
+
+#include "GraphicsJNI.h"
+#include "SkBitmap.h"
+#include "SkMatrix.h"
+#include "fpdfview.h"
+
+#include <vector>
+#include <utils/Log.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace android {
+
+static const int RENDER_MODE_FOR_DISPLAY = 1;
+static const int RENDER_MODE_FOR_PRINT = 2;
+
+static struct {
+    jfieldID x;
+    jfieldID y;
+} gPointClassInfo;
+
+static jlong nativeOpenPageAndGetSize(JNIEnv* env, jclass thiz, jlong documentPtr,
+        jint pageIndex, jobject outSize) {
+    FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+
+    FPDF_PAGE page = FPDF_LoadPage(document, pageIndex);
+    if (!page) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                "cannot load page");
+        return -1;
+    }
+
+    double width = 0;
+    double height = 0;
+
+    int result = FPDF_GetPageSizeByIndex(document, pageIndex, &width, &height);
+    if (!result) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                    "cannot get page size");
+        return -1;
+    }
+
+    env->SetIntField(outSize, gPointClassInfo.x, width);
+    env->SetIntField(outSize, gPointClassInfo.y, height);
+
+    return reinterpret_cast<jlong>(page);
+}
+
+static void nativeClosePage(JNIEnv* env, jclass thiz, jlong pagePtr) {
+    FPDF_PAGE page = reinterpret_cast<FPDF_PAGE>(pagePtr);
+    FPDF_ClosePage(page);
+}
+
+static void nativeRenderPage(JNIEnv* env, jclass thiz, jlong documentPtr, jlong pagePtr,
+        jlong bitmapPtr, jint clipLeft, jint clipTop, jint clipRight, jint clipBottom,
+        jlong transformPtr, jint renderMode) {
+    FPDF_PAGE page = reinterpret_cast<FPDF_PAGE>(pagePtr);
+
+    SkBitmap skBitmap;
+    bitmap::toBitmap(bitmapPtr).getSkBitmap(&skBitmap);
+
+    const int stride = skBitmap.width() * 4;
+
+    FPDF_BITMAP bitmap = FPDFBitmap_CreateEx(skBitmap.width(), skBitmap.height(),
+            FPDFBitmap_BGRA, skBitmap.getPixels(), stride);
+
+    int renderFlags = FPDF_REVERSE_BYTE_ORDER;
+    if (renderMode == RENDER_MODE_FOR_DISPLAY) {
+        renderFlags |= FPDF_LCD_TEXT;
+    } else if (renderMode == RENDER_MODE_FOR_PRINT) {
+        renderFlags |= FPDF_PRINTING;
+    }
+
+    SkMatrix matrix = *reinterpret_cast<SkMatrix*>(transformPtr);
+    SkScalar transformValues[6];
+    if (!matrix.asAffine(transformValues)) {
+        jniThrowException(env, "java/lang/IllegalArgumentException",
+                "transform matrix has perspective. Only affine matrices are allowed.");
+        return;
+    }
+
+    FS_MATRIX transform = {transformValues[SkMatrix::kAScaleX], transformValues[SkMatrix::kASkewY],
+                           transformValues[SkMatrix::kASkewX], transformValues[SkMatrix::kAScaleY],
+                           transformValues[SkMatrix::kATransX],
+                           transformValues[SkMatrix::kATransY]};
+
+    FS_RECTF clip = {(float) clipLeft, (float) clipTop, (float) clipRight, (float) clipBottom};
+
+    FPDF_RenderPageBitmapWithMatrix(bitmap, page, &transform, &clip, renderFlags);
+
+    skBitmap.notifyPixelsChanged();
+}
+
+static const JNINativeMethod gPdfRenderer_Methods[] = {
+    {"nativeCreate", "(IJ)J", (void*) nativeOpen},
+    {"nativeClose", "(J)V", (void*) nativeClose},
+    {"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount},
+    {"nativeScaleForPrinting", "(J)Z", (void*) nativeScaleForPrinting},
+    {"nativeRenderPage", "(JJJIIIIJI)V", (void*) nativeRenderPage},
+    {"nativeOpenPageAndGetSize", "(JILandroid/graphics/Point;)J", (void*) nativeOpenPageAndGetSize},
+    {"nativeClosePage", "(J)V", (void*) nativeClosePage}
+};
+
+int register_android_graphics_pdf_PdfRenderer(JNIEnv* env) {
+    int result = RegisterMethodsOrDie(
+            env, "android/graphics/pdf/PdfRenderer", gPdfRenderer_Methods,
+            NELEM(gPdfRenderer_Methods));
+
+    jclass clazz = FindClassOrDie(env, "android/graphics/Point");
+    gPointClassInfo.x = GetFieldIDOrDie(env, clazz, "x", "I");
+    gPointClassInfo.y = GetFieldIDOrDie(env, clazz, "y", "I");
+
+    return result;
+};
+
+};
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index f84107e..f9dc5fa 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -41,6 +41,8 @@
 
 namespace {
 
+static const bool ENABLE_POINTER_CHOREOGRAPHER = input_flags::enable_pointer_choreographer();
+
 const ui::Transform kIdentityTransform;
 
 } // namespace
@@ -224,7 +226,7 @@
 
     mLocked.presentation = presentation;
 
-    if (input_flags::enable_pointer_choreographer()) {
+    if (ENABLE_POINTER_CHOREOGRAPHER) {
         // When pointer choreographer is enabled, the presentation mode is only set once when the
         // PointerController is constructed, before the display viewport is provided.
         // TODO(b/293587049): Clean up the PointerController interface after pointer choreographer
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index ea136ed..c90c441 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -1079,7 +1079,7 @@
      * @return one of the values that can be set in {@link Builder#setEncoding(int)} or
      * {@link AudioFormat#ENCODING_INVALID} if not set.
      */
-    public @Encoding int getEncoding() {
+    public @EncodingCanBeInvalid int getEncoding() {
         return mEncoding;
     }
 
@@ -1486,6 +1486,44 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface Encoding {}
 
+    /** @hide same as @Encoding, but adding ENCODING_INVALID */
+    @IntDef(flag = false, prefix = "ENCODING", value = {
+            ENCODING_INVALID,
+            ENCODING_DEFAULT,
+            ENCODING_PCM_16BIT,
+            ENCODING_PCM_8BIT,
+            ENCODING_PCM_FLOAT,
+            ENCODING_AC3,
+            ENCODING_E_AC3,
+            ENCODING_DTS,
+            ENCODING_DTS_HD,
+            ENCODING_MP3,
+            ENCODING_AAC_LC,
+            ENCODING_AAC_HE_V1,
+            ENCODING_AAC_HE_V2,
+            ENCODING_IEC61937,
+            ENCODING_DOLBY_TRUEHD,
+            ENCODING_AAC_ELD,
+            ENCODING_AAC_XHE,
+            ENCODING_AC4,
+            ENCODING_E_AC3_JOC,
+            ENCODING_DOLBY_MAT,
+            ENCODING_OPUS,
+            ENCODING_PCM_24BIT_PACKED,
+            ENCODING_PCM_32BIT,
+            ENCODING_MPEGH_BL_L3,
+            ENCODING_MPEGH_BL_L4,
+            ENCODING_MPEGH_LC_L3,
+            ENCODING_MPEGH_LC_L4,
+            ENCODING_DTS_UHD_P1,
+            ENCODING_DRA,
+            ENCODING_DTS_HD_MA,
+            ENCODING_DTS_UHD_P2,
+            ENCODING_DSD }
+    )
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface EncodingCanBeInvalid {}
+
     /** @hide */
     public static final int[] SURROUND_SOUND_ENCODING = {
             ENCODING_AC3,
diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java
index d145397..ed543e6 100644
--- a/media/java/android/media/tv/ITvInputSessionWrapper.java
+++ b/media/java/android/media/tv/ITvInputSessionWrapper.java
@@ -519,7 +519,7 @@
 
     @Override
     public void stopPlayback(int mode) {
-        mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_STOP_PLAYBACK, mode));
+        mCaller.executeOrSendMessage(mCaller.obtainMessageI(DO_STOP_PLAYBACK, mode));
     }
 
     @Override
diff --git a/nfc/api/current.txt b/nfc/api/current.txt
index 7b53ca6..0fb7c95 100644
--- a/nfc/api/current.txt
+++ b/nfc/api/current.txt
@@ -204,7 +204,7 @@
     method public boolean isDefaultServiceForAid(android.content.ComponentName, String);
     method public boolean isDefaultServiceForCategory(android.content.ComponentName, String);
     method public boolean registerAidsForService(android.content.ComponentName, String, java.util.List<java.lang.String>);
-    method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean registerPollingLoopFilterForService(@NonNull android.content.ComponentName, @NonNull String);
+    method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean registerPollingLoopFilterForService(@NonNull android.content.ComponentName, @NonNull String, boolean);
     method public boolean removeAidsForService(android.content.ComponentName, String);
     method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean setDefaultToObserveModeForService(@NonNull android.content.ComponentName, boolean);
     method @NonNull @RequiresPermission(android.Manifest.permission.NFC) public boolean setOffHostForService(@NonNull android.content.ComponentName, @NonNull String);
diff --git a/nfc/java/android/nfc/INfcCardEmulation.aidl b/nfc/java/android/nfc/INfcCardEmulation.aidl
index 65d0625..64f7fa4 100644
--- a/nfc/java/android/nfc/INfcCardEmulation.aidl
+++ b/nfc/java/android/nfc/INfcCardEmulation.aidl
@@ -32,7 +32,7 @@
     boolean setDefaultForNextTap(int userHandle, in ComponentName service);
     boolean setDefaultToObserveModeForService(int userId, in android.content.ComponentName service, boolean enable);
     boolean registerAidGroupForService(int userHandle, in ComponentName service, in AidGroup aidGroup);
-    boolean registerPollingLoopFilterForService(int userHandle, in ComponentName service, in String pollingLoopFilter);
+    boolean registerPollingLoopFilterForService(int userHandle, in ComponentName service, in String pollingLoopFilter, boolean autoTransact);
     boolean setOffHostForService(int userHandle, in ComponentName service, in String offHostSecureElement);
     boolean unsetOffHostForService(int userHandle, in ComponentName service);
     AidGroup getAidGroupForService(int userHandle, in ComponentName service, String category);
diff --git a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
index c81b95b..e62e37b 100644
--- a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -681,34 +681,18 @@
 
     /**
      * Add a Polling Loop Filter. Custom NFC polling frames that match this filter will be
-     * delivered to {@link HostApduService#processPollingFrames(List)}. Adding a key with this or
-     * {@link  ApduServiceInfo#addPollingLoopFilterToAutoTransact(String)} multiple times will
-     * cause the value to be overwritten each time.
+     * delivered to {@link HostApduService#processPollingFrames(List)}. Adding a key with this
+     * multiple times will cause the value to be overwritten each time.
      * @param pollingLoopFilter the polling loop filter to add, must be a  valide hexadecimal string
      */
     @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
-    public void addPollingLoopFilter(@NonNull String pollingLoopFilter) {
-        mAutoTransact.put(pollingLoopFilter.toUpperCase(Locale.ROOT), false);
+    public void addPollingLoopFilter(@NonNull String pollingLoopFilter,
+            boolean autoTransact) {
+        mAutoTransact.put(pollingLoopFilter, autoTransact);
 
     }
 
     /**
-     * Add a Polling Loop Filter. Custom NFC polling frames that match this filter will cause the
-     * device to exit observe mode, just as if
-     * {@link android.nfc.NfcAdapter#setObserveModeEnabled(boolean)} had been called with true,
-     * allowing transactions to proceed. The matching frame will also be delivered to
-     * {@link HostApduService#processPollingFrames(List)}. Adding a key with this or
-     * {@link  ApduServiceInfo#addPollingLoopFilter(String)} multiple times will
-     * cause the value to be overwritten each time.
-     *
-     * @param pollingLoopFilter the polling loop filter to add, must be a  valide hexadecimal string
-     */
-    @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
-    public void addPollingLoopFilterToAutoTransact(@NonNull String pollingLoopFilter) {
-        mAutoTransact.put(pollingLoopFilter.toUpperCase(Locale.ROOT), true);
-    }
-
-    /**
      * Remove a Polling Loop Filter. Custom NFC polling frames that match this filter will no
      * longer be delivered to {@link HostApduService#processPollingFrames(List)}.
      * @param pollingLoopFilter this polling loop filter to add.
diff --git a/nfc/java/android/nfc/cardemulation/CardEmulation.java b/nfc/java/android/nfc/cardemulation/CardEmulation.java
index e681a85..47ddd9d 100644
--- a/nfc/java/android/nfc/cardemulation/CardEmulation.java
+++ b/nfc/java/android/nfc/cardemulation/CardEmulation.java
@@ -42,6 +42,7 @@
 import android.util.Log;
 
 import java.util.HashMap;
+import java.util.HexFormat;
 import java.util.List;
 import java.util.regex.Pattern;
 
@@ -59,7 +60,6 @@
  */
 public final class CardEmulation {
     private static final Pattern AID_PATTERN = Pattern.compile("[0-9A-Fa-f]{10,32}\\*?\\#?");
-    private static final Pattern PLF_PATTERN = Pattern.compile("[0-9A-Fa-f]{1,32}");
 
     static final String TAG = "CardEmulation";
 
@@ -360,21 +360,28 @@
     }
 
     /**
-     * Register a polling loop filter (PLF) for a HostApduService. The PLF can be sequence of an
-     * even number of hexadecimal numbers (0-9, A-F or a-f). When non-standard polling loop frame
-     * matches this sequence exactly, it may be delivered to
-     * {@link HostApduService#processPollingFrames(List)}  if this service is currently
-     * preferred or there are no other services registered for this filter.
+     * Register a polling loop filter (PLF) for a HostApduService and indicate whether it should
+     * auto-transact or not.  The PLF can be sequence of an
+     * even number of at least 2 hexadecimal numbers (0-9, A-F or a-f), representing a series of
+     * bytes. When non-standard polling loop frame matches this sequence exactly, it may be
+     * delivered to {@link HostApduService#processPollingFrames(List)}. If auto-transact is set to
+     * true, then observe mode will also be disabled.  if this service is currently preferred or
+     * there are no other services registered for this filter.
      * @param service The HostApduService to register the filter for
      * @param pollingLoopFilter The filter to register
+     * @param autoTransact true to have the NFC stack automatically disable observe mode and allow
+     *         transactions to proceed when this filter matches, false otherwise
      * @return true if the filter was registered, false otherwise
+     * @throws IllegalArgumentException if the passed in string doesn't parse to at least one byte
      */
     @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
     public boolean registerPollingLoopFilterForService(@NonNull ComponentName service,
-            @NonNull String pollingLoopFilter) {
+            @NonNull String pollingLoopFilter, boolean autoTransact) {
+        pollingLoopFilter = validatePollingLoopFilter(pollingLoopFilter);
+
         try {
             return sService.registerPollingLoopFilterForService(mContext.getUser().getIdentifier(),
-                    service, pollingLoopFilter);
+                    service, pollingLoopFilter, autoTransact);
         } catch (RemoteException e) {
             // Try one more time
             recoverService();
@@ -384,7 +391,8 @@
             }
             try {
                 return sService.registerPollingLoopFilterForService(
-                        mContext.getUser().getIdentifier(), service, pollingLoopFilter);
+                        mContext.getUser().getIdentifier(), service,
+                        pollingLoopFilter, autoTransact);
             } catch (RemoteException ee) {
                 Log.e(TAG, "Failed to reach CardEmulationService.");
                 return false;
@@ -979,15 +987,14 @@
      * @hide
      */
     @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
-    public static boolean isValidPollingLoopFilter(@NonNull String pollingLoopFilter) {
+    public static @NonNull String validatePollingLoopFilter(@NonNull String pollingLoopFilter) {
         // Verify hex characters
-        if (!PLF_PATTERN.matcher(pollingLoopFilter).matches()) {
-            Log.e(TAG, "Polling Loop Filter " + pollingLoopFilter
-                    + " is not a valid Polling Loop Filter.");
-            return false;
+        byte[] plfBytes = HexFormat.of().parseHex(pollingLoopFilter);
+        if (plfBytes.length == 0) {
+            throw new IllegalArgumentException(
+                "Polling loop filter must contain at least one byte.");
         }
-
-        return true;
+        return HexFormat.of().withUpperCase().formatHex(plfBytes);
     }
 
     /**
diff --git a/packages/CrashRecovery/framework/Android.bp b/packages/CrashRecovery/framework/Android.bp
index c0d93531..9480327 100644
--- a/packages/CrashRecovery/framework/Android.bp
+++ b/packages/CrashRecovery/framework/Android.bp
@@ -3,7 +3,7 @@
     module_type: "filegroup",
     config_namespace: "ANDROID",
     bool_variables: [
-        "move_crashrecovery_files",
+        "crashrecovery_files_in_platform",
     ],
     properties: [
         "srcs",
@@ -12,14 +12,13 @@
 
 platform_filegroup {
     name: "framework-crashrecovery-sources",
-    srcs: [
-        "java/**/*.java",
-        "java/**/*.aidl",
-    ],
     soong_config_variables: {
-        // if the flag is enabled, then files would be moved to module
-        move_crashrecovery_files: {
-            srcs: [],
+        // if this flag is enabled, then files are part of platform
+        crashrecovery_files_in_platform: {
+            srcs: [
+                "java/**/*.java",
+                "java/**/*.aidl",
+            ],
         },
     },
     path: "java",
@@ -31,7 +30,7 @@
     module_type: "filegroup",
     config_namespace: "ANDROID",
     bool_variables: [
-        "move_crashrecovery_files",
+        "crashrecovery_files_in_module",
     ],
     properties: [
         "srcs",
@@ -40,10 +39,9 @@
 
 module_filegroup {
     name: "framework-crashrecovery-module-sources",
-    srcs: [],
     soong_config_variables: {
-        // if the flag is enabled, then files would be moved to module
-        move_crashrecovery_files: {
+        // if this flag is enabled, then files are part of module
+        crashrecovery_files_in_module: {
             srcs: [
                 "java/**/*.java",
                 "java/**/*.aidl",
diff --git a/packages/CrashRecovery/services/Android.bp b/packages/CrashRecovery/services/Android.bp
index ab10b5a..961b41f 100644
--- a/packages/CrashRecovery/services/Android.bp
+++ b/packages/CrashRecovery/services/Android.bp
@@ -3,7 +3,7 @@
     module_type: "filegroup",
     config_namespace: "ANDROID",
     bool_variables: [
-        "move_crashrecovery_files",
+        "crashrecovery_files_in_platform",
     ],
     properties: [
         "srcs",
@@ -12,15 +12,14 @@
 
 platform_filegroup {
     name: "services-crashrecovery-sources",
-    srcs: [
-        "java/**/*.java",
-        "java/**/*.aidl",
-        ":statslog-crashrecovery-java-gen",
-    ],
     soong_config_variables: {
-        // if the flag is enabled, then files would be moved to module
-        move_crashrecovery_files: {
-            srcs: [],
+        // if this flag is enabled, then files are part of platform
+        crashrecovery_files_in_platform: {
+            srcs: [
+                "java/**/*.java",
+                "java/**/*.aidl",
+                ":statslog-crashrecovery-java-gen",
+            ],
         },
     },
     visibility: ["//frameworks/base:__subpackages__"],
@@ -31,7 +30,7 @@
     module_type: "filegroup",
     config_namespace: "ANDROID",
     bool_variables: [
-        "move_crashrecovery_files",
+        "crashrecovery_files_in_module",
     ],
     properties: [
         "srcs",
@@ -40,10 +39,9 @@
 
 module_filegroup {
     name: "services-crashrecovery-module-sources",
-    srcs: [],
     soong_config_variables: {
-        // if the flag is enabled, then files would be moved to module
-        move_crashrecovery_files: {
+        // if this flag is enabled, then files are part of module
+        crashrecovery_files_in_module: {
             srcs: [
                 "java/**/*.java",
                 "java/**/*.aidl",
diff --git a/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java b/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java
index ce8fb65..5d71b7d 100644
--- a/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java
+++ b/packages/CrashRecovery/services/java/com/android/server/PackageWatchdog.java
@@ -38,13 +38,13 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
+import android.util.BackgroundThread;
 import android.util.LongArrayQueue;
 import android.util.Slog;
 import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.XmlUtils;
 import com.android.modules.utils.TypedXmlPullParser;
diff --git a/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index 5fb47dd..0fb9327 100644
--- a/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/packages/CrashRecovery/services/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -75,6 +75,9 @@
     private static final int PERSISTENT_MASK = ApplicationInfo.FLAG_PERSISTENT
             | ApplicationInfo.FLAG_SYSTEM;
 
+    private static final String PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG =
+            "persist.device_config.configuration.disable_high_impact_rollback";
+
     private final Context mContext;
     private final Handler mHandler;
     private final ApexManager mApexManager;
@@ -605,6 +608,10 @@
             // Apply all available low impact rollbacks.
             mHandler.post(() -> rollbackAllLowImpact(availableRollbacks, rollbackReason));
         } else if (minRollbackImpactLevel == PackageManager.ROLLBACK_USER_IMPACT_HIGH) {
+            // Check disable_high_impact_rollback device config before performing rollback
+            if (SystemProperties.getBoolean(PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG, false)) {
+                return;
+            }
             // Rollback one package at a time. If that doesn't resolve the issue, rollback
             // next with same impact level.
             mHandler.post(() -> rollbackHighImpact(availableRollbacks, rollbackReason));
@@ -718,7 +725,9 @@
                 impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_70;
                 break;
             case PackageManager.ROLLBACK_USER_IMPACT_HIGH:
-                impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_90;
+                if (!SystemProperties.getBoolean(PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG, false)) {
+                    impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_90;
+                }
                 break;
             default:
                 impact = PackageHealthObserverImpact.USER_IMPACT_LEVEL_0;
diff --git a/packages/CrashRecovery/services/java/com/android/util/BackgroundThread.java b/packages/CrashRecovery/services/java/com/android/util/BackgroundThread.java
new file mode 100644
index 0000000..a6ae68f
--- /dev/null
+++ b/packages/CrashRecovery/services/java/com/android/util/BackgroundThread.java
@@ -0,0 +1,103 @@
+/*
+ *  * Copyright (C) 2024 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 android.util;
+
+import android.annotation.NonNull;
+import android.os.Handler;
+import android.os.HandlerThread;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Thread for asynchronous event processing. This thread is configured as
+ * {@link android.os.Process#THREAD_PRIORITY_BACKGROUND}, which means fewer CPU
+ * resources will be dedicated to it, and it will "have less chance of impacting
+ * the responsiveness of the user interface."
+ * <p>
+ * This thread is best suited for tasks that the user is not actively waiting
+ * for, or for tasks that the user expects to be executed eventually.
+ *
+ * @see com.android.internal.os.BackgroundThread
+ *
+ * TODO: b/326916057 depend on modules-utils-backgroundthread instead
+ * @hide
+ */
+public final class BackgroundThread extends HandlerThread {
+    private static final Object sLock = new Object();
+
+    @GuardedBy("sLock")
+    private static BackgroundThread sInstance;
+    @GuardedBy("sLock")
+    private static Handler sHandler;
+    @GuardedBy("sLock")
+    private static HandlerExecutor sHandlerExecutor;
+
+    private BackgroundThread() {
+        super(BackgroundThread.class.getName(), android.os.Process.THREAD_PRIORITY_BACKGROUND);
+    }
+
+    @GuardedBy("sLock")
+    private static void ensureThreadLocked() {
+        if (sInstance == null) {
+            sInstance = new BackgroundThread();
+            sInstance.start();
+            sHandler = new Handler(sInstance.getLooper());
+            sHandlerExecutor = new HandlerExecutor(sHandler);
+        }
+    }
+
+    /**
+     * Get the singleton instance of this class.
+     *
+     * @return the singleton instance of this class
+     */
+    @NonNull
+    public static BackgroundThread get() {
+        synchronized (sLock) {
+            ensureThreadLocked();
+            return sInstance;
+        }
+    }
+
+    /**
+     * Get the singleton {@link Handler} for this class.
+     *
+     * @return the singleton {@link Handler} for this class.
+     */
+    @NonNull
+    public static Handler getHandler() {
+        synchronized (sLock) {
+            ensureThreadLocked();
+            return sHandler;
+        }
+    }
+
+    /**
+     * Get the singleton {@link Executor} for this class.
+     *
+     * @return the singleton {@link Executor} for this class.
+     */
+    @NonNull
+    public static Executor getExecutor() {
+        synchronized (sLock) {
+            ensureThreadLocked();
+            return sHandlerExecutor;
+        }
+    }
+}
diff --git a/packages/CrashRecovery/services/java/com/android/util/HandlerExecutor.java b/packages/CrashRecovery/services/java/com/android/util/HandlerExecutor.java
new file mode 100644
index 0000000..948ebcca
--- /dev/null
+++ b/packages/CrashRecovery/services/java/com/android/util/HandlerExecutor.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 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 android.util;
+
+import android.annotation.NonNull;
+import android.os.Handler;
+
+import java.util.Objects;
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
+
+/**
+ * An adapter {@link Executor} that posts all executed tasks onto the given
+ * {@link Handler}.
+ *
+ * TODO: b/326916057 depend on modules-utils-backgroundthread instead
+ * @hide
+ */
+public class HandlerExecutor implements Executor {
+    private final Handler mHandler;
+
+    public HandlerExecutor(@NonNull Handler handler) {
+        mHandler = Objects.requireNonNull(handler);
+    }
+
+    @Override
+    public void execute(Runnable command) {
+        if (!mHandler.post(command)) {
+            throw new RejectedExecutionException(mHandler + " is shutting down");
+        }
+    }
+}
diff --git a/packages/CredentialManager/res/values/colors.xml b/packages/CredentialManager/res/values/colors.xml
index 7cb1d01..b4d2eeb 100644
--- a/packages/CredentialManager/res/values/colors.xml
+++ b/packages/CredentialManager/res/values/colors.xml
@@ -22,4 +22,7 @@
     <color name="dropdown_container">#F3F3FA</color>
     <color name="sign_in_options_container">#DADADA</color>
     <color name="sign_in_options_icon_color">#1B1B1B</color>
+
+    <!-- These colors are used for Inline Suggestions. -->
+    <color name="inline_background">#FFFFFF</color>
 </resources>
\ No newline at end of file
diff --git a/packages/CredentialManager/res/values/dimens.xml b/packages/CredentialManager/res/values/dimens.xml
index b47a4dc..350920b2 100644
--- a/packages/CredentialManager/res/values/dimens.xml
+++ b/packages/CredentialManager/res/values/dimens.xml
@@ -28,4 +28,6 @@
     <dimen name="dropdown_layout_horizontal_margin">24dp</dimen>
     <integer name="autofill_max_visible_datasets">5</integer>
     <dimen name="dropdown_touch_target_min_height">48dp</dimen>
+    <dimen name="horizontal_chip_padding">8dp</dimen>
+    <dimen name="vertical_chip_padding">6dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt b/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt
index a5f227a..02320a1 100644
--- a/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt
+++ b/packages/CredentialManager/shared/src/com/android/credentialmanager/ktx/CredentialKtx.kt
@@ -127,10 +127,10 @@
                     userName = credentialEntry.username.toString(),
                     displayName = credentialEntry.displayName?.toString(),
                     icon = credentialEntry.icon.loadDrawable(context),
-                    shouldTintIcon = credentialEntry.isDefaultIcon,
+                    shouldTintIcon = credentialEntry.hasDefaultIcon,
                     lastUsedTimeMillis = credentialEntry.lastUsedTime,
                     isAutoSelectable = credentialEntry.isAutoSelectAllowed &&
-                            credentialEntry.autoSelectAllowedFromOption,
+                            credentialEntry.isAutoSelectAllowedFromOption,
                 )
                 )
             }
@@ -148,10 +148,10 @@
                     userName = credentialEntry.username.toString(),
                     displayName = credentialEntry.displayName?.toString(),
                     icon = credentialEntry.icon.loadDrawable(context),
-                    shouldTintIcon = credentialEntry.isDefaultIcon,
+                    shouldTintIcon = credentialEntry.hasDefaultIcon,
                     lastUsedTimeMillis = credentialEntry.lastUsedTime,
                     isAutoSelectable = credentialEntry.isAutoSelectAllowed &&
-                            credentialEntry.autoSelectAllowedFromOption,
+                            credentialEntry.isAutoSelectAllowedFromOption,
                 )
                 )
             }
@@ -170,10 +170,10 @@
                     userName = credentialEntry.title.toString(),
                     displayName = credentialEntry.subtitle?.toString(),
                     icon = credentialEntry.icon.loadDrawable(context),
-                    shouldTintIcon = credentialEntry.isDefaultIcon,
+                    shouldTintIcon = credentialEntry.hasDefaultIcon,
                     lastUsedTimeMillis = credentialEntry.lastUsedTime,
                     isAutoSelectable = credentialEntry.isAutoSelectAllowed &&
-                            credentialEntry.autoSelectAllowedFromOption,
+                            credentialEntry.isAutoSelectAllowedFromOption,
                 )
                 )
             }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
index eef75c7..28c42fb 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
@@ -57,6 +57,7 @@
 import androidx.credentials.provider.PasswordCredentialEntry
 import androidx.credentials.provider.PublicKeyCredentialEntry
 import com.android.credentialmanager.GetFlowUtils
+import com.android.credentialmanager.common.ui.InlinePresentationsFactory
 import com.android.credentialmanager.common.ui.RemoteViewsFactory
 import com.android.credentialmanager.getflow.ProviderDisplayInfo
 import com.android.credentialmanager.getflow.toProviderDisplayInfo
@@ -212,7 +213,7 @@
         autofillIdToProvidersMap.forEach { (autofillId, providers) ->
             validFillResponse = processProvidersForAutofillId(
                     filLRequest, autofillId, providers, entryIconMap, fillResponseBuilder,
-                    getCredResponse.pendingIntent)
+                    getCredResponse.intent)
                     .or(validFillResponse)
         }
         if (!validFillResponse) {
@@ -228,7 +229,7 @@
             providerDataList: ArrayList<GetCredentialProviderData>,
             entryIconMap: Map<String, Icon>,
             fillResponseBuilder: FillResponse.Builder,
-            bottomSheetPendingIntent: PendingIntent?
+            bottomSheetIntent: Intent
     ): Boolean {
         val providerList = GetFlowUtils.toProviderList(
             providerDataList,
@@ -266,6 +267,8 @@
                 }
             }
         }
+        bottomSheetIntent.putExtra(
+                ProviderData.EXTRA_ENABLED_PROVIDER_DATA_LIST, providerDataList)
         providerDisplayInfo.sortedUserNameToCredentialEntryList.forEach usernameLoop@{
             val primaryEntry = it.sortedCredentialEntryList.first()
             val pendingIntent = primaryEntry.pendingIntent
@@ -294,8 +297,12 @@
                 } else {
                     inlinePresentationSpecs[inlinePresentationSpecsCount - 1]
                 }
-                inlinePresentation = createInlinePresentation(primaryEntry, pendingIntent, icon,
-                        spec!!, duplicateDisplayNamesForPasskeys)
+                if (spec != null) {
+                    inlinePresentation = createInlinePresentation(primaryEntry, pendingIntent, icon,
+                            InlinePresentationsFactory.modifyInlinePresentationSpec
+                            (this@CredentialAutofillService, spec),
+                            duplicateDisplayNamesForPasskeys)
+                }
             }
             var dropdownPresentation: RemoteViews? = null
             if (i < lastDropdownDatasetIndex) {
@@ -325,16 +332,16 @@
             datasetAdded = true
             i++
 
-            if (i == lastDropdownDatasetIndex && bottomSheetPendingIntent != null) {
-                addDropdownMoreOptionsPresentation(bottomSheetPendingIntent, autofillId,
+            if (i == lastDropdownDatasetIndex) {
+                addDropdownMoreOptionsPresentation(bottomSheetIntent, autofillId,
                         fillResponseBuilder)
             }
         }
         val pinnedSpec = getLastInlinePresentationSpec(inlinePresentationSpecs,
                 inlinePresentationSpecsCount)
-        if (datasetAdded && bottomSheetPendingIntent != null && pinnedSpec != null) {
-            addPinnedInlineSuggestion(bottomSheetPendingIntent, pinnedSpec, autofillId,
-                    fillResponseBuilder, providerDataList)
+        if (datasetAdded && pinnedSpec != null) {
+            addPinnedInlineSuggestion(pinnedSpec, autofillId,
+                    fillResponseBuilder, bottomSheetIntent)
         }
         return datasetAdded
     }
@@ -365,13 +372,14 @@
     }
 
     private fun addDropdownMoreOptionsPresentation(
-            bottomSheetPendingIntent: PendingIntent,
+            bottomSheetIntent: Intent,
             autofillId: AutofillId,
             fillResponseBuilder: FillResponse.Builder
     ) {
         val presentationBuilder = Presentations.Builder()
                 .setMenuPresentation(
                         RemoteViewsFactory.createMoreSignInOptionsPresentation(this))
+        val pendingIntent = setUpBottomSheetPendingIntent(bottomSheetIntent)
 
         fillResponseBuilder.addDataset(
                 Dataset.Builder()
@@ -380,7 +388,7 @@
                                 Field.Builder().setPresentations(
                                         presentationBuilder.build())
                                         .build())
-                        .setAuthentication(bottomSheetPendingIntent.intentSender)
+                        .setAuthentication(pendingIntent.intentSender)
                         .build()
         )
     }
@@ -396,37 +404,41 @@
     }
 
     private fun addPinnedInlineSuggestion(
-            bottomSheetPendingIntent: PendingIntent,
             spec: InlinePresentationSpec,
             autofillId: AutofillId,
             fillResponseBuilder: FillResponse.Builder,
-            providerDataList: ArrayList<GetCredentialProviderData>
+            bottomSheetIntent: Intent
     ) {
+        val pendingIntent = setUpBottomSheetPendingIntent(bottomSheetIntent)
+
         val dataSetBuilder = Dataset.Builder()
         val sliceBuilder = InlineSuggestionUi
-                .newContentBuilder(bottomSheetPendingIntent)
+                .newContentBuilder(pendingIntent)
                 .setStartIcon(Icon.createWithResource(this,
                         com.android.credentialmanager.R.drawable.more_horiz_24px))
         val presentationBuilder = Presentations.Builder()
                 .setInlinePresentation(InlinePresentation(
                         sliceBuilder.build().slice, spec, /* pinned= */ true))
 
-        val extrasIntent = Intent()
-        extrasIntent.putExtra(ProviderData.EXTRA_ENABLED_PROVIDER_DATA_LIST, providerDataList)
-
         fillResponseBuilder.addDataset(
                 dataSetBuilder
                         .setField(
                                 autofillId,
                                 Field.Builder().setPresentations(
-                                        presentationBuilder.build())
-                                        .build())
-                        .setAuthentication(bottomSheetPendingIntent.intentSender)
-                        .setCredentialFillInIntent(extrasIntent)
+                                        presentationBuilder.build()
+                                ).build()
+                        )
+                        .setAuthentication(pendingIntent.intentSender)
                         .build()
         )
     }
 
+    private fun setUpBottomSheetPendingIntent(intent: Intent): PendingIntent {
+        intent.setAction(java.util.UUID.randomUUID().toString())
+        return PendingIntent.getActivity(this, /*requestCode=*/0, intent,
+                PendingIntent.FLAG_MUTABLE, /*options=*/null)
+    }
+
     /**
      *  Maps Autofill Id to provider list. For example, passing in a provider info
      *
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt
index d319e4c..a7b5c36 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/BottomSheet.kt
@@ -16,8 +16,15 @@
 
 package com.android.credentialmanager.common.ui
 
+import android.credentials.flags.Flags
+import androidx.compose.animation.animateContentSize
 import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.ColumnScope
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.rememberCoroutineScope
@@ -25,6 +32,7 @@
 import androidx.compose.ui.graphics.Color
 import com.android.compose.rememberSystemUiController
 import com.android.compose.theme.LocalAndroidColorScheme
+import androidx.compose.ui.unit.dp
 import com.android.credentialmanager.common.material.ModalBottomSheetLayout
 import com.android.credentialmanager.common.material.ModalBottomSheetValue
 import com.android.credentialmanager.common.material.rememberModalBottomSheetState
@@ -34,40 +42,68 @@
 
 /** Draws a modal bottom sheet with the same styles and effects shared by various flows. */
 @Composable
+@OptIn(ExperimentalMaterial3Api::class)
 fun ModalBottomSheet(
-    sheetContent: @Composable ColumnScope.() -> Unit,
-    onDismiss: () -> Unit,
-    isInitialRender: Boolean,
-    onInitialRenderComplete: () -> Unit,
-    isAutoSelectFlow: Boolean,
+        sheetContent: @Composable () -> Unit,
+        onDismiss: () -> Unit,
+        isInitialRender: Boolean,
+        onInitialRenderComplete: () -> Unit,
+        isAutoSelectFlow: Boolean,
 ) {
-    val scope = rememberCoroutineScope()
-    val state = rememberModalBottomSheetState(
-        initialValue = if (isAutoSelectFlow) ModalBottomSheetValue.Expanded
-        else ModalBottomSheetValue.Hidden,
-        skipHalfExpanded = true
-    )
-    val sysUiController = rememberSystemUiController()
-    if (state.targetValue == ModalBottomSheetValue.Hidden || isAutoSelectFlow) {
-        setTransparentSystemBarsColor(sysUiController)
+    if (Flags.selectorUiImprovementsEnabled()) {
+        val state = androidx.compose.material3.rememberModalBottomSheetState(
+                skipPartiallyExpanded = true
+        )
+        androidx.compose.material3.ModalBottomSheet(
+                onDismissRequest = onDismiss,
+                containerColor = LocalAndroidColorScheme.current.surfaceBright,
+                sheetState = state,
+                content = {
+                    Box(
+                            modifier = Modifier
+                                    .animateContentSize()
+                                    .wrapContentHeight()
+                                    .fillMaxWidth()
+                    ) {
+                        sheetContent()
+                    }
+                },
+                scrimColor = MaterialTheme.colorScheme.scrim.copy(alpha = .32f),
+                shape = EntryShape.TopRoundedCorner,
+                dragHandle = null,
+                // Never take over the full screen. We always want to leave some top scrim space
+                // for exiting and viewing the underlying app to help a user gain context.
+                modifier = Modifier.padding(top = 56.dp),
+        )
     } else {
-        setBottomSheetSystemBarsColor(sysUiController)
-    }
-    ModalBottomSheetLayout(
-        sheetBackgroundColor = LocalAndroidColorScheme.current.surfaceBright,
-        modifier = Modifier.background(Color.Transparent),
-        sheetState = state,
-        sheetContent = sheetContent,
-        sheetShape = EntryShape.TopRoundedCorner,
-    ) {}
-    LaunchedEffect(state.currentValue, state.targetValue) {
-        if (state.currentValue == ModalBottomSheetValue.Hidden) {
-            if (isInitialRender) {
-                onInitialRenderComplete()
-                scope.launch { state.show() }
-            } else if (state.targetValue == ModalBottomSheetValue.Hidden) {
-                // Only dismiss ui when the motion is downwards
-                onDismiss()
+        val scope = rememberCoroutineScope()
+        val state = rememberModalBottomSheetState(
+                initialValue = if (isAutoSelectFlow) ModalBottomSheetValue.Expanded
+                else ModalBottomSheetValue.Hidden,
+                skipHalfExpanded = true
+        )
+        val sysUiController = rememberSystemUiController()
+        if (state.targetValue == ModalBottomSheetValue.Hidden || isAutoSelectFlow) {
+            setTransparentSystemBarsColor(sysUiController)
+        } else {
+            setBottomSheetSystemBarsColor(sysUiController)
+        }
+        ModalBottomSheetLayout(
+                sheetBackgroundColor = LocalAndroidColorScheme.current.surfaceBright,
+                modifier = Modifier.background(Color.Transparent),
+                sheetState = state,
+                sheetContent = { sheetContent() },
+                sheetShape = EntryShape.TopRoundedCorner,
+        ) {}
+        LaunchedEffect(state.currentValue, state.targetValue) {
+            if (state.currentValue == ModalBottomSheetValue.Hidden) {
+                if (isInitialRender) {
+                    onInitialRenderComplete()
+                    scope.launch { state.show() }
+                } else if (state.targetValue == ModalBottomSheetValue.Hidden) {
+                    // Only dismiss ui when the motion is downwards
+                    onDismiss()
+                }
             }
         }
     }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt
index bdfe399..c68ae8b 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt
@@ -18,7 +18,10 @@
 
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.ColumnScope
+import androidx.compose.foundation.layout.WindowInsets
 import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.asPaddingValues
+import androidx.compose.foundation.layout.navigationBars
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.wrapContentHeight
 import androidx.compose.foundation.lazy.LazyColumn
@@ -66,6 +69,9 @@
             horizontalAlignment = Alignment.CenterHorizontally,
             content = content,
             verticalArrangement = contentVerticalArrangement,
+            // The bottom sheet overlaps with the navigation bars but make sure the actual content
+            // in the bottom sheet does not.
+            contentPadding = WindowInsets.navigationBars.asPaddingValues(),
         )
     }
 }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt
index a6253b8..8ff17e0 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt
@@ -29,13 +29,10 @@
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.ArrowBack
 import androidx.compose.material.icons.outlined.Lock
-import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.Icon
 import androidx.compose.material3.IconButton
 import androidx.compose.material3.SuggestionChip
 import androidx.compose.material3.SuggestionChipDefaults
-import androidx.compose.material3.TopAppBar
-import androidx.compose.material3.TopAppBarDefaults
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
@@ -278,31 +275,6 @@
 }
 
 /**
- * A single row of leading icon and text describing a benefit of passkeys, used by the
- * [com.android.credentialmanager.createflow.PasskeyIntroCard].
- */
-@Composable
-fun PasskeyBenefitRow(
-    leadingIconPainter: Painter,
-    text: String,
-) {
-    Row(
-        horizontalArrangement = Arrangement.spacedBy(16.dp),
-        verticalAlignment = Alignment.CenterVertically,
-        modifier = Modifier.fillMaxWidth()
-    ) {
-        Icon(
-            modifier = Modifier.size(24.dp),
-            painter = leadingIconPainter,
-            tint = LocalAndroidColorScheme.current.onSurfaceVariant,
-            // Decorative purpose only.
-            contentDescription = null,
-        )
-        BodyMediumText(text = text)
-    }
-}
-
-/**
  * A single row of one or two CTA buttons for continuing or cancelling the current step.
  */
 @Composable
@@ -327,40 +299,36 @@
     }
 }
 
-@OptIn(ExperimentalMaterial3Api::class)
 @Composable
 fun MoreOptionTopAppBar(
     text: String,
     onNavigationIconClicked: () -> Unit,
     bottomPadding: Dp,
 ) {
-    TopAppBar(
-        title = {
-            LargeTitleText(text = text, modifier = Modifier.padding(horizontal = 4.dp))
-        },
-        navigationIcon = {
-            IconButton(
+    Row(
+            modifier = Modifier.padding(top = 12.dp, bottom = bottomPadding),
+            verticalAlignment = Alignment.CenterVertically,
+    ) {
+        IconButton(
                 modifier = Modifier.padding(top = 8.dp, bottom = 8.dp, start = 4.dp).size(48.dp),
                 onClick = onNavigationIconClicked
-            ) {
-                Box(
+        ) {
+            Box(
                     modifier = Modifier.size(48.dp),
                     contentAlignment = Alignment.Center,
-                ) {
-                    Icon(
+            ) {
+                Icon(
                         imageVector = Icons.Filled.ArrowBack,
                         contentDescription = stringResource(
-                            R.string.accessibility_back_arrow_button
+                                R.string.accessibility_back_arrow_button
                         ),
                         modifier = Modifier.size(24.dp).autoMirrored(),
                         tint = LocalAndroidColorScheme.current.onSurfaceVariant,
-                    )
-                }
+                )
             }
-        },
-        colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent),
-        modifier = Modifier.padding(top = 12.dp, bottom = bottomPadding)
-    )
+        }
+        LargeTitleText(text = text, modifier = Modifier.padding(horizontal = 4.dp))
+    }
 }
 
 private fun Modifier.autoMirrored() = composed {
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/InlinePresentationFactory.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/InlinePresentationFactory.kt
new file mode 100644
index 0000000..3ebdd20
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/InlinePresentationFactory.kt
@@ -0,0 +1,84 @@
+/*
+* Copyright (C) 2024 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.credentialmanager.common.ui
+
+
+import android.content.Context
+import android.util.Size
+import android.widget.inline.InlinePresentationSpec
+import androidx.autofill.inline.common.TextViewStyle
+import androidx.autofill.inline.common.ViewStyle
+import androidx.autofill.inline.UiVersions
+import androidx.autofill.inline.UiVersions.Style
+import androidx.autofill.inline.v1.InlineSuggestionUi
+import androidx.core.content.ContextCompat
+import android.util.TypedValue
+import android.graphics.Typeface
+
+
+class InlinePresentationsFactory {
+    companion object {
+        private const val googleSansMediumFontFamily = "google-sans-medium"
+        private const val googleSansTextFontFamily = "google-sans-text"
+        // There is no min width required for now but this is needed for the spec builder
+        private const val minInlineWidth = 5000
+
+
+        fun modifyInlinePresentationSpec(context: Context,
+                                         originalSpec: InlinePresentationSpec): InlinePresentationSpec {
+            return InlinePresentationSpec.Builder(Size(originalSpec.minSize.width, originalSpec
+                    .minSize.height),
+                    Size(minInlineWidth, originalSpec
+                            .maxSize.height))
+                    .setStyle(UiVersions.newStylesBuilder().addStyle(getStyle(context)).build())
+                    .build()
+        }
+
+
+        fun getStyle(context: Context): Style {
+            val textColorPrimary = ContextCompat.getColor(context,
+                    com.android.credentialmanager.R.color.text_primary)
+            val textColorSecondary = ContextCompat.getColor(context,
+                    com.android.credentialmanager.R.color.text_secondary)
+            val textColorBackground = ContextCompat.getColor(context,
+                    com.android.credentialmanager.R.color.inline_background)
+            val chipHorizontalPadding = context.resources.getDimensionPixelSize(com.android
+                    .credentialmanager.R.dimen.horizontal_chip_padding)
+            val chipVerticalPadding = context.resources.getDimensionPixelSize(com.android
+                    .credentialmanager.R.dimen.vertical_chip_padding)
+            return InlineSuggestionUi.newStyleBuilder()
+                    .setChipStyle(
+                            ViewStyle.Builder().setPadding(chipHorizontalPadding,
+                                    chipVerticalPadding,
+                                    chipHorizontalPadding, chipVerticalPadding).build()
+                    )
+                    .setTitleStyle(
+                            TextViewStyle.Builder().setTextColor(textColorPrimary).setTextSize
+                            (TypedValue.COMPLEX_UNIT_DIP, 14F)
+                                    .setTypeface(googleSansMediumFontFamily,
+                                            Typeface.NORMAL).setBackgroundColor(textColorBackground)
+                                    .build()
+                    )
+                    .setSubtitleStyle(TextViewStyle.Builder().setTextColor(textColorSecondary)
+                            .setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12F).setTypeface
+                            (googleSansTextFontFamily, Typeface.NORMAL).setBackgroundColor
+                            (textColorBackground).build())
+                    .build()
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
index 4ed84b9..7277550 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
@@ -653,4 +653,4 @@
         contentText = stringResource(R.string.no_sign_in_info_in, lastLocked.providerDisplayName),
     )
     onLog(GetCredentialEvent.CREDMAN_GET_CRED_SCREEN_EMPTY_AUTH_SNACKBAR_SCREEN)
-}
\ No newline at end of file
+}
diff --git a/packages/CredentialManager/tests/robotests/Android.bp b/packages/CredentialManager/tests/robotests/Android.bp
index baebfeb..75a0dcc 100644
--- a/packages/CredentialManager/tests/robotests/Android.bp
+++ b/packages/CredentialManager/tests/robotests/Android.bp
@@ -37,7 +37,7 @@
         ":CredentialManagerScreenshotTestFiles",
     ],
 
-    // Do not add any libraries here, instead add them to the ScreenshotTestStub
+    // Do not add any libraries here, instead add them to the ScreenshotTestRobo
     static_libs: [
         "androidx.compose.runtime_runtime",
         "androidx.test.uiautomator_uiautomator",
@@ -45,6 +45,7 @@
         "inline-mockito-robolectric-prebuilt",
         "platform-parametric-runner-lib",
         "uiautomator-helpers",
+        "flag-junit-base",
     ],
     libs: [
         "android.test.runner",
diff --git a/packages/CredentialManager/tests/robotests/customization/assets/phone/dark_landscape_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/phone/dark_landscape_singleCredentialScreen_newM3BottomSheet.png
new file mode 100644
index 0000000..81860e5
--- /dev/null
+++ b/packages/CredentialManager/tests/robotests/customization/assets/phone/dark_landscape_singleCredentialScreen_newM3BottomSheet.png
Binary files differ
diff --git a/packages/CredentialManager/tests/robotests/customization/assets/phone/dark_portrait_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/phone/dark_portrait_singleCredentialScreen_newM3BottomSheet.png
new file mode 100644
index 0000000..8c1fff7
--- /dev/null
+++ b/packages/CredentialManager/tests/robotests/customization/assets/phone/dark_portrait_singleCredentialScreen_newM3BottomSheet.png
Binary files differ
diff --git a/packages/CredentialManager/tests/robotests/customization/assets/phone/light_landscape_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/phone/light_landscape_singleCredentialScreen_newM3BottomSheet.png
new file mode 100644
index 0000000..4eb025f
--- /dev/null
+++ b/packages/CredentialManager/tests/robotests/customization/assets/phone/light_landscape_singleCredentialScreen_newM3BottomSheet.png
Binary files differ
diff --git a/packages/CredentialManager/tests/robotests/customization/assets/phone/light_portrait_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/phone/light_portrait_singleCredentialScreen_newM3BottomSheet.png
new file mode 100644
index 0000000..c709f93
--- /dev/null
+++ b/packages/CredentialManager/tests/robotests/customization/assets/phone/light_portrait_singleCredentialScreen_newM3BottomSheet.png
Binary files differ
diff --git a/packages/CredentialManager/tests/robotests/customization/assets/tablet/dark_landscape_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/tablet/dark_landscape_singleCredentialScreen_newM3BottomSheet.png
new file mode 100644
index 0000000..278c13f
--- /dev/null
+++ b/packages/CredentialManager/tests/robotests/customization/assets/tablet/dark_landscape_singleCredentialScreen_newM3BottomSheet.png
Binary files differ
diff --git a/packages/CredentialManager/tests/robotests/customization/assets/tablet/dark_portrait_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/tablet/dark_portrait_singleCredentialScreen_newM3BottomSheet.png
new file mode 100644
index 0000000..cb85df3
--- /dev/null
+++ b/packages/CredentialManager/tests/robotests/customization/assets/tablet/dark_portrait_singleCredentialScreen_newM3BottomSheet.png
Binary files differ
diff --git a/packages/CredentialManager/tests/robotests/customization/assets/tablet/light_landscape_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/tablet/light_landscape_singleCredentialScreen_newM3BottomSheet.png
new file mode 100644
index 0000000..2eca707
--- /dev/null
+++ b/packages/CredentialManager/tests/robotests/customization/assets/tablet/light_landscape_singleCredentialScreen_newM3BottomSheet.png
Binary files differ
diff --git a/packages/CredentialManager/tests/robotests/customization/assets/tablet/light_portrait_singleCredentialScreen_newM3BottomSheet.png b/packages/CredentialManager/tests/robotests/customization/assets/tablet/light_portrait_singleCredentialScreen_newM3BottomSheet.png
new file mode 100644
index 0000000..7ee91b3
--- /dev/null
+++ b/packages/CredentialManager/tests/robotests/customization/assets/tablet/light_portrait_singleCredentialScreen_newM3BottomSheet.png
Binary files differ
diff --git a/packages/CredentialManager/tests/robotests/screenshot/src/com/android/credentialmanager/GetCredScreenshotTest.kt b/packages/CredentialManager/tests/robotests/screenshot/src/com/android/credentialmanager/GetCredScreenshotTest.kt
index a0e1fed..e609d0c 100644
--- a/packages/CredentialManager/tests/robotests/screenshot/src/com/android/credentialmanager/GetCredScreenshotTest.kt
+++ b/packages/CredentialManager/tests/robotests/screenshot/src/com/android/credentialmanager/GetCredScreenshotTest.kt
@@ -16,7 +16,10 @@
 
 package com.android.credentialmanager
 
+import android.credentials.flags.Flags
 import android.content.Context
+import android.platform.test.flag.junit.SetFlagsRule
+import androidx.compose.ui.test.isPopup
 import com.android.credentialmanager.getflow.RequestDisplayInfo
 import com.android.credentialmanager.model.CredentialType
 import com.android.credentialmanager.model.get.ProviderInfo
@@ -59,8 +62,11 @@
             CredentialManagerGoldenImagePathManager(getEmulatedDevicePathConfig(emulationSpec))
     )
 
+    @get:Rule val setFlagsRule: SetFlagsRule = SetFlagsRule()
+
     @Test
-    fun singleCredentialScreen() {
+    fun singleCredentialScreen_M3BottomSheetDisabled() {
+        setFlagsRule.disableFlags(Flags.FLAG_SELECTOR_UI_IMPROVEMENTS_ENABLED)
         val providerInfoList = buildProviderInfoList()
         val providerDisplayInfo = toProviderDisplayInfo(providerInfoList)
         val activeEntry = toActiveEntry(providerDisplayInfo)
@@ -86,6 +92,39 @@
         }
     }
 
+    @Test
+    fun singleCredentialScreen_M3BottomSheetEnabled() {
+        setFlagsRule.enableFlags(Flags.FLAG_SELECTOR_UI_IMPROVEMENTS_ENABLED)
+        val providerInfoList = buildProviderInfoList()
+        val providerDisplayInfo = toProviderDisplayInfo(providerInfoList)
+        val activeEntry = toActiveEntry(providerDisplayInfo)
+        screenshotRule.screenshotTest(
+                "singleCredentialScreen_newM3BottomSheet",
+                // M3's ModalBottomSheet lives in a new window, meaning we have two windows with
+                // a root. Hence use a different matcher `isPopup`.
+                viewFinder = { screenshotRule.composeRule.onNode(isPopup()) },
+        ) {
+            ModalBottomSheet(
+                    sheetContent = {
+                        PrimarySelectionCard(
+                                requestDisplayInfo = REQUEST_DISPLAY_INFO,
+                                providerDisplayInfo = providerDisplayInfo,
+                                providerInfoList = providerInfoList,
+                                activeEntry = activeEntry,
+                                onEntrySelected = {},
+                                onConfirm = {},
+                                onMoreOptionSelected = {},
+                                onLog = {},
+                        )
+                    },
+                    isInitialRender = true,
+                    onDismiss = {},
+                    onInitialRenderComplete = {},
+                    isAutoSelectFlow = false,
+            )
+        }
+    }
+
     private fun buildProviderInfoList(): List<ProviderInfo> {
         val context = ApplicationProvider.getApplicationContext<Context>()
         val provider1 = ProviderInfo(
diff --git a/packages/FusedLocation/AndroidManifest.xml b/packages/FusedLocation/AndroidManifest.xml
index 05561d7..158c33a 100644
--- a/packages/FusedLocation/AndroidManifest.xml
+++ b/packages/FusedLocation/AndroidManifest.xml
@@ -28,6 +28,7 @@
     <uses-permission android:name="android.permission.INSTALL_LOCATION_PROVIDER" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
     <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
+    <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
 
     <application
             android:label="@string/app_label"
@@ -49,5 +50,17 @@
            <meta-data android:name="serviceVersion" android:value="0" />
            <meta-data android:name="serviceIsMultiuser" android:value="true" />
         </service>
+
+        <!-- GNSS overlay Service that LocationManagerService binds to.
+             LocationManagerService will bind to the service with the highest
+             version. -->
+        <service android:name="com.android.location.gnss.GnssOverlayLocationService"
+                 android:exported="false">
+           <intent-filter>
+               <action android:name="android.location.provider.action.GNSS_PROVIDER" />
+           </intent-filter>
+           <meta-data android:name="serviceVersion" android:value="0" />
+           <meta-data android:name="serviceIsMultiuser" android:value="true" />
+        </service>
     </application>
 </manifest>
diff --git a/packages/FusedLocation/src/com/android/location/gnss/GnssOverlayLocationProvider.java b/packages/FusedLocation/src/com/android/location/gnss/GnssOverlayLocationProvider.java
new file mode 100644
index 0000000..c6576e3
--- /dev/null
+++ b/packages/FusedLocation/src/com/android/location/gnss/GnssOverlayLocationProvider.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2024 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.location.gnss;
+
+import static android.location.provider.ProviderProperties.ACCURACY_FINE;
+import static android.location.provider.ProviderProperties.POWER_USAGE_HIGH;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.location.LocationRequest;
+import android.location.provider.LocationProviderBase;
+import android.location.provider.ProviderProperties;
+import android.location.provider.ProviderRequest;
+import android.os.Bundle;
+import android.util.SparseArray;
+
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.ConcurrentUtils;
+
+import java.util.List;
+
+/** Basic pass-through GNSS location provider implementation. */
+public class GnssOverlayLocationProvider extends LocationProviderBase {
+
+    private static final String TAG = "GnssOverlay";
+
+    private static final ProviderProperties PROPERTIES = new ProviderProperties.Builder()
+                .setHasAltitudeSupport(true)
+                .setHasSpeedSupport(true)
+                .setHasBearingSupport(true)
+                .setPowerUsage(POWER_USAGE_HIGH)
+                .setAccuracy(ACCURACY_FINE)
+                .build();
+
+    @GuardedBy("mPendingFlushes")
+    private final SparseArray<OnFlushCompleteCallback> mPendingFlushes = new SparseArray<>();
+
+    private final LocationManager mLocationManager;
+
+    private final GnssLocationListener mGnssLocationListener = new GnssLocationListener();
+
+    @GuardedBy("mPendingFlushes")
+    private int mFlushCode = 0;
+
+    /** Location listener for receiving locations from LocationManager. */
+    private class GnssLocationListener implements LocationListener {
+        @Override
+        public void onLocationChanged(Location location) {
+            reportLocation(location);
+        }
+
+        @Override
+        public void onLocationChanged(List<Location> locations) {
+            reportLocations(locations);
+        }
+
+        @Override
+        public void onFlushComplete(int requestCode) {
+            OnFlushCompleteCallback flushCompleteCallback;
+            synchronized (mPendingFlushes) {
+                flushCompleteCallback = mPendingFlushes.get(requestCode);
+                mPendingFlushes.remove(requestCode);
+            }
+            if (flushCompleteCallback != null) {
+                flushCompleteCallback.onFlushComplete();
+            }
+        }
+    }
+
+    public GnssOverlayLocationProvider(Context context) {
+        super(context, TAG, PROPERTIES);
+        mLocationManager = context.getSystemService(LocationManager.class);
+    }
+
+    void start() {
+    }
+
+    void stop() {
+        mLocationManager.removeUpdates(mGnssLocationListener);
+    }
+
+    @Override
+    public void onSendExtraCommand(String command, @Nullable Bundle extras) {
+        mLocationManager.sendExtraCommand(LocationManager.GPS_HARDWARE_PROVIDER, command, extras);
+    }
+
+    @Override
+    public void onFlush(OnFlushCompleteCallback callback) {
+        int flushCodeCopy;
+        synchronized (mPendingFlushes) {
+            flushCodeCopy = mFlushCode++;
+            mPendingFlushes.put(flushCodeCopy, callback);
+        }
+        mLocationManager.requestFlush(
+                LocationManager.GPS_HARDWARE_PROVIDER, mGnssLocationListener, flushCodeCopy);
+    }
+
+    @Override
+    public void onSetRequest(ProviderRequest request) {
+        if (request.isActive()) {
+            mLocationManager.requestLocationUpdates(
+                    LocationManager.GPS_HARDWARE_PROVIDER,
+                    new LocationRequest.Builder(request.getIntervalMillis())
+                            .setMaxUpdateDelayMillis(request.getMaxUpdateDelayMillis())
+                            .setLowPower(request.isLowPower())
+                            .setLocationSettingsIgnored(request.isLocationSettingsIgnored())
+                            .setWorkSource(request.getWorkSource())
+                            .setQuality(request.getQuality())
+                            .build(),
+                    ConcurrentUtils.DIRECT_EXECUTOR,
+                    mGnssLocationListener);
+        } else {
+            mLocationManager.removeUpdates(mGnssLocationListener);
+        }
+    }
+}
diff --git a/packages/FusedLocation/src/com/android/location/gnss/GnssOverlayLocationService.java b/packages/FusedLocation/src/com/android/location/gnss/GnssOverlayLocationService.java
new file mode 100644
index 0000000..dd034fe
--- /dev/null
+++ b/packages/FusedLocation/src/com/android/location/gnss/GnssOverlayLocationService.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2024 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.location.gnss;
+
+import android.annotation.Nullable;
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+public class GnssOverlayLocationService extends Service {
+
+    @Nullable private GnssOverlayLocationProvider mProvider;
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        if (mProvider == null) {
+            mProvider = new GnssOverlayLocationProvider(this);
+            mProvider.start();
+        }
+
+        return mProvider.getBinder();
+    }
+
+    @Override
+    public void onDestroy() {
+        if (mProvider != null) {
+            mProvider.stop();
+            mProvider = null;
+        }
+    }
+
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+    }
+}
diff --git a/packages/FusedLocation/test/src/com/android/location/gnss/tests/GnssOverlayLocationServiceTest.java b/packages/FusedLocation/test/src/com/android/location/gnss/tests/GnssOverlayLocationServiceTest.java
new file mode 100644
index 0000000..5b33deb
--- /dev/null
+++ b/packages/FusedLocation/test/src/com/android/location/gnss/tests/GnssOverlayLocationServiceTest.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2024 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.location.gnss.tests;
+
+import static android.location.LocationManager.GPS_HARDWARE_PROVIDER;
+
+import static androidx.test.ext.truth.location.LocationSubject.assertThat;
+
+import android.content.Context;
+import android.location.Criteria;
+import android.location.Location;
+import android.location.LocationManager;
+import android.location.LocationRequest;
+import android.location.provider.ILocationProvider;
+import android.location.provider.ILocationProviderManager;
+import android.location.provider.ProviderProperties;
+import android.location.provider.ProviderRequest;
+import android.os.ParcelFileDescriptor;
+import android.os.SystemClock;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.location.gnss.GnssOverlayLocationProvider;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class GnssOverlayLocationServiceTest {
+
+    private static final String TAG = "GnssOverlayLocationServiceTest";
+
+    private static final long TIMEOUT_MS = 5000;
+
+    private Random mRandom;
+    private LocationManager mLocationManager;
+
+    private ILocationProvider mProvider;
+    private LocationProviderManagerCapture mManager;
+
+    @Before
+    public void setUp() throws Exception {
+        long seed = System.currentTimeMillis();
+        Log.i(TAG, "location seed: " + seed);
+
+        Context context = ApplicationProvider.getApplicationContext();
+        mRandom = new Random(seed);
+        mLocationManager = context.getSystemService(LocationManager.class);
+
+        setMockLocation(true);
+
+        mManager = new LocationProviderManagerCapture();
+        mProvider = ILocationProvider.Stub.asInterface(
+                new GnssOverlayLocationProvider(context).getBinder());
+        mProvider.setLocationProviderManager(mManager);
+
+        mLocationManager.addTestProvider(GPS_HARDWARE_PROVIDER,
+                true,
+                false,
+                true,
+                false,
+                false,
+                false,
+                false,
+                Criteria.POWER_MEDIUM,
+                Criteria.ACCURACY_FINE);
+        mLocationManager.setTestProviderEnabled(GPS_HARDWARE_PROVIDER, true);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        for (String provider : mLocationManager.getAllProviders()) {
+            mLocationManager.removeTestProvider(provider);
+        }
+
+        setMockLocation(false);
+    }
+
+    @Test
+    public void testGpsRequest() throws Exception {
+        mProvider.setRequest(
+                new ProviderRequest.Builder()
+                        .setQuality(LocationRequest.QUALITY_HIGH_ACCURACY)
+                        .setIntervalMillis(1000)
+                        .build());
+
+        Location location = createLocation(GPS_HARDWARE_PROVIDER, mRandom);
+        mLocationManager.setTestProviderLocation(GPS_HARDWARE_PROVIDER, location);
+
+        assertThat(mManager.getNextLocation(TIMEOUT_MS)).isEqualTo(location);
+    }
+
+    private static class LocationProviderManagerCapture extends ILocationProviderManager.Stub {
+
+        private final LinkedBlockingQueue<Location> mLocations;
+
+        private LocationProviderManagerCapture() {
+            mLocations = new LinkedBlockingQueue<>();
+        }
+
+        @Override
+        public void onInitialize(boolean allowed, ProviderProperties properties,
+                String attributionTag) {}
+
+        @Override
+        public void onSetAllowed(boolean allowed) {}
+
+        @Override
+        public void onSetProperties(ProviderProperties properties) {}
+
+        @Override
+        public void onReportLocation(Location location) {
+            mLocations.add(location);
+        }
+
+        @Override
+        public void onReportLocations(List<Location> locations) {
+            mLocations.addAll(locations);
+        }
+
+        @Override
+        public void onFlushComplete() {}
+
+        public Location getNextLocation(long timeoutMs) throws InterruptedException {
+            return mLocations.poll(timeoutMs, TimeUnit.MILLISECONDS);
+        }
+    }
+
+    private static final double MIN_LATITUDE = -90D;
+    private static final double MAX_LATITUDE = 90D;
+    private static final double MIN_LONGITUDE = -180D;
+    private static final double MAX_LONGITUDE = 180D;
+
+    private static final float MIN_ACCURACY = 1;
+    private static final float MAX_ACCURACY = 100;
+
+    private static Location createLocation(String provider, Random random) {
+        return createLocation(provider,
+                MIN_LATITUDE + random.nextDouble() * (MAX_LATITUDE - MIN_LATITUDE),
+                MIN_LONGITUDE + random.nextDouble() * (MAX_LONGITUDE - MIN_LONGITUDE),
+                MIN_ACCURACY + random.nextFloat() * (MAX_ACCURACY - MIN_ACCURACY));
+    }
+
+    private static Location createLocation(String provider, double latitude, double longitude,
+            float accuracy) {
+        Location location = new Location(provider);
+        location.setLatitude(latitude);
+        location.setLongitude(longitude);
+        location.setAccuracy(accuracy);
+        location.setTime(System.currentTimeMillis());
+        location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
+        return location;
+    }
+
+    private static void setMockLocation(boolean allowed) throws IOException {
+        ParcelFileDescriptor pfd = InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                .executeShellCommand("appops set "
+                        + InstrumentationRegistry.getTargetContext().getPackageName()
+                        + " android:mock_location " + (allowed ? "allow" : "deny"));
+        try (FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
+            ByteArrayOutputStream os = new ByteArrayOutputStream();
+            byte[] buffer = new byte[32768];
+            int count;
+            try {
+                while ((count = fis.read(buffer)) != -1) {
+                    os.write(buffer, 0, count);
+                }
+                fis.close();
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+            Log.e(TAG, new String(os.toByteArray()));
+        }
+    }
+}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
index 904e184..cf6aab6 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -403,7 +403,7 @@
                 resolvedPath = info.getResolvedBaseApkPath();
             }
             if (info == null || !info.isSealed() || resolvedPath == null) {
-                Log.w(TAG, "Session " + mSessionId + " in funky state; ignoring");
+                Log.w(TAG, "Session " + sessionId + " in funky state; ignoring");
                 finish();
                 return;
             }
@@ -418,7 +418,7 @@
                     -1 /* defaultValue */);
             final SessionInfo info = mInstaller.getSessionInfo(sessionId);
             if (info == null || !info.isPreApprovalRequested()) {
-                Log.w(TAG, "Session " + mSessionId + " in funky state; ignoring");
+                Log.w(TAG, "Session " + sessionId + " in funky state; ignoring");
                 finish();
                 return;
             }
@@ -839,7 +839,9 @@
                     // work for the multiple user case, i.e. the caller task user and started
                     // Activity user are not the same. To avoid having multiple PIAs in the task,
                     // finish the current PackageInstallerActivity
-                    finish();
+                    // Because finish() is overridden to set the installation result, we must use
+                    // the original finish() method, or the confirmation dialog fails to appear.
+                    PackageInstallerActivity.super.finish();
                 }
             }, 500);
 
diff --git a/packages/SettingsLib/Spa/build.gradle.kts b/packages/SettingsLib/Spa/build.gradle.kts
index 463e9be..335725c 100644
--- a/packages/SettingsLib/Spa/build.gradle.kts
+++ b/packages/SettingsLib/Spa/build.gradle.kts
@@ -29,7 +29,7 @@
 
 allprojects {
     extra["androidTop"] = androidTop
-    extra["jetpackComposeVersion"] = "1.7.0-alpha02"
+    extra["jetpackComposeVersion"] = "1.7.0-alpha03"
 }
 
 subprojects {
diff --git a/packages/SettingsLib/Spa/gradle/libs.versions.toml b/packages/SettingsLib/Spa/gradle/libs.versions.toml
index fe378c2..609a82e 100644
--- a/packages/SettingsLib/Spa/gradle/libs.versions.toml
+++ b/packages/SettingsLib/Spa/gradle/libs.versions.toml
@@ -16,7 +16,7 @@
 
 [versions]
 agp = "8.2.2"
-compose-compiler = "1.5.9"
+compose-compiler = "1.5.10"
 dexmaker-mockito = "2.28.3"
 jvm = "17"
 kotlin = "1.9.22"
diff --git a/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_landscape_slider.png b/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_landscape_slider.png
index a038779..e1f5c74 100644
--- a/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_landscape_slider.png
+++ b/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_landscape_slider.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_portrait_slider.png b/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_portrait_slider.png
index 03db688..928e926 100644
--- a/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_portrait_slider.png
+++ b/packages/SettingsLib/Spa/screenshot/robotests/assets/phone/light_portrait_slider.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/screenshot/robotests/assets/tablet/dark_portrait_slider.png b/packages/SettingsLib/Spa/screenshot/robotests/assets/tablet/dark_portrait_slider.png
index 1345c37..0521368 100644
--- a/packages/SettingsLib/Spa/screenshot/robotests/assets/tablet/dark_portrait_slider.png
+++ b/packages/SettingsLib/Spa/screenshot/robotests/assets/tablet/dark_portrait_slider.png
Binary files differ
diff --git a/packages/SettingsLib/Spa/spa/build.gradle.kts b/packages/SettingsLib/Spa/spa/build.gradle.kts
index 2259bd74..a193a2f 100644
--- a/packages/SettingsLib/Spa/spa/build.gradle.kts
+++ b/packages/SettingsLib/Spa/spa/build.gradle.kts
@@ -57,7 +57,7 @@
     api("androidx.slice:slice-builders:1.1.0-alpha02")
     api("androidx.slice:slice-core:1.1.0-alpha02")
     api("androidx.slice:slice-view:1.1.0-alpha02")
-    api("androidx.compose.material3:material3:1.2.0")
+    api("androidx.compose.material3:material3:1.3.0-alpha01")
     api("androidx.compose.material:material-icons-extended:$jetpackComposeVersion")
     api("androidx.compose.runtime:runtime-livedata:$jetpackComposeVersion")
     api("androidx.compose.ui:ui-tooling-preview:$jetpackComposeVersion")
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/RadioPreferences.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/RadioPreferences.kt
new file mode 100644
index 0000000..8300ce8
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/RadioPreferences.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2024 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.settingslib.spa.widget.preference
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.selection.selectable
+import androidx.compose.foundation.selection.selectableGroup
+import androidx.compose.material3.RadioButton
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.semantics.Role
+import com.android.settingslib.spa.framework.theme.SettingsDimension
+import com.android.settingslib.spa.widget.ui.CategoryTitle
+import com.android.settingslib.spa.widget.ui.SettingsListItem
+
+@Composable
+fun RadioPreferences(model: ListPreferenceModel) {
+    CategoryTitle(title = model.title)
+    Spacer(modifier = Modifier.width(SettingsDimension.itemDividerHeight))
+    Column(modifier = Modifier.selectableGroup()) {
+        for (option in model.options) {
+            Radio2(option, model.selectedId.intValue, model.enabled()) {
+                model.onIdSelected(it)
+            }
+        }
+    }
+}
+
+@Composable
+fun Radio2(
+    option: ListPreferenceOption,
+    selectedId: Int,
+    enabled: Boolean,
+    onIdSelected: (id: Int) -> Unit,
+) {
+    val selected = option.id == selectedId
+    Row(
+        modifier = Modifier
+            .fillMaxWidth()
+            .selectable(
+                selected = selected,
+                enabled = enabled,
+                onClick = { onIdSelected(option.id) },
+                role = Role.RadioButton,
+            )
+            .padding(SettingsDimension.dialogItemPadding),
+        verticalAlignment = Alignment.CenterVertically,
+    ) {
+        RadioButton(selected = selected, onClick = null, enabled = enabled)
+        Spacer(modifier = Modifier.width(SettingsDimension.itemDividerHeight))
+        SettingsListItem(text = option.text, enabled = enabled)
+    }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
index 4f61966..56534f4 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
@@ -180,7 +180,7 @@
      * @param colorTransitionFraction a `0.0` to `1.0` value that represents a color transition
      * percentage
      */
-    @Composable
+    @Stable
     fun containerColor(colorTransitionFraction: Float): Color {
         return lerp(
             containerColor,
@@ -519,7 +519,7 @@
                 0
             }
 
-        val layoutHeight = if (heightPx.isNaN()) 0 else heightPx.roundToInt()
+        val layoutHeight = if (heightPx > 0) heightPx.roundToInt() else 0
 
         layout(constraints.maxWidth, layoutHeight) {
             // Navigation icon
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Text.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Text.kt
index b4a6a0d..a59b95a 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Text.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Text.kt
@@ -66,6 +66,19 @@
 }
 
 @Composable
+fun SettingsListItem(text: String, enabled: Boolean = true) {
+    Text(
+        text = text,
+        modifier = Modifier
+            .alphaForEnabled(enabled)
+            .padding(vertical = SettingsDimension.paddingTiny),
+        color = MaterialTheme.colorScheme.onSurface,
+        style = MaterialTheme.typography.titleMedium,
+        overflow = TextOverflow.Ellipsis,
+    )
+}
+
+@Composable
 fun SettingsBody(
     body: String,
     maxLines: Int = Int.MAX_VALUE,
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/RadioPreferencesTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/RadioPreferencesTest.kt
new file mode 100644
index 0000000..2f98b02
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/preference/RadioPreferencesTest.kt
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2024 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.settingslib.spa.widget.preference
+
+import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertIsNotEnabled
+import androidx.compose.ui.test.assertIsNotSelected
+import androidx.compose.ui.test.assertIsSelectable
+import androidx.compose.ui.test.assertIsSelected
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class RadioPreferencesTest {
+    @get:Rule
+    val composeTestRule = createComposeRule()
+
+    @Test
+    fun title_displayed() {
+        composeTestRule.setContent {
+            RadioPreferences(remember {
+                object : ListPreferenceModel {
+                    override val title = TITLE
+                    override val options = emptyList<ListPreferenceOption>()
+                    override val selectedId = mutableIntStateOf(0)
+                    override val onIdSelected: (Int) -> Unit = {}
+                }
+            })
+        }
+        composeTestRule.onNodeWithText(TITLE).assertIsDisplayed()
+    }
+
+    @Test
+    fun item_displayed() {
+        val selectedId = mutableIntStateOf(1)
+        composeTestRule.setContent {
+            RadioPreferences(remember {
+                object : ListPreferenceModel {
+                    override val title = TITLE
+                    override val options = listOf(
+                        ListPreferenceOption(id = 1, text = "A"),
+                        ListPreferenceOption(id = 2, text = "B"),
+                    )
+                    override val selectedId = selectedId
+                    override val onIdSelected = { id: Int -> selectedId.intValue = id }
+                }
+            })
+        }
+        composeTestRule.onNodeWithText("A").assertIsDisplayed()
+        composeTestRule.onNodeWithText("B").assertIsDisplayed()
+    }
+
+    @Test
+    fun item_selectable() {
+        val selectedId = mutableIntStateOf(1)
+        val enabledState = mutableStateOf(true)
+        composeTestRule.setContent {
+            RadioPreferences(remember {
+                object : ListPreferenceModel {
+                    override val title = TITLE
+                    override val enabled = { enabledState.value }
+                    override val options = listOf(
+                        ListPreferenceOption(id = 1, text = "A"),
+                        ListPreferenceOption(id = 2, text = "B"),
+                    )
+                    override val selectedId = selectedId
+                    override val onIdSelected = { id: Int -> selectedId.intValue = id }
+                }
+            })
+        }
+        composeTestRule.onNodeWithText("A").assertIsSelectable()
+        composeTestRule.onNodeWithText("B").assertIsSelectable()
+    }
+
+    @Test
+    fun item_single_selected() {
+        val selectedId = mutableIntStateOf(1)
+        val enabledState = mutableStateOf(true)
+        composeTestRule.setContent {
+            RadioPreferences(remember {
+                object : ListPreferenceModel {
+                    override val title = TITLE
+                    override val enabled = { enabledState.value }
+                    override val options = listOf(
+                        ListPreferenceOption(id = 1, text = "A"),
+                        ListPreferenceOption(id = 2, text = "B"),
+                    )
+                    override val selectedId = selectedId
+                    override val onIdSelected = { id: Int -> selectedId.intValue = id }
+                }
+            })
+        }
+        composeTestRule.onNodeWithText("B").assertIsSelectable()
+        composeTestRule.onNodeWithText("B").performClick()
+        composeTestRule.onNodeWithText("B").assertIsSelected()
+        composeTestRule.onNodeWithText("A").assertIsNotSelected()
+        composeTestRule.onNodeWithText("A").performClick()
+        composeTestRule.onNodeWithText("A").assertIsSelected()
+        composeTestRule.onNodeWithText("B").assertIsNotSelected()
+    }
+
+    @Test
+    fun select_itemDisabled() {
+        val selectedId = mutableIntStateOf(1)
+        val enabledState = mutableStateOf(true)
+        composeTestRule.setContent {
+            RadioPreferences(remember {
+                object : ListPreferenceModel {
+                    override val title = TITLE
+                    override val enabled = { enabledState.value }
+                    override val options = listOf(
+                        ListPreferenceOption(id = 1, text = "A"),
+                        ListPreferenceOption(id = 2, text = "B"),
+                    )
+                    override val selectedId = selectedId
+                    override val onIdSelected = { id: Int -> selectedId.intValue = id }
+                }
+            })
+        }
+        enabledState.value = false
+        composeTestRule.onNodeWithText("A").assertIsDisplayed().assertIsNotEnabled()
+        composeTestRule.onNodeWithText("B").assertIsDisplayed().assertIsNotEnabled()
+    }
+
+    private companion object {
+        const val TITLE = "Title"
+    }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt
index 988afd7..a395266 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt
@@ -26,6 +26,7 @@
 import android.content.pm.PackageManager.ApplicationInfoFlags
 import android.content.pm.ResolveInfo
 import android.os.SystemProperties
+import android.util.Log
 import com.android.internal.R
 import com.android.settingslib.spaprivileged.framework.common.userManager
 import kotlinx.coroutines.async
@@ -85,19 +86,24 @@
         userId: Int,
         loadInstantApps: Boolean,
         matchAnyUserForAdmin: Boolean,
-    ): List<ApplicationInfo> = coroutineScope {
-        val hiddenSystemModulesDeferred = async { packageManager.getHiddenSystemModules() }
-        val hideWhenDisabledPackagesDeferred = async {
-            context.resources.getStringArray(R.array.config_hideWhenDisabled_packageNames)
-        }
-        val installedApplicationsAsUser =
-            getInstalledApplications(userId, matchAnyUserForAdmin)
+    ): List<ApplicationInfo> = try {
+        coroutineScope {
+            val hiddenSystemModulesDeferred = async { packageManager.getHiddenSystemModules() }
+            val hideWhenDisabledPackagesDeferred = async {
+                context.resources.getStringArray(R.array.config_hideWhenDisabled_packageNames)
+            }
+            val installedApplicationsAsUser =
+                getInstalledApplications(userId, matchAnyUserForAdmin)
 
-        val hiddenSystemModules = hiddenSystemModulesDeferred.await()
-        val hideWhenDisabledPackages = hideWhenDisabledPackagesDeferred.await()
-        installedApplicationsAsUser.filter { app ->
-            app.isInAppList(loadInstantApps, hiddenSystemModules, hideWhenDisabledPackages)
+            val hiddenSystemModules = hiddenSystemModulesDeferred.await()
+            val hideWhenDisabledPackages = hideWhenDisabledPackagesDeferred.await()
+            installedApplicationsAsUser.filter { app ->
+                app.isInAppList(loadInstantApps, hiddenSystemModules, hideWhenDisabledPackages)
+            }
         }
+    } catch (e: Exception) {
+        Log.e(TAG, "loadApps failed", e)
+        emptyList()
     }
 
     private suspend fun getInstalledApplications(
@@ -210,6 +216,8 @@
     }
 
     companion object {
+        private const val TAG = "AppListRepository"
+
         private fun ApplicationInfo.isInAppList(
             showInstantApps: Boolean,
             hiddenSystemModules: Set<String>,
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
index efd53a4..c60ce41 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
@@ -28,6 +28,8 @@
 import android.content.pm.ResolveInfo
 import android.content.pm.UserInfo
 import android.content.res.Resources
+import android.os.BadParcelableException
+import android.os.DeadObjectException
 import android.os.UserManager
 import android.platform.test.flag.junit.SetFlagsRule
 import androidx.test.core.app.ApplicationProvider
@@ -44,6 +46,7 @@
 import org.mockito.kotlin.argumentCaptor
 import org.mockito.kotlin.doAnswer
 import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.doThrow
 import org.mockito.kotlin.eq
 import org.mockito.kotlin.mock
 import org.mockito.kotlin.spy
@@ -311,6 +314,19 @@
     }
 
     @Test
+    fun loadApps_hasException_returnEmptyList() = runTest {
+        packageManager.stub {
+            on {
+                getInstalledApplicationsAsUser(any<ApplicationInfoFlags>(), eq(ADMIN_USER_ID))
+            } doThrow BadParcelableException(DeadObjectException())
+        }
+
+        val appList = repository.loadApps(userId = ADMIN_USER_ID)
+
+        assertThat(appList).isEmpty()
+    }
+
+    @Test
     fun showSystemPredicate_showSystem() = runTest {
         val app = SYSTEM_APP
 
diff --git a/packages/SettingsLib/aconfig/settingslib.aconfig b/packages/SettingsLib/aconfig/settingslib.aconfig
index 6a1ee3a..54c5a14 100644
--- a/packages/SettingsLib/aconfig/settingslib.aconfig
+++ b/packages/SettingsLib/aconfig/settingslib.aconfig
@@ -43,4 +43,11 @@
   namespace: "pixel_cross_device_control"
   description: "Gates whether to enable LE audio private broadcast sharing via QR code"
   bug: "308368124"
-}
\ No newline at end of file
+}
+
+flag {
+  name: "enable_hide_exclusively_managed_bluetooth_device"
+  namespace: "dck_framework"
+  description: "Hide exclusively managed Bluetooth devices in BT settings menu."
+  bug: "324475542"
+}
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 9588e50..a4bc235 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1085,7 +1085,7 @@
     <!-- [CHAR_LIMIT=NONE] Label for charging on hold on main page of settings -->
     <string name="power_charging_on_hold_settings_home_page"><xliff:g id="level">%1$s</xliff:g> - Charging on hold to protect battery</string>
     <!-- [CHAR_LIMIT=NONE] Label for incompatible charging accessory on main page of settings -->
-    <string name="power_incompatible_charging_settings_home_page"><xliff:g id="level">%1$s</xliff:g> - Checking charging accessory</string>
+    <string name="power_incompatible_charging_settings_home_page"><xliff:g id="level">%1$s</xliff:g> - Check charging accessory</string>
     <!-- [CHAR_LIMIT=40] Label for estimated remaining duration of battery discharging -->
     <string name="power_remaining_duration_only">About <xliff:g id="time_remaining">%1$s</xliff:g> left</string>
     <!-- [CHAR_LIMIT=40] Label for battery level chart when discharging with duration -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
index 6ee403d..bd27c89 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothLeBroadcast.java
@@ -19,6 +19,7 @@
 import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
 
 import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothCsipSetCoordinator;
@@ -35,6 +36,7 @@
 import android.bluetooth.BluetoothProfile.ServiceListener;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.Intent;
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Build;
@@ -52,6 +54,8 @@
 
 import com.google.common.collect.ImmutableList;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -71,6 +75,18 @@
  * result callback.
  */
 public class LocalBluetoothLeBroadcast implements LocalBluetoothProfile {
+    public static final String ACTION_LE_AUDIO_SHARING_STATE_CHANGE =
+            "com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_STATE_CHANGE";
+    public static final String EXTRA_LE_AUDIO_SHARING_STATE = "BLUETOOTH_LE_AUDIO_SHARING_STATE";
+    public static final int BROADCAST_STATE_UNKNOWN = 0;
+    public static final int BROADCAST_STATE_ON = 1;
+    public static final int BROADCAST_STATE_OFF = 2;
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(
+            prefix = {"BROADCAST_STATE_"},
+            value = {BROADCAST_STATE_UNKNOWN, BROADCAST_STATE_ON, BROADCAST_STATE_OFF})
+    public @interface BroadcastState {}
+    private static final String SETTINGS_PKG = "com.android.settings";
     private static final String TAG = "LocalBluetoothLeBroadcast";
     private static final boolean DEBUG = BluetoothUtils.D;
 
@@ -89,7 +105,6 @@
                 Settings.Secure.getUriFor(
                         Settings.Secure.BLUETOOTH_LE_BROADCAST_IMPROVE_COMPATIBILITY),
             };
-
     private final Context mContext;
     private final CachedBluetoothDeviceManager mDeviceManager;
     private BluetoothLeBroadcast mServiceBroadcast;
@@ -200,6 +215,7 @@
                         Log.d(TAG, "onBroadcastMetadataChanged(), broadcastId = " + broadcastId);
                     }
                     setLatestBluetoothLeBroadcastMetadata(metadata);
+                    notifyBroadcastStateChange(BROADCAST_STATE_ON);
                 }
 
                 @Override
@@ -212,7 +228,7 @@
                                         + ", broadcastId = "
                                         + broadcastId);
                     }
-
+                    notifyBroadcastStateChange(BROADCAST_STATE_OFF);
                     stopLocalSourceReceivers();
                     resetCacheInfo();
                 }
@@ -1005,10 +1021,6 @@
 
     /** Update fallback active device if needed. */
     public void updateFallbackActiveDeviceIfNeeded() {
-        if (!isEnabled(null)) {
-            Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded due to no ongoing broadcast");
-            return;
-        }
         if (mServiceBroadcastAssistant == null) {
             Log.d(TAG, "Skip updateFallbackActiveDeviceIfNeeded due to assistant profile is null");
             return;
@@ -1078,4 +1090,15 @@
                 "bluetooth_le_broadcast_fallback_active_group_id",
                 BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
     }
+
+    private void notifyBroadcastStateChange(@BroadcastState int state) {
+        if (!mContext.getPackageName().equals(SETTINGS_PKG)) {
+            Log.d(TAG, "Skip notifyBroadcastStateChange, not triggered by Settings.");
+            return;
+        }
+        Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_STATE_CHANGE);
+        intent.putExtra(EXTRA_LE_AUDIO_SHARING_STATE, state);
+        intent.setPackage(mContext.getPackageName());
+        mContext.sendBroadcast(intent);
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java
index 0f08605..df03167 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/RouterInfoMediaManager.java
@@ -41,6 +41,7 @@
 import java.util.List;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Consumer;
 import java.util.stream.Collectors;
 
@@ -64,6 +65,8 @@
                 refreshDevices();
             };
 
+    private final AtomicReference<MediaRouter2.ScanToken> mScanToken = new AtomicReference<>();
+
     // TODO (b/321969740): Plumb target UserHandle between UMO and RouterInfoMediaManager.
     /* package */ RouterInfoMediaManager(
             Context context,
@@ -101,12 +104,24 @@
                 mExecutor, mRouteListingPreferenceCallback);
         mRouter.registerTransferCallback(mExecutor, mTransferCallback);
         mRouter.registerControllerCallback(mExecutor, mControllerCallback);
-        mRouter.startScan();
+        if (Flags.enableScreenOffScanning()) {
+            MediaRouter2.ScanRequest request = new MediaRouter2.ScanRequest.Builder().build();
+            mScanToken.compareAndSet(null, mRouter.requestScan(request));
+        } else {
+            mRouter.startScan();
+        }
     }
 
     @Override
     public void stopScan() {
-        mRouter.stopScan();
+        if (Flags.enableScreenOffScanning()) {
+            MediaRouter2.ScanToken token = mScanToken.getAndSet(null);
+            if (token != null) {
+                mRouter.cancelScanRequest(token);
+            }
+        } else {
+            mRouter.stopScan();
+        }
         mRouter.unregisterControllerCallback(mControllerCallback);
         mRouter.unregisterTransferCallback(mTransferCallback);
         mRouter.unregisterRouteListingPreferenceUpdatedCallback(mRouteListingPreferenceCallback);
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/data/repository/SpatializerRepository.kt b/packages/SettingsLib/src/com/android/settingslib/media/data/repository/SpatializerRepository.kt
index 2a4658b..a5c63be 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/data/repository/SpatializerRepository.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/media/data/repository/SpatializerRepository.kt
@@ -18,33 +18,71 @@
 
 import android.media.AudioDeviceAttributes
 import android.media.Spatializer
+import androidx.concurrent.futures.DirectExecutor
 import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
 
 interface SpatializerRepository {
 
+    /** Returns true when head tracking is enabled and false the otherwise. */
+    val isHeadTrackingAvailable: StateFlow<Boolean>
+
     /**
      * Returns true when Spatial audio feature is supported for the [audioDeviceAttributes] and
      * false the otherwise.
      */
-    suspend fun isAvailableForDevice(audioDeviceAttributes: AudioDeviceAttributes): Boolean
+    suspend fun isSpatialAudioAvailableForDevice(
+        audioDeviceAttributes: AudioDeviceAttributes
+    ): Boolean
 
     /** Returns a list [AudioDeviceAttributes] that are compatible with spatial audio. */
-    suspend fun getCompatibleDevices(): Collection<AudioDeviceAttributes>
+    suspend fun getSpatialAudioCompatibleDevices(): Collection<AudioDeviceAttributes>
 
-    /** Adds a [audioDeviceAttributes] to [getCompatibleDevices] list. */
-    suspend fun addCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes)
+    /** Adds a [audioDeviceAttributes] to [getSpatialAudioCompatibleDevices] list. */
+    suspend fun addSpatialAudioCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes)
 
-    /** Removes a [audioDeviceAttributes] to [getCompatibleDevices] list. */
-    suspend fun removeCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes)
+    /** Removes a [audioDeviceAttributes] from [getSpatialAudioCompatibleDevices] list. */
+    suspend fun removeSpatialAudioCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes)
+
+    /** Checks if the head tracking is enabled for the [audioDeviceAttributes]. */
+    suspend fun isHeadTrackingEnabled(audioDeviceAttributes: AudioDeviceAttributes): Boolean
+
+    /** Sets head tracking [isEnabled] for the [audioDeviceAttributes]. */
+    suspend fun setHeadTrackingEnabled(
+        audioDeviceAttributes: AudioDeviceAttributes,
+        isEnabled: Boolean,
+    )
 }
 
 class SpatializerRepositoryImpl(
     private val spatializer: Spatializer,
+    coroutineScope: CoroutineScope,
     private val backgroundContext: CoroutineContext,
 ) : SpatializerRepository {
 
-    override suspend fun isAvailableForDevice(
+    override val isHeadTrackingAvailable: StateFlow<Boolean> =
+        callbackFlow {
+                val listener =
+                    Spatializer.OnHeadTrackerAvailableListener { _, available ->
+                        launch { send(available) }
+                    }
+                spatializer.addOnHeadTrackerAvailableListener(DirectExecutor.INSTANCE, listener)
+                awaitClose { spatializer.removeOnHeadTrackerAvailableListener(listener) }
+            }
+            .onStart { emit(spatializer.isHeadTrackerAvailable) }
+            .flowOn(backgroundContext)
+            .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), false)
+
+    override suspend fun isSpatialAudioAvailableForDevice(
         audioDeviceAttributes: AudioDeviceAttributes
     ): Boolean {
         return withContext(backgroundContext) {
@@ -52,18 +90,36 @@
         }
     }
 
-    override suspend fun getCompatibleDevices(): Collection<AudioDeviceAttributes> =
+    override suspend fun getSpatialAudioCompatibleDevices(): Collection<AudioDeviceAttributes> =
         withContext(backgroundContext) { spatializer.compatibleAudioDevices }
 
-    override suspend fun addCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes) {
+    override suspend fun addSpatialAudioCompatibleDevice(
+        audioDeviceAttributes: AudioDeviceAttributes
+    ) {
         withContext(backgroundContext) {
             spatializer.addCompatibleAudioDevice(audioDeviceAttributes)
         }
     }
 
-    override suspend fun removeCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes) {
+    override suspend fun removeSpatialAudioCompatibleDevice(
+        audioDeviceAttributes: AudioDeviceAttributes
+    ) {
         withContext(backgroundContext) {
             spatializer.removeCompatibleAudioDevice(audioDeviceAttributes)
         }
     }
+
+    override suspend fun isHeadTrackingEnabled(
+        audioDeviceAttributes: AudioDeviceAttributes
+    ): Boolean =
+        withContext(backgroundContext) { spatializer.isHeadTrackerEnabled(audioDeviceAttributes) }
+
+    override suspend fun setHeadTrackingEnabled(
+        audioDeviceAttributes: AudioDeviceAttributes,
+        isEnabled: Boolean,
+    ) {
+        withContext(backgroundContext) {
+            spatializer.setHeadTrackerEnabled(isEnabled, audioDeviceAttributes)
+        }
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/domain/interactor/SpatializerInteractor.kt b/packages/SettingsLib/src/com/android/settingslib/media/domain/interactor/SpatializerInteractor.kt
index c3cc340..0347403 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/domain/interactor/SpatializerInteractor.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/media/domain/interactor/SpatializerInteractor.kt
@@ -18,22 +18,40 @@
 
 import android.media.AudioDeviceAttributes
 import com.android.settingslib.media.data.repository.SpatializerRepository
+import kotlinx.coroutines.flow.StateFlow
 
 class SpatializerInteractor(private val repository: SpatializerRepository) {
 
-    suspend fun isAvailable(audioDeviceAttributes: AudioDeviceAttributes): Boolean =
-        repository.isAvailableForDevice(audioDeviceAttributes)
+    /** Checks if head tracking is available. */
+    val isHeadTrackingAvailable: StateFlow<Boolean>
+        get() = repository.isHeadTrackingAvailable
+
+    suspend fun isSpatialAudioAvailable(audioDeviceAttributes: AudioDeviceAttributes): Boolean =
+        repository.isSpatialAudioAvailableForDevice(audioDeviceAttributes)
 
     /** Checks if spatial audio is enabled for the [audioDeviceAttributes]. */
-    suspend fun isEnabled(audioDeviceAttributes: AudioDeviceAttributes): Boolean =
-        repository.getCompatibleDevices().contains(audioDeviceAttributes)
+    suspend fun isSpatialAudioEnabled(audioDeviceAttributes: AudioDeviceAttributes): Boolean =
+        repository.getSpatialAudioCompatibleDevices().contains(audioDeviceAttributes)
 
-    /** Enblaes or disables spatial audio for [audioDeviceAttributes]. */
-    suspend fun setEnabled(audioDeviceAttributes: AudioDeviceAttributes, isEnabled: Boolean) {
+    /** Enables or disables spatial audio for [audioDeviceAttributes]. */
+    suspend fun setSpatialAudioEnabled(
+        audioDeviceAttributes: AudioDeviceAttributes,
+        isEnabled: Boolean
+    ) {
         if (isEnabled) {
-            repository.addCompatibleDevice(audioDeviceAttributes)
+            repository.addSpatialAudioCompatibleDevice(audioDeviceAttributes)
         } else {
-            repository.removeCompatibleDevice(audioDeviceAttributes)
+            repository.removeSpatialAudioCompatibleDevice(audioDeviceAttributes)
         }
     }
+
+    /** Checks if head tracking is enabled for the [audioDeviceAttributes]. */
+    suspend fun isHeadTrackingEnabled(audioDeviceAttributes: AudioDeviceAttributes): Boolean =
+        repository.isHeadTrackingEnabled(audioDeviceAttributes)
+
+    /** Enables or disables head tracking for the [audioDeviceAttributes]. */
+    suspend fun setHeadTrackingEnabled(
+        audioDeviceAttributes: AudioDeviceAttributes,
+        isEnabled: Boolean,
+    ) = repository.setHeadTrackingEnabled(audioDeviceAttributes, isEnabled)
 }
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/media/domain/interactor/FakeSpatializerRepository.kt b/packages/SettingsLib/tests/integ/src/com/android/settingslib/media/domain/interactor/FakeSpatializerRepository.kt
deleted file mode 100644
index 3f52f24..0000000
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/media/domain/interactor/FakeSpatializerRepository.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2024 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.settingslib.media.domain.interactor
-
-import android.media.AudioDeviceAttributes
-import com.android.settingslib.media.data.repository.SpatializerRepository
-
-class FakeSpatializerRepository : SpatializerRepository {
-
-    private val availabilityByDevice: MutableMap<AudioDeviceAttributes, Boolean> = mutableMapOf()
-    private val compatibleDevices: MutableList<AudioDeviceAttributes> = mutableListOf()
-
-    override suspend fun isAvailableForDevice(
-        audioDeviceAttributes: AudioDeviceAttributes
-    ): Boolean = availabilityByDevice.getOrDefault(audioDeviceAttributes, false)
-
-    override suspend fun getCompatibleDevices(): Collection<AudioDeviceAttributes> =
-        compatibleDevices
-
-    override suspend fun addCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes) {
-        compatibleDevices.add(audioDeviceAttributes)
-    }
-
-    override suspend fun removeCompatibleDevice(audioDeviceAttributes: AudioDeviceAttributes) {
-        compatibleDevices.remove(audioDeviceAttributes)
-    }
-
-    fun setIsAvailable(audioDeviceAttributes: AudioDeviceAttributes, isAvailable: Boolean) {
-        availabilityByDevice[audioDeviceAttributes] = isAvailable
-    }
-}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/media/domain/interactor/SpatializerInteractorTest.kt b/packages/SettingsLib/tests/integ/src/com/android/settingslib/media/domain/interactor/SpatializerInteractorTest.kt
deleted file mode 100644
index a44baeb..0000000
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/media/domain/interactor/SpatializerInteractorTest.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2024 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.settingslib.media.domain.interactor
-
-import android.media.AudioDeviceAttributes
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.runTest
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class SpatializerInteractorTest {
-
-    private val testScope = TestScope()
-    private val underTest = SpatializerInteractor(FakeSpatializerRepository())
-
-    @Test
-    fun setEnabledFalse_isEnabled_false() {
-        testScope.runTest {
-            underTest.setEnabled(deviceAttributes, false)
-
-            assertThat(underTest.isEnabled(deviceAttributes)).isFalse()
-        }
-    }
-
-    @Test
-    fun setEnabledTrue_isEnabled_true() {
-        testScope.runTest {
-            underTest.setEnabled(deviceAttributes, true)
-
-            assertThat(underTest.isEnabled(deviceAttributes)).isTrue()
-        }
-    }
-
-    private companion object {
-        val deviceAttributes = AudioDeviceAttributes(0, 0, "test_device")
-    }
-}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java
index 3705267..70ba415 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java
@@ -20,9 +20,7 @@
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
 
 import android.annotation.SuppressLint;
 import android.content.Context;
@@ -94,19 +92,6 @@
     }
 
     @Test
-    public void updateConnectivity_notAvailable_notCalled() {
-        boolean mCalled = false;
-        mController = spy(new ConcreteWifiMacAddressPreferenceController(mContext, mLifecycle) {
-            @Override
-            public boolean isAvailable() {
-                return false;
-            }
-        });
-        mController.displayPreference(mScreen);
-        verify(mController, never()).updateConnectivity();
-    }
-
-    @Test
     public void updateConnectivity_null_setMacUnavailable() {
         doReturn(null).when(mWifiManager).getFactoryMacAddresses();
         mController.displayPreference(mScreen);
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index e424797..2fa1c6e 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -227,6 +227,7 @@
         Settings.Secure.ACCESSIBILITY_MAGNIFICATION_JOYSTICK_ENABLED,
         Settings.Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED,
         Settings.Secure.ACCESSIBILITY_PINCH_TO_ZOOM_ANYWHERE_ENABLED,
+        Settings.Secure.ACCESSIBILITY_SINGLE_FINGER_PANNING_ENABLED,
         Settings.Secure.ODI_CAPTIONS_VOLUME_UI_ENABLED,
         Settings.Secure.NOTIFICATION_BUBBLES,
         Settings.Secure.LOCATION_TIME_ZONE_DETECTION_ENABLED,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index a32eead..2535fdb 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -321,6 +321,7 @@
                 Secure.ACCESSIBILITY_MAGNIFICATION_TWO_FINGER_TRIPLE_TAP_ENABLED,
                 BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.ACCESSIBILITY_PINCH_TO_ZOOM_ANYWHERE_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.ACCESSIBILITY_SINGLE_FINGER_PANNING_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(
                 Secure.ACCESSIBILITY_BUTTON_TARGETS,
                 ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index d27ff17..02d212c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1865,6 +1865,10 @@
                 SecureSettingsProto.Accessibility
                         .ACCESSIBILITY_PINCH_TO_ZOOM_ANYWHERE_ENABLED);
         dumpSetting(s, p,
+                Settings.Secure.ACCESSIBILITY_SINGLE_FINGER_PANNING_ENABLED,
+                SecureSettingsProto.Accessibility
+                        .ACCESSIBILITY_SINGLE_FINGER_PANNING_ENABLED);
+        dumpSetting(s, p,
                 Settings.Secure.HEARING_AID_RINGTONE_ROUTING,
                 SecureSettingsProto.Accessibility.HEARING_AID_RINGTONE_ROUTING);
         dumpSetting(s, p,
diff --git a/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java b/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java
index ea46c0c..ee81813 100644
--- a/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java
+++ b/packages/SoundPicker/src/com/android/soundpicker/RingtonePickerActivity.java
@@ -300,6 +300,8 @@
                 }
             };
             installTask.execute(data.getData());
+        } else if (requestCode == ADD_FILE_REQUEST_CODE && resultCode == RESULT_CANCELED) {
+            setupAlert();
         }
     }
 
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index d1a3571..e63232a 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -230,6 +230,7 @@
         extra_check_modules: ["SystemUILintChecker"],
         warning_checks: ["MissingApacheLicenseDetector"],
     },
+    skip_jarjar_repackage: true,
 }
 
 filegroup {
@@ -550,5 +551,6 @@
     required: [
         "privapp_whitelist_com.android.systemui",
         "wmshell.protolog.json.gz",
+        "wmshell.protolog.pb",
     ],
 }
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 71f9ba27..f5c4843 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -377,6 +377,13 @@
 }
 
 flag {
+    name: "screenshot_action_dismiss_system_windows"
+    namespace: "systemui"
+    description: "Dismiss existing system windows when starting action from screenshot UI"
+    bug: "309933761"
+}
+
+flag {
    name: "run_fingerprint_detect_on_dismissible_keyguard"
    namespace: "systemui"
    description: "Run fingerprint detect instead of authenticate if the keyguard is dismissible."
@@ -529,3 +536,23 @@
         purpose: PURPOSE_BUGFIX
     }
 }
+
+flag {
+    name: "bind_keyguard_media_visibility"
+    namespace: "systemui"
+    description: "Binds Keyguard Media Controller Visibility to MediaContainerView"
+    bug: "298213983"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
+    name: "notify_power_manager_user_activity_background"
+    namespace: "systemui"
+    description: "Decide whether to notify the user activity to power manager in the background thread."
+    bug: "325203885"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
diff --git a/packages/SystemUI/animation/Android.bp b/packages/SystemUI/animation/Android.bp
index c1125f0..99b7c36 100644
--- a/packages/SystemUI/animation/Android.bp
+++ b/packages/SystemUI/animation/Android.bp
@@ -45,6 +45,7 @@
         "androidx.core_core-ktx",
         "androidx.annotation_annotation",
         "SystemUIShaderLib",
+        "WindowManager-Shell-shared",
         "animationlib",
     ],
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationRunnerCompat.java
similarity index 98%
rename from packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java
rename to packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationRunnerCompat.java
index a78080f..e20425d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationRunnerCompat.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -11,10 +11,10 @@
  * 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
+ * limitations under the License.
  */
 
-package com.android.systemui.shared.system;
+package com.android.systemui.animation;
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.view.WindowManager.TRANSIT_CLOSE;
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationTargetCompat.java
similarity index 97%
rename from packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
rename to packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationTargetCompat.java
index e4d9243..e251af4 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteAnimationTargetCompat.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.shared.system;
+package com.android.systemui.animation;
 
 import android.util.ArrayMap;
 import android.view.RemoteAnimationTarget;
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseController.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseController.kt
index 535c2d3..e862f0c 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseController.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseController.kt
@@ -17,7 +17,6 @@
 
 import android.view.View
 import androidx.annotation.VisibleForTesting
-import java.util.Random
 
 /** Plays [TurbulenceNoiseView] in ease-in, main (no easing), and ease-out order. */
 class TurbulenceNoiseController(private val turbulenceNoiseView: TurbulenceNoiseView) {
@@ -37,8 +36,6 @@
         }
     }
 
-    private val random = Random()
-
     /** Current state of the animation. */
     @VisibleForTesting
     var state: AnimationState = AnimationState.NOT_PLAYING
@@ -95,12 +92,7 @@
         }
         state = AnimationState.EASE_IN
 
-        // Add offset to avoid repetitive noise.
-        turbulenceNoiseView.playEaseIn(
-            offsetX = random.nextFloat(),
-            offsetY = random.nextFloat(),
-            this::playMainAnimation
-        )
+        turbulenceNoiseView.playEaseIn(this::playMainAnimation)
     }
 
     private fun playMainAnimation() {
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseView.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseView.kt
index c59bc10..5e72e3b 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseView.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseView.kt
@@ -109,7 +109,7 @@
 
     /** Plays the turbulence noise with linear ease-in. */
     @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
-    fun playEaseIn(offsetX: Float = 0f, offsetY: Float = 0f, onAnimationEnd: Runnable? = null) {
+    fun playEaseIn(onAnimationEnd: Runnable? = null) {
         if (noiseConfig == null) {
             return
         }
@@ -129,8 +129,8 @@
             val progress = updateListener.animatedValue as Float
 
             shader.setNoiseMove(
-                offsetX + initialX + timeInSec * config.noiseMoveSpeedX,
-                offsetY + initialY + timeInSec * config.noiseMoveSpeedY,
+                initialX + timeInSec * config.noiseMoveSpeedX,
+                initialY + timeInSec * config.noiseMoveSpeedY,
                 initialZ + timeInSec * config.noiseMoveSpeedZ
             )
 
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/PlatformSlider.kt b/packages/SystemUI/compose/core/src/com/android/compose/PlatformSlider.kt
index b8c4fae..ef15c84 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/PlatformSlider.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/PlatformSlider.kt
@@ -57,9 +57,6 @@
 import com.android.compose.modifiers.padding
 import com.android.compose.theme.LocalAndroidColorScheme
 
-/** Indicator corner radius used when the user drags the [PlatformSlider]. */
-private val DefaultPlatformSliderDraggingCornerRadius = 8.dp
-
 /**
  * Platform slider implementation that displays a slider with an [icon] and a [label] at the start.
  *
@@ -83,10 +80,8 @@
     valueRange: ClosedFloatingPointRange<Float> = 0f..1f,
     enabled: Boolean = true,
     interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
-    colors: PlatformSliderColors =
-        if (isSystemInDarkTheme()) darkThemePlatformSliderColors()
-        else lightThemePlatformSliderColors(),
-    draggingCornersRadius: Dp = DefaultPlatformSliderDraggingCornerRadius,
+    colors: PlatformSliderColors = PlatformSliderDefaults.defaultPlatformSliderColors(),
+    draggingCornersRadius: Dp = PlatformSliderDefaults.DefaultPlatformSliderDraggingCornerRadius,
     icon: (@Composable (isDragging: Boolean) -> Unit)? = null,
     label: (@Composable (isDragging: Boolean) -> Unit)? = null,
 ) {
@@ -109,7 +104,7 @@
     val paddingStart by
         animateDpAsState(
             targetValue =
-                if ((!isDragging && value == 0f) || icon == null) {
+                if ((!isDragging && value == valueRange.start) || icon == null) {
                     16.dp
                 } else {
                     0.dp
@@ -125,6 +120,7 @@
             valueRange = valueRange,
             onValueChangeFinished = onValueChangeFinished,
             interactionSource = interactionSource,
+            enabled = enabled,
             track = {
                 Track(
                     sliderState = it,
@@ -156,7 +152,10 @@
                         modifier =
                             Modifier.fillMaxHeight()
                                 .weight(1f)
-                                .padding(start = { paddingStart.roundToPx() }),
+                                .padding(
+                                    start = { paddingStart.roundToPx() },
+                                    end = { sliderHeight.roundToPx() / 2 },
+                                ),
                         contentAlignment = Alignment.CenterStart,
                     ) {
                         labelComposable(isDragging)
@@ -286,6 +285,17 @@
     val disabledLabelColor: Color,
 )
 
+object PlatformSliderDefaults {
+
+    /** Indicator corner radius used when the user drags the [PlatformSlider]. */
+    val DefaultPlatformSliderDraggingCornerRadius = 8.dp
+
+    @Composable
+    fun defaultPlatformSliderColors(): PlatformSliderColors =
+        if (isSystemInDarkTheme()) darkThemePlatformSliderColors()
+        else lightThemePlatformSliderColors()
+}
+
 /** [PlatformSliderColors] for the light theme */
 @Composable
 private fun lightThemePlatformSliderColors() =
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/volume/VolumeSlidersModule.kt b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/volume/VolumeSlidersModule.kt
new file mode 100644
index 0000000..b4cb098
--- /dev/null
+++ b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/volume/panel/component/volume/VolumeSlidersModule.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2024 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.volume.panel.component.volume
+
+import dagger.Module
+
+@Module interface VolumeSlidersModule
diff --git a/packages/SystemUI/compose/features/Android.bp b/packages/SystemUI/compose/features/Android.bp
index c12084d..dfb3a55 100644
--- a/packages/SystemUI/compose/features/Android.bp
+++ b/packages/SystemUI/compose/features/Android.bp
@@ -44,4 +44,5 @@
     ],
 
     kotlincflags: ["-Xjvm-default=all"],
+    skip_jarjar_repackage: true,
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
index be5aa8a..7535a51 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
@@ -9,7 +9,7 @@
 import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.unit.dp
+import androidx.compose.ui.res.dimensionResource
 import com.android.compose.animation.scene.Edge
 import com.android.compose.animation.scene.ElementKey
 import com.android.compose.animation.scene.FixedSizeEdgeDetector
@@ -29,6 +29,7 @@
 import com.android.systemui.communal.ui.compose.extensions.allowGestures
 import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel
 import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
+import com.android.systemui.res.R
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.transform
 
@@ -91,7 +92,10 @@
     SceneTransitionLayout(
         state = sceneTransitionLayoutState,
         modifier = modifier.fillMaxSize().allowGestures(allowed = touchesAllowed),
-        swipeSourceDetector = FixedSizeEdgeDetector(ContainerDimensions.EdgeSwipeSize),
+        swipeSourceDetector =
+            FixedSizeEdgeDetector(
+                dimensionResource(id = R.dimen.communal_gesture_initiation_width)
+            ),
     ) {
         scene(
             TransitionSceneKey.Blank,
@@ -167,7 +171,3 @@
             )
     }
 }
-
-object ContainerDimensions {
-    val EdgeSwipeSize = 40.dp
-}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index 622a4f0..609f314 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -274,7 +274,7 @@
     widgetConfigurator: WidgetConfigurator?,
 ) {
     var gridModifier =
-        Modifier.align(Alignment.CenterStart).onGloballyPositioned { setGridCoordinates(it) }
+        Modifier.align(Alignment.TopStart).onGloballyPositioned { setGridCoordinates(it) }
     var list = communalContent
     var dragDropState: GridDragDropState? = null
     if (viewModel.isEditMode && viewModel is CommunalEditModeViewModel) {
@@ -309,8 +309,8 @@
         state = gridState,
         rows = GridCells.Fixed(CommunalContentSize.FULL.span),
         contentPadding = contentPadding,
-        horizontalArrangement = Arrangement.spacedBy(Dimensions.Spacing),
-        verticalArrangement = Arrangement.spacedBy(Dimensions.Spacing),
+        horizontalArrangement = Arrangement.spacedBy(32.dp),
+        verticalArrangement = Arrangement.spacedBy(32.dp),
     ) {
         items(
             count = list.size,
@@ -681,19 +681,20 @@
     Box(
         modifier = modifier,
     ) {
-        val paddingInPx = with(LocalDensity.current) { CardOutlineWidth.toPx().toInt() }
+        val paddingInPx =
+            if (selected) with(LocalDensity.current) { CardOutlineWidth.toPx().toInt() } else 0
         AndroidView(
             modifier = Modifier.fillMaxSize().allowGestures(allowed = !viewModel.isEditMode),
             factory = { context ->
-                val view =
-                    model.appWidgetHost
-                        .createViewForCommunal(context, model.appWidgetId, model.providerInfo)
-                        .apply { updateAppWidgetSize(Bundle.EMPTY, listOf(size)) }
+                model.appWidgetHost
+                    .createViewForCommunal(context, model.appWidgetId, model.providerInfo)
+                    .apply { updateAppWidgetSize(Bundle.EMPTY, listOf(size)) }
+            },
+            update = { view ->
                 // Remove the extra padding applied to AppWidgetHostView to allow widgets to
                 // occupy the entire box. The added padding is now adjusted to leave only sufficient
                 // space for displaying the outline around the box when the widget is selected.
                 view.setPadding(paddingInPx)
-                view
             },
             // For reusing composition in lazy lists.
             onReset = {},
@@ -795,7 +796,7 @@
 @Composable
 private fun gridContentPadding(isEditMode: Boolean, toolbarSize: IntSize?): PaddingValues {
     if (!isEditMode || toolbarSize == null) {
-        return PaddingValues(horizontal = Dimensions.Spacing)
+        return PaddingValues(start = 48.dp, end = 48.dp, top = Dimensions.GridTopSpacing)
     }
     val configuration = LocalConfiguration.current
     val density = LocalDensity.current
@@ -858,12 +859,13 @@
 }
 
 object Dimensions {
-    val CardWidth = 464.dp
-    val CardHeightFull = 630.dp
-    val CardHeightHalf = 307.dp
-    val CardHeightThird = 199.dp
+    val CardWidth = 424.dp
+    val CardHeightFull = 596.dp
+    val CardHeightHalf = 282.dp
+    val CardHeightThird = 177.33.dp
     val CardOutlineWidth = 3.dp
-    val GridHeight = CardHeightFull
+    val GridTopSpacing = 72.dp
+    val GridHeight = CardHeightFull + GridTopSpacing
     val Spacing = 16.dp
 
     // The sizing/padding of the toolbar in glanceable hub edit mode
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenSceneBlueprintModule.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenSceneBlueprintModule.kt
index 3677cab..53f400f 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenSceneBlueprintModule.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenSceneBlueprintModule.kt
@@ -20,6 +20,8 @@
 import com.android.systemui.keyguard.ui.composable.blueprint.DefaultBlueprintModule
 import com.android.systemui.keyguard.ui.composable.blueprint.ShortcutsBesideUdfpsBlueprintModule
 import com.android.systemui.keyguard.ui.composable.blueprint.SplitShadeBlueprintModule
+import com.android.systemui.keyguard.ui.composable.blueprint.SplitShadeWeatherClockBlueprintModule
+import com.android.systemui.keyguard.ui.composable.blueprint.WeatherClockBlueprintModule
 import com.android.systemui.keyguard.ui.composable.section.OptionalSectionModule
 import dagger.Module
 
@@ -31,6 +33,8 @@
             OptionalSectionModule::class,
             ShortcutsBesideUdfpsBlueprintModule::class,
             SplitShadeBlueprintModule::class,
+            SplitShadeWeatherClockBlueprintModule::class,
+            WeatherClockBlueprintModule::class,
         ],
 )
 interface LockscreenSceneBlueprintModule
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
index a07ab4a..452dc03 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/DefaultBlueprint.kt
@@ -33,7 +33,7 @@
 import com.android.systemui.keyguard.ui.composable.LockscreenLongPress
 import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSection
 import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection
-import com.android.systemui.keyguard.ui.composable.section.ClockSection
+import com.android.systemui.keyguard.ui.composable.section.DefaultClockSection
 import com.android.systemui.keyguard.ui.composable.section.LockSection
 import com.android.systemui.keyguard.ui.composable.section.NotificationSection
 import com.android.systemui.keyguard.ui.composable.section.SettingsMenuSection
@@ -56,7 +56,7 @@
 constructor(
     private val viewModel: LockscreenContentViewModel,
     private val statusBarSection: StatusBarSection,
-    private val clockSection: ClockSection,
+    private val clockSection: DefaultClockSection,
     private val smartSpaceSection: SmartSpaceSection,
     private val notificationSection: NotificationSection,
     private val lockSection: LockSection,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt
index b035e42..71c60c7 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt
@@ -33,7 +33,7 @@
 import com.android.systemui.keyguard.ui.composable.LockscreenLongPress
 import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSection
 import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection
-import com.android.systemui.keyguard.ui.composable.section.ClockSection
+import com.android.systemui.keyguard.ui.composable.section.DefaultClockSection
 import com.android.systemui.keyguard.ui.composable.section.LockSection
 import com.android.systemui.keyguard.ui.composable.section.NotificationSection
 import com.android.systemui.keyguard.ui.composable.section.SettingsMenuSection
@@ -56,7 +56,7 @@
 constructor(
     private val viewModel: LockscreenContentViewModel,
     private val statusBarSection: StatusBarSection,
-    private val clockSection: ClockSection,
+    private val clockSection: DefaultClockSection,
     private val smartSpaceSection: SmartSpaceSection,
     private val notificationSection: NotificationSection,
     private val lockSection: LockSection,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/SplitShadeBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/SplitShadeBlueprint.kt
index 44fe883..af836b6 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/SplitShadeBlueprint.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/SplitShadeBlueprint.kt
@@ -39,7 +39,7 @@
 import com.android.systemui.keyguard.ui.composable.LockscreenLongPress
 import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSection
 import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection
-import com.android.systemui.keyguard.ui.composable.section.ClockSection
+import com.android.systemui.keyguard.ui.composable.section.DefaultClockSection
 import com.android.systemui.keyguard.ui.composable.section.LockSection
 import com.android.systemui.keyguard.ui.composable.section.NotificationSection
 import com.android.systemui.keyguard.ui.composable.section.SettingsMenuSection
@@ -63,7 +63,7 @@
 constructor(
     private val viewModel: LockscreenContentViewModel,
     private val statusBarSection: StatusBarSection,
-    private val clockSection: ClockSection,
+    private val clockSection: DefaultClockSection,
     private val smartSpaceSection: SmartSpaceSection,
     private val notificationSection: NotificationSection,
     private val lockSection: LockSection,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt
new file mode 100644
index 0000000..e2e7a95
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/WeatherClockBlueprint.kt
@@ -0,0 +1,409 @@
+/*
+ * Copyright (C) 2024 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.keyguard.ui.composable.blueprint
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.Layout
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.dimensionResource
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.IntRect
+import androidx.compose.ui.unit.dp
+import com.android.compose.animation.scene.SceneScope
+import com.android.compose.modifiers.padding
+import com.android.systemui.Flags
+import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID
+import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.WEATHER_CLOCK_BLUEPRINT_ID
+import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
+import com.android.systemui.keyguard.ui.composable.LockscreenLongPress
+import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSection
+import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection
+import com.android.systemui.keyguard.ui.composable.section.LockSection
+import com.android.systemui.keyguard.ui.composable.section.NotificationSection
+import com.android.systemui.keyguard.ui.composable.section.SettingsMenuSection
+import com.android.systemui.keyguard.ui.composable.section.SmartSpaceSection
+import com.android.systemui.keyguard.ui.composable.section.StatusBarSection
+import com.android.systemui.keyguard.ui.composable.section.WeatherClockSection
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
+import com.android.systemui.res.R
+import com.android.systemui.shade.LargeScreenHeaderHelper
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.IntoSet
+import java.util.Optional
+import javax.inject.Inject
+
+class WeatherClockBlueprint
+@Inject
+constructor(
+    private val viewModel: LockscreenContentViewModel,
+    private val statusBarSection: StatusBarSection,
+    private val weatherClockSection: WeatherClockSection,
+    private val smartSpaceSection: SmartSpaceSection,
+    private val notificationSection: NotificationSection,
+    private val lockSection: LockSection,
+    private val ambientIndicationSectionOptional: Optional<AmbientIndicationSection>,
+    private val bottomAreaSection: BottomAreaSection,
+    private val settingsMenuSection: SettingsMenuSection,
+    private val clockInteractor: KeyguardClockInteractor,
+) : ComposableLockscreenSceneBlueprint {
+
+    override val id: String = WEATHER_CLOCK_BLUEPRINT_ID
+    @Composable
+    override fun SceneScope.Content(modifier: Modifier) {
+        val isUdfpsVisible = viewModel.isUdfpsVisible
+        val burnIn = rememberBurnIn(clockInteractor)
+        val resources = LocalContext.current.resources
+
+        LockscreenLongPress(
+            viewModel = viewModel.longPress,
+            modifier = modifier,
+        ) { onSettingsMenuPlaced ->
+            Layout(
+                content = {
+                    // Constrained to above the lock icon.
+                    Column(
+                        modifier = Modifier.fillMaxWidth(),
+                    ) {
+                        with(statusBarSection) { StatusBar(modifier = Modifier.fillMaxWidth()) }
+                        // TODO: Add weather clock for small and large clock
+                        with(smartSpaceSection) {
+                            SmartSpace(
+                                burnInParams = burnIn.parameters,
+                                onTopChanged = burnIn.onSmartspaceTopChanged,
+                                modifier =
+                                    Modifier.fillMaxWidth()
+                                        .padding(
+                                            top = { viewModel.getSmartSpacePaddingTop(resources) },
+                                        )
+                                        .padding(
+                                            bottom =
+                                                dimensionResource(
+                                                    R.dimen.keyguard_status_view_bottom_margin
+                                                ),
+                                        ),
+                            )
+                        }
+
+                        if (viewModel.areNotificationsVisible) {
+                            with(notificationSection) {
+                                Notifications(
+                                    modifier = Modifier.fillMaxWidth().weight(weight = 1f)
+                                )
+                            }
+                        }
+
+                        if (!isUdfpsVisible && ambientIndicationSectionOptional.isPresent) {
+                            with(ambientIndicationSectionOptional.get()) {
+                                AmbientIndication(modifier = Modifier.fillMaxWidth())
+                            }
+                        }
+                    }
+
+                    with(lockSection) { LockIcon() }
+
+                    // Aligned to bottom and constrained to below the lock icon.
+                    Column(modifier = Modifier.fillMaxWidth()) {
+                        if (isUdfpsVisible && ambientIndicationSectionOptional.isPresent) {
+                            with(ambientIndicationSectionOptional.get()) {
+                                AmbientIndication(modifier = Modifier.fillMaxWidth())
+                            }
+                        }
+
+                        with(bottomAreaSection) {
+                            IndicationArea(modifier = Modifier.fillMaxWidth())
+                        }
+                    }
+
+                    // Aligned to bottom and NOT constrained by the lock icon.
+                    with(bottomAreaSection) {
+                        Shortcut(isStart = true, applyPadding = true)
+                        Shortcut(isStart = false, applyPadding = true)
+                    }
+                    with(settingsMenuSection) { SettingsMenu(onSettingsMenuPlaced) }
+                },
+                modifier = Modifier.fillMaxSize(),
+            ) { measurables, constraints ->
+                check(measurables.size == 6)
+                val aboveLockIconMeasurable = measurables[0]
+                val lockIconMeasurable = measurables[1]
+                val belowLockIconMeasurable = measurables[2]
+                val startShortcutMeasurable = measurables[3]
+                val endShortcutMeasurable = measurables[4]
+                val settingsMenuMeasurable = measurables[5]
+
+                val noMinConstraints =
+                    constraints.copy(
+                        minWidth = 0,
+                        minHeight = 0,
+                    )
+                val lockIconPlaceable = lockIconMeasurable.measure(noMinConstraints)
+                val lockIconBounds =
+                    IntRect(
+                        left = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Left],
+                        top = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Top],
+                        right = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Right],
+                        bottom = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Bottom],
+                    )
+
+                val aboveLockIconPlaceable =
+                    aboveLockIconMeasurable.measure(
+                        noMinConstraints.copy(maxHeight = lockIconBounds.top)
+                    )
+                val belowLockIconPlaceable =
+                    belowLockIconMeasurable.measure(
+                        noMinConstraints.copy(
+                            maxHeight =
+                                (constraints.maxHeight - lockIconBounds.bottom).coerceAtLeast(0)
+                        )
+                    )
+                val startShortcutPleaceable = startShortcutMeasurable.measure(noMinConstraints)
+                val endShortcutPleaceable = endShortcutMeasurable.measure(noMinConstraints)
+                val settingsMenuPlaceable = settingsMenuMeasurable.measure(noMinConstraints)
+
+                layout(constraints.maxWidth, constraints.maxHeight) {
+                    aboveLockIconPlaceable.place(
+                        x = 0,
+                        y = 0,
+                    )
+                    lockIconPlaceable.place(
+                        x = lockIconBounds.left,
+                        y = lockIconBounds.top,
+                    )
+                    belowLockIconPlaceable.place(
+                        x = 0,
+                        y = constraints.maxHeight - belowLockIconPlaceable.height,
+                    )
+                    startShortcutPleaceable.place(
+                        x = 0,
+                        y = constraints.maxHeight - startShortcutPleaceable.height,
+                    )
+                    endShortcutPleaceable.place(
+                        x = constraints.maxWidth - endShortcutPleaceable.width,
+                        y = constraints.maxHeight - endShortcutPleaceable.height,
+                    )
+                    settingsMenuPlaceable.place(
+                        x = (constraints.maxWidth - settingsMenuPlaceable.width) / 2,
+                        y = constraints.maxHeight - settingsMenuPlaceable.height,
+                    )
+                }
+            }
+        }
+    }
+}
+
+class SplitShadeWeatherClockBlueprint
+@Inject
+constructor(
+    private val viewModel: LockscreenContentViewModel,
+    private val statusBarSection: StatusBarSection,
+    private val smartSpaceSection: SmartSpaceSection,
+    private val notificationSection: NotificationSection,
+    private val lockSection: LockSection,
+    private val ambientIndicationSectionOptional: Optional<AmbientIndicationSection>,
+    private val bottomAreaSection: BottomAreaSection,
+    private val settingsMenuSection: SettingsMenuSection,
+    private val clockInteractor: KeyguardClockInteractor,
+    private val largeScreenHeaderHelper: LargeScreenHeaderHelper,
+    private val weatherClockSection: WeatherClockSection,
+) : ComposableLockscreenSceneBlueprint {
+    override val id: String = SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID
+
+    @Composable
+    override fun SceneScope.Content(modifier: Modifier) {
+        val isUdfpsVisible = viewModel.isUdfpsVisible
+        val burnIn = rememberBurnIn(clockInteractor)
+        val resources = LocalContext.current.resources
+
+        LockscreenLongPress(
+            viewModel = viewModel.longPress,
+            modifier = modifier,
+        ) { onSettingsMenuPlaced ->
+            Layout(
+                content = {
+                    // Constrained to above the lock icon.
+                    Column(
+                        modifier = Modifier.fillMaxSize(),
+                    ) {
+                        with(statusBarSection) { StatusBar(modifier = Modifier.fillMaxWidth()) }
+                        Row(
+                            modifier = Modifier.fillMaxSize(),
+                        ) {
+                            // TODO: Add weather clock for small and large clock
+                            Column(
+                                modifier = Modifier.fillMaxHeight().weight(weight = 1f),
+                                horizontalAlignment = Alignment.CenterHorizontally,
+                            ) {
+                                with(smartSpaceSection) {
+                                    SmartSpace(
+                                        burnInParams = burnIn.parameters,
+                                        onTopChanged = burnIn.onSmartspaceTopChanged,
+                                        modifier =
+                                            Modifier.fillMaxWidth()
+                                                .padding(
+                                                    top = {
+                                                        viewModel.getSmartSpacePaddingTop(resources)
+                                                    },
+                                                )
+                                                .padding(
+                                                    bottom =
+                                                        dimensionResource(
+                                                            R.dimen
+                                                                .keyguard_status_view_bottom_margin
+                                                        )
+                                                ),
+                                    )
+                                }
+                            }
+                            with(notificationSection) {
+                                val splitShadeTopMargin: Dp =
+                                    if (Flags.centralizedStatusBarHeightFix()) {
+                                        largeScreenHeaderHelper.getLargeScreenHeaderHeight().dp
+                                    } else {
+                                        dimensionResource(
+                                            id = R.dimen.large_screen_shade_header_height
+                                        )
+                                    }
+                                Notifications(
+                                    modifier =
+                                        Modifier.fillMaxHeight()
+                                            .weight(weight = 1f)
+                                            .padding(top = splitShadeTopMargin)
+                                )
+                            }
+                        }
+
+                        if (!isUdfpsVisible && ambientIndicationSectionOptional.isPresent) {
+                            with(ambientIndicationSectionOptional.get()) {
+                                AmbientIndication(modifier = Modifier.fillMaxWidth())
+                            }
+                        }
+                    }
+
+                    with(lockSection) { LockIcon() }
+
+                    // Aligned to bottom and constrained to below the lock icon.
+                    Column(modifier = Modifier.fillMaxWidth()) {
+                        if (isUdfpsVisible && ambientIndicationSectionOptional.isPresent) {
+                            with(ambientIndicationSectionOptional.get()) {
+                                AmbientIndication(modifier = Modifier.fillMaxWidth())
+                            }
+                        }
+
+                        with(bottomAreaSection) {
+                            IndicationArea(modifier = Modifier.fillMaxWidth())
+                        }
+                    }
+
+                    // Aligned to bottom and NOT constrained by the lock icon.
+                    with(bottomAreaSection) {
+                        Shortcut(isStart = true, applyPadding = true)
+                        Shortcut(isStart = false, applyPadding = true)
+                    }
+                    with(settingsMenuSection) { SettingsMenu(onSettingsMenuPlaced) }
+                },
+                modifier = Modifier.fillMaxSize(),
+            ) { measurables, constraints ->
+                check(measurables.size == 6)
+                val aboveLockIconMeasurable = measurables[0]
+                val lockIconMeasurable = measurables[1]
+                val belowLockIconMeasurable = measurables[2]
+                val startShortcutMeasurable = measurables[3]
+                val endShortcutMeasurable = measurables[4]
+                val settingsMenuMeasurable = measurables[5]
+
+                val noMinConstraints =
+                    constraints.copy(
+                        minWidth = 0,
+                        minHeight = 0,
+                    )
+                val lockIconPlaceable = lockIconMeasurable.measure(noMinConstraints)
+                val lockIconBounds =
+                    IntRect(
+                        left = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Left],
+                        top = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Top],
+                        right = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Right],
+                        bottom = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Bottom],
+                    )
+
+                val aboveLockIconPlaceable =
+                    aboveLockIconMeasurable.measure(
+                        noMinConstraints.copy(maxHeight = lockIconBounds.top)
+                    )
+                val belowLockIconPlaceable =
+                    belowLockIconMeasurable.measure(
+                        noMinConstraints.copy(
+                            maxHeight =
+                                (constraints.maxHeight - lockIconBounds.bottom).coerceAtLeast(0)
+                        )
+                    )
+                val startShortcutPleaceable = startShortcutMeasurable.measure(noMinConstraints)
+                val endShortcutPleaceable = endShortcutMeasurable.measure(noMinConstraints)
+                val settingsMenuPlaceable = settingsMenuMeasurable.measure(noMinConstraints)
+
+                layout(constraints.maxWidth, constraints.maxHeight) {
+                    aboveLockIconPlaceable.place(
+                        x = 0,
+                        y = 0,
+                    )
+                    lockIconPlaceable.place(
+                        x = lockIconBounds.left,
+                        y = lockIconBounds.top,
+                    )
+                    belowLockIconPlaceable.place(
+                        x = 0,
+                        y = constraints.maxHeight - belowLockIconPlaceable.height,
+                    )
+                    startShortcutPleaceable.place(
+                        x = 0,
+                        y = constraints.maxHeight - startShortcutPleaceable.height,
+                    )
+                    endShortcutPleaceable.place(
+                        x = constraints.maxWidth - endShortcutPleaceable.width,
+                        y = constraints.maxHeight - endShortcutPleaceable.height,
+                    )
+                    settingsMenuPlaceable.place(
+                        x = (constraints.maxWidth - settingsMenuPlaceable.width) / 2,
+                        y = constraints.maxHeight - settingsMenuPlaceable.height,
+                    )
+                }
+            }
+        }
+    }
+}
+
+@Module
+interface WeatherClockBlueprintModule {
+    @Binds
+    @IntoSet
+    fun blueprint(blueprint: WeatherClockBlueprint): ComposableLockscreenSceneBlueprint
+}
+
+@Module
+interface SplitShadeWeatherClockBlueprintModule {
+    @Binds
+    @IntoSet
+    fun blueprint(blueprint: SplitShadeWeatherClockBlueprint): ComposableLockscreenSceneBlueprint
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/ClockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
similarity index 93%
rename from packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/ClockSection.kt
rename to packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
index fa07baf..335c915 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/ClockSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt
@@ -18,6 +18,7 @@
 
 import android.view.ViewGroup
 import android.widget.FrameLayout
+import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.padding
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
@@ -38,14 +39,17 @@
 import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel
 import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel
+import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
 import javax.inject.Inject
 
-class ClockSection
+/** Provides small clock and large clock composables for the default clock face. */
+class DefaultClockSection
 @Inject
 constructor(
     private val viewModel: KeyguardClockViewModel,
     private val clockInteractor: KeyguardClockInteractor,
     private val aodBurnInViewModel: AodBurnInViewModel,
+    private val lockscreenSmartspaceController: LockscreenSmartspaceController,
 ) {
 
     @Composable
@@ -151,6 +155,7 @@
                         (newClockView.parent as? ViewGroup)?.removeView(newClockView)
                         it.addView(newClockView)
                     },
+                    modifier = Modifier.fillMaxSize()
                 )
             }
         }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
index be6f022..31d3fa0 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt
@@ -18,6 +18,7 @@
 
 import android.content.Context
 import android.util.DisplayMetrics
+import android.view.View
 import android.view.WindowManager
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
@@ -45,6 +46,7 @@
 import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryIconViewModel
 import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.res.R
+import com.android.systemui.shade.NotificationPanelView
 import com.android.systemui.statusbar.VibratorHelper
 import dagger.Lazy
 import javax.inject.Inject
@@ -63,6 +65,7 @@
     private val deviceEntryBackgroundViewModel: Lazy<DeviceEntryBackgroundViewModel>,
     private val falsingManager: Lazy<FalsingManager>,
     private val vibratorHelper: Lazy<VibratorHelper>,
+    private val notificationPanelView: NotificationPanelView,
 ) {
     @Composable
     fun SceneScope.LockIcon(modifier: Modifier = Modifier) {
@@ -70,6 +73,10 @@
             return
         }
 
+        notificationPanelView.findViewById<View?>(R.id.lock_icon_view)?.let {
+            notificationPanelView.removeView(it)
+        }
+
         val context = LocalContext.current
 
         AndroidView(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt
new file mode 100644
index 0000000..2e7bc2a
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/WeatherClockSection.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2024 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.keyguard.ui.composable.section
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import com.android.compose.animation.scene.SceneScope
+import javax.inject.Inject
+
+/** Provides small clock and large clock composables for the weather clock layout. */
+class WeatherClockSection @Inject constructor() {
+    @Composable
+    fun SceneScope.Time(
+        modifier: Modifier = Modifier,
+    ) {
+        // TODO: compose view
+    }
+
+    @Composable
+    fun SceneScope.Date(
+        modifier: Modifier = Modifier,
+    ) {
+        // TODO: compose view
+    }
+
+    @Composable
+    fun SceneScope.Weather(
+        modifier: Modifier = Modifier,
+    ) {
+        // TODO: compose view
+    }
+
+    @Composable
+    fun SceneScope.DndAlarmStatus(
+        modifier: Modifier = Modifier,
+    ) {
+        // TODO: compose view
+    }
+
+    @Composable
+    fun SceneScope.Temperature(
+        modifier: Modifier = Modifier,
+    ) {
+        // TODO: compose view
+    }
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
index 66cef86..6875bc5 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
@@ -40,7 +40,6 @@
 import androidx.compose.foundation.layout.wrapContentHeight
 import androidx.compose.foundation.rememberScrollState
 import androidx.compose.foundation.verticalScroll
-import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
@@ -51,6 +50,7 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.platform.LocalLifecycleOwner
+import androidx.compose.ui.res.colorResource
 import androidx.compose.ui.unit.dp
 import com.android.compose.animation.scene.SceneScope
 import com.android.compose.animation.scene.TransitionState
@@ -62,6 +62,7 @@
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.qs.footer.ui.compose.FooterActions
 import com.android.systemui.qs.ui.viewmodel.QuickSettingsSceneViewModel
+import com.android.systemui.res.R
 import com.android.systemui.scene.shared.model.SceneKey
 import com.android.systemui.scene.ui.composable.ComposableScene
 import com.android.systemui.scene.ui.composable.asComposeAware
@@ -168,7 +169,7 @@
             modifier =
                 Modifier.element(Shade.Elements.BackgroundScrim)
                     .fillMaxSize()
-                    .background(MaterialTheme.colorScheme.scrim)
+                    .background(colorResource(R.color.shade_scrim_background_dark))
         )
         Column(
             horizontalAlignment = Alignment.CenterHorizontally,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposeAwareExtensions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposeAwareExtensions.kt
index a7de1ee..0de4650 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposeAwareExtensions.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposeAwareExtensions.kt
@@ -16,9 +16,6 @@
 
 package com.android.systemui.scene.ui.composable
 
-import androidx.compose.foundation.gestures.Orientation
-import androidx.compose.ui.unit.Density
-import androidx.compose.ui.unit.IntSize
 import com.android.compose.animation.scene.Back
 import com.android.compose.animation.scene.Edge as ComposeAwareEdge
 import com.android.compose.animation.scene.SceneKey as ComposeAwareSceneKey
@@ -26,14 +23,12 @@
 import com.android.compose.animation.scene.SwipeDirection
 import com.android.compose.animation.scene.TransitionKey as ComposeAwareTransitionKey
 import com.android.compose.animation.scene.UserAction as ComposeAwareUserAction
-import com.android.compose.animation.scene.UserActionDistance as ComposeAwareUserActionDistance
 import com.android.compose.animation.scene.UserActionResult as ComposeAwareUserActionResult
 import com.android.systemui.scene.shared.model.Direction
 import com.android.systemui.scene.shared.model.Edge
 import com.android.systemui.scene.shared.model.SceneKey
 import com.android.systemui.scene.shared.model.TransitionKey
 import com.android.systemui.scene.shared.model.UserAction
-import com.android.systemui.scene.shared.model.UserActionDistance
 import com.android.systemui.scene.shared.model.UserActionResult
 
 // TODO(b/293899074): remove this file once we can use the types from SceneTransitionLayout.
@@ -82,22 +77,5 @@
     return ComposeAwareUserActionResult(
         toScene = composeUnaware.toScene.asComposeAware(),
         transitionKey = composeUnaware.transitionKey?.asComposeAware(),
-        distance = composeUnaware.distance?.asComposeAware(),
     )
 }
-
-fun UserActionDistance.asComposeAware(): ComposeAwareUserActionDistance {
-    val composeUnware = this
-    return object : ComposeAwareUserActionDistance {
-        override fun Density.absoluteDistance(
-            fromSceneSize: IntSize,
-            orientation: Orientation,
-        ): Float {
-            return composeUnware.absoluteDistance(
-                fromSceneWidth = fromSceneSize.width,
-                fromSceneHeight = fromSceneSize.height,
-                isHorizontal = orientation == Orientation.Horizontal,
-            )
-        }
-    }
-}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
index 2e0ce42..8484b7f 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
@@ -26,7 +26,6 @@
 import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.collectAsState
 import androidx.compose.runtime.getValue
@@ -37,6 +36,7 @@
 import androidx.compose.ui.layout.Layout
 import androidx.compose.ui.layout.layout
 import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.res.colorResource
 import androidx.compose.ui.res.dimensionResource
 import androidx.compose.ui.unit.dp
 import com.android.compose.animation.scene.ElementKey
@@ -171,7 +171,7 @@
         modifier =
             modifier
                 .element(Shade.Elements.BackgroundScrim)
-                .background(MaterialTheme.colorScheme.scrim),
+                .background(colorResource(R.color.shade_scrim_background_dark)),
     )
     Box {
         Layout(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/bottombar/ui/BottomBarComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/bottombar/ui/BottomBarComponent.kt
index d401261..c08eb94 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/bottombar/ui/BottomBarComponent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/bottombar/ui/BottomBarComponent.kt
@@ -19,17 +19,17 @@
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.heightIn
+import androidx.compose.material3.Button
 import androidx.compose.material3.ButtonDefaults
 import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.OutlinedButton
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.unit.dp
-import com.android.compose.PlatformButton
-import com.android.compose.PlatformOutlinedButton
 import com.android.systemui.res.R
 import com.android.systemui.volume.panel.component.bottombar.ui.viewmodel.BottomBarViewModel
 import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
@@ -47,11 +47,11 @@
     @Composable
     override fun VolumePanelComposeScope.Content(modifier: Modifier) {
         Row(
-            modifier = modifier.height(if (isLargeScreen) 54.dp else 48.dp).fillMaxWidth(),
+            modifier = modifier.heightIn(min = if (isLargeScreen) 54.dp else 48.dp).fillMaxWidth(),
             horizontalArrangement = Arrangement.SpaceBetween,
             verticalAlignment = Alignment.CenterVertically,
         ) {
-            PlatformOutlinedButton(
+            OutlinedButton(
                 onClick = viewModel::onSettingsClicked,
                 colors =
                     ButtonDefaults.outlinedButtonColors(
@@ -60,8 +60,8 @@
             ) {
                 Text(text = stringResource(R.string.volume_panel_dialog_settings_button))
             }
-            PlatformButton(onClick = viewModel::onDoneClicked) {
-                Text(text = stringResource(R.string.inline_done_button))
+            Button(onClick = viewModel::onDoneClicked) {
+                Text(stringResource(R.string.inline_done_button))
             }
         }
     }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt
index d49fed5..b3fcc30 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt
@@ -27,6 +27,7 @@
 import androidx.compose.animation.slideInVertically
 import androidx.compose.animation.slideOutVertically
 import androidx.compose.animation.togetherWith
+import androidx.compose.foundation.basicMarquee
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
@@ -46,7 +47,6 @@
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.dp
 import com.android.compose.animation.Expandable
 import com.android.systemui.common.ui.compose.Icon
@@ -78,8 +78,8 @@
             color = MaterialTheme.colorScheme.surface,
             shape = RoundedCornerShape(28.dp),
             onClick = { viewModel.onBarClick(it) },
-        ) {
-            Row {
+        ) { _ ->
+            Row(verticalAlignment = Alignment.CenterVertically) {
                 connectedDeviceViewModel?.let { ConnectedDeviceText(it) }
 
                 deviceIconViewModel?.let { ConnectedDeviceIcon(it) }
@@ -90,26 +90,23 @@
     @Composable
     private fun RowScope.ConnectedDeviceText(connectedDeviceViewModel: ConnectedDeviceViewModel) {
         Column(
-            modifier =
-                Modifier.weight(1f)
-                    .padding(start = 24.dp, top = 20.dp, bottom = 20.dp)
-                    .fillMaxHeight(),
+            modifier = Modifier.weight(1f).padding(start = 24.dp),
             verticalArrangement = Arrangement.spacedBy(4.dp),
         ) {
             Text(
-                connectedDeviceViewModel.label.toString(),
+                modifier = Modifier.basicMarquee(),
+                text = connectedDeviceViewModel.label.toString(),
                 style = MaterialTheme.typography.labelMedium,
                 color = MaterialTheme.colorScheme.onSurfaceVariant,
                 maxLines = 1,
-                overflow = TextOverflow.Ellipsis,
             )
             connectedDeviceViewModel.deviceName?.let {
                 Text(
-                    it.toString(),
+                    modifier = Modifier.basicMarquee(),
+                    text = it.toString(),
                     style = MaterialTheme.typography.titleMedium,
                     color = MaterialTheme.colorScheme.onSurface,
                     maxLines = 1,
-                    overflow = TextOverflow.Ellipsis,
                 )
             }
         }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/VolumeSlidersModule.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/VolumeSlidersModule.kt
new file mode 100644
index 0000000..453ff02
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/VolumeSlidersModule.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 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.volume.panel.component.volume
+
+import com.android.systemui.volume.panel.component.shared.model.VolumePanelComponents
+import com.android.systemui.volume.panel.component.volume.ui.composable.VolumeSlidersComponent
+import com.android.systemui.volume.panel.domain.AlwaysAvailableCriteria
+import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria
+import com.android.systemui.volume.panel.shared.model.VolumePanelUiComponent
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.IntoMap
+import dagger.multibindings.StringKey
+
+@Module
+interface VolumeSlidersModule {
+
+    @Binds
+    @IntoMap
+    @StringKey(VolumePanelComponents.VOLUME_SLIDERS)
+    fun bindVolumePanelUiComponent(component: VolumeSlidersComponent): VolumePanelUiComponent
+
+    @Binds
+    @IntoMap
+    @StringKey(VolumePanelComponents.VOLUME_SLIDERS)
+    fun bindComponentAvailabilityCriteria(
+        criteria: AlwaysAvailableCriteria
+    ): ComponentAvailabilityCriteria
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt
new file mode 100644
index 0000000..4d810df
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2024 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.volume.panel.component.volume.ui.composable
+
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.EnterTransition
+import androidx.compose.animation.ExitTransition
+import androidx.compose.animation.ExperimentalAnimationApi
+import androidx.compose.animation.core.tween
+import androidx.compose.animation.core.updateTransition
+import androidx.compose.animation.expandVertically
+import androidx.compose.animation.fadeIn
+import androidx.compose.animation.fadeOut
+import androidx.compose.animation.scaleIn
+import androidx.compose.animation.scaleOut
+import androidx.compose.animation.shrinkVertically
+import androidx.compose.animation.slideInVertically
+import androidx.compose.animation.slideOutVertically
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.IconButtonDefaults
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.unit.dp
+import com.android.compose.PlatformSliderColors
+import com.android.systemui.res.R
+import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderViewModel
+
+private const val EXPAND_DURATION_MILLIS = 500
+private const val COLLAPSE_DURATION_MILLIS = 300
+
+/** Volume sliders laid out in a collapsable column */
+@OptIn(ExperimentalAnimationApi::class)
+@Composable
+fun ColumnVolumeSliders(
+    viewModels: List<SliderViewModel>,
+    sliderColors: PlatformSliderColors,
+    isExpandable: Boolean,
+    modifier: Modifier = Modifier,
+) {
+    require(viewModels.isNotEmpty())
+    var isExpanded: Boolean by remember(isExpandable) { mutableStateOf(!isExpandable) }
+    val transition = updateTransition(isExpanded, label = "CollapsableSliders")
+    Column(modifier = modifier) {
+        Row(
+            modifier = Modifier.fillMaxWidth(),
+            horizontalArrangement = Arrangement.spacedBy(8.dp),
+        ) {
+            val sliderViewModel: SliderViewModel = viewModels.first()
+            val sliderState by viewModels.first().slider.collectAsState()
+            VolumeSlider(
+                modifier = Modifier.weight(1f),
+                state = sliderState,
+                onValueChangeFinished = { sliderViewModel.onValueChangeFinished(sliderState, it) },
+                sliderColors = sliderColors,
+            )
+
+            if (isExpandable) {
+                ExpandButton(
+                    isExpanded = isExpanded,
+                    onExpandedChanged = { isExpanded = it },
+                    sliderColors,
+                    Modifier,
+                )
+            }
+        }
+        transition.AnimatedVisibility(
+            visible = { it },
+            enter =
+                expandVertically(
+                    animationSpec = tween(durationMillis = EXPAND_DURATION_MILLIS),
+                    expandFrom = Alignment.CenterVertically,
+                ),
+            exit =
+                shrinkVertically(
+                    animationSpec = tween(durationMillis = COLLAPSE_DURATION_MILLIS),
+                    shrinkTowards = Alignment.CenterVertically,
+                ),
+        ) {
+            Column(modifier = Modifier.fillMaxWidth()) {
+                for (index in 1..viewModels.lastIndex) {
+                    val sliderViewModel: SliderViewModel = viewModels[index]
+                    val sliderState by sliderViewModel.slider.collectAsState()
+                    transition.AnimatedVisibility(
+                        visible = { it },
+                        enter = enterTransition(index = index, totalCount = viewModels.size),
+                        exit = exitTransition(index = index, totalCount = viewModels.size)
+                    ) {
+                        VolumeSlider(
+                            modifier = Modifier.fillMaxWidth().padding(top = 16.dp),
+                            state = sliderState,
+                            onValueChangeFinished = {
+                                sliderViewModel.onValueChangeFinished(sliderState, it)
+                            },
+                            sliderColors = sliderColors,
+                        )
+                    }
+                }
+            }
+        }
+    }
+}
+
+@Composable
+private fun ExpandButton(
+    isExpanded: Boolean,
+    onExpandedChanged: (Boolean) -> Unit,
+    sliderColors: PlatformSliderColors,
+    modifier: Modifier = Modifier,
+) {
+    IconButton(
+        modifier = modifier.size(64.dp),
+        onClick = { onExpandedChanged(!isExpanded) },
+        colors =
+            IconButtonDefaults.filledIconButtonColors(
+                containerColor = sliderColors.indicatorColor,
+                contentColor = sliderColors.iconColor
+            ),
+    ) {
+        Icon(
+            painter =
+                painterResource(
+                    if (isExpanded) {
+                        R.drawable.ic_filled_arrow_down
+                    } else {
+                        R.drawable.ic_filled_arrow_up
+                    }
+                ),
+            contentDescription = null,
+        )
+    }
+}
+
+private fun enterTransition(index: Int, totalCount: Int): EnterTransition {
+    val enterDelay = ((totalCount - index + 1) * 10).coerceAtLeast(0)
+    val enterDuration = (EXPAND_DURATION_MILLIS - enterDelay).coerceAtLeast(100)
+    return slideInVertically(
+        initialOffsetY = { (it * 0.25).toInt() },
+        animationSpec = tween(durationMillis = enterDuration, delayMillis = enterDelay),
+    ) +
+        scaleIn(
+            initialScale = 0.9f,
+            animationSpec = tween(durationMillis = enterDuration, delayMillis = enterDelay),
+        ) +
+        expandVertically(
+            initialHeight = { (it * 0.65).toInt() },
+            animationSpec = tween(durationMillis = enterDuration, delayMillis = enterDelay),
+            clip = false,
+            expandFrom = Alignment.CenterVertically,
+        ) +
+        fadeIn(
+            animationSpec = tween(durationMillis = enterDuration, delayMillis = enterDelay),
+        )
+}
+
+private fun exitTransition(index: Int, totalCount: Int): ExitTransition {
+    val exitDuration = (COLLAPSE_DURATION_MILLIS - (totalCount - index + 1) * 10).coerceAtLeast(100)
+    return slideOutVertically(
+        targetOffsetY = { (it * 0.25).toInt() },
+        animationSpec = tween(durationMillis = exitDuration),
+    ) +
+        scaleOut(
+            targetScale = 0.9f,
+            animationSpec = tween(durationMillis = exitDuration),
+        ) +
+        shrinkVertically(
+            targetHeight = { (it * 0.65).toInt() },
+            animationSpec = tween(durationMillis = exitDuration),
+            clip = false,
+            shrinkTowards = Alignment.CenterVertically,
+        ) +
+        fadeOut(animationSpec = tween(durationMillis = exitDuration))
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/GridVolumeSliders.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/GridVolumeSliders.kt
new file mode 100644
index 0000000..910ee72
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/GridVolumeSliders.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2024 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.volume.panel.component.volume.ui.composable
+
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import com.android.compose.PlatformSliderColors
+import com.android.compose.grid.VerticalGrid
+import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderViewModel
+
+@Composable
+fun GridVolumeSliders(
+    viewModels: List<SliderViewModel>,
+    sliderColors: PlatformSliderColors,
+    modifier: Modifier = Modifier,
+) {
+    require(viewModels.isNotEmpty())
+    VerticalGrid(
+        modifier = modifier,
+        columns = 2,
+        verticalSpacing = 16.dp,
+        horizontalSpacing = 24.dp,
+    ) {
+        for (sliderViewModel in viewModels) {
+            val sliderState = sliderViewModel.slider.collectAsState().value
+            VolumeSlider(
+                modifier = Modifier.fillMaxWidth(),
+                state = sliderState,
+                onValueChangeFinished = { sliderViewModel.onValueChangeFinished(sliderState, it) },
+                sliderColors = sliderColors,
+            )
+        }
+    }
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt
new file mode 100644
index 0000000..18a62dc
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlider.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2024 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.volume.panel.component.volume.ui.composable
+
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.animateContentSize
+import androidx.compose.animation.expandVertically
+import androidx.compose.animation.shrinkVertically
+import androidx.compose.foundation.basicMarquee
+import androidx.compose.foundation.layout.Column
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableFloatStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import com.android.compose.PlatformSlider
+import com.android.compose.PlatformSliderColors
+import com.android.systemui.common.ui.compose.Icon
+import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderState
+
+@Composable
+fun VolumeSlider(
+    state: SliderState,
+    onValueChangeFinished: (Float) -> Unit,
+    modifier: Modifier = Modifier,
+    sliderColors: PlatformSliderColors,
+) {
+    var value by remember(state.value) { mutableFloatStateOf(state.value) }
+    PlatformSlider(
+        modifier = modifier,
+        value = value,
+        valueRange = state.valueRange,
+        onValueChange = { value = it },
+        onValueChangeFinished = { onValueChangeFinished(value) },
+        enabled = state.isEnabled,
+        icon = { isDragging ->
+            if (isDragging) {
+                Text(text = value.toInt().toString())
+            } else {
+                state.icon?.let { Icon(icon = it) }
+            }
+        },
+        colors = sliderColors,
+        label = {
+            Column(modifier = Modifier.animateContentSize()) {
+                Text(
+                    modifier = Modifier.basicMarquee(),
+                    text = state.label,
+                    style = MaterialTheme.typography.titleMedium,
+                    maxLines = 1,
+                )
+
+                state.disabledMessage?.let { message ->
+                    AnimatedVisibility(
+                        !state.isEnabled,
+                        enter = expandVertically { it },
+                        exit = shrinkVertically { it },
+                    ) {
+                        Text(
+                            modifier = Modifier.basicMarquee(),
+                            text = message,
+                            style = MaterialTheme.typography.bodySmall,
+                            maxLines = 1,
+                        )
+                    }
+                }
+            }
+        }
+    )
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlidersComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlidersComponent.kt
new file mode 100644
index 0000000..1ca18de
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlidersComponent.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2024 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.volume.panel.component.volume.ui.composable
+
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Modifier
+import com.android.compose.PlatformSliderDefaults
+import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderViewModel
+import com.android.systemui.volume.panel.component.volume.ui.viewmodel.AudioVolumeComponentViewModel
+import com.android.systemui.volume.panel.ui.composable.ComposeVolumePanelUiComponent
+import com.android.systemui.volume.panel.ui.composable.VolumePanelComposeScope
+import com.android.systemui.volume.panel.ui.composable.isPortrait
+import javax.inject.Inject
+
+class VolumeSlidersComponent
+@Inject
+constructor(
+    private val viewModel: AudioVolumeComponentViewModel,
+) : ComposeVolumePanelUiComponent {
+
+    @Composable
+    override fun VolumePanelComposeScope.Content(modifier: Modifier) {
+        val sliderViewModels: List<SliderViewModel> by viewModel.sliderViewModels.collectAsState()
+        if (sliderViewModels.isEmpty()) {
+            return
+        }
+        if (isLargeScreen) {
+            GridVolumeSliders(
+                viewModels = sliderViewModels,
+                sliderColors = PlatformSliderDefaults.defaultPlatformSliderColors(),
+                modifier = modifier.fillMaxWidth(),
+            )
+        } else {
+            ColumnVolumeSliders(
+                viewModels = sliderViewModels,
+                sliderColors = PlatformSliderDefaults.defaultPlatformSliderColors(),
+                isExpandable = isPortrait,
+                modifier = modifier.fillMaxWidth(),
+            )
+        }
+    }
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/HorizontalVolumePanelContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/HorizontalVolumePanelContent.kt
index 98ef067..ac5004e 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/HorizontalVolumePanelContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/HorizontalVolumePanelContent.kt
@@ -21,7 +21,8 @@
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
@@ -36,7 +37,7 @@
     val spacing = 20.dp
     Row(modifier = modifier, horizontalArrangement = Arrangement.spacedBy(space = spacing)) {
         Column(
-            modifier = Modifier.weight(1f),
+            modifier = Modifier.weight(1f).verticalScroll(rememberScrollState()),
             verticalArrangement = Arrangement.spacedBy(spacing)
         ) {
             for (component in layout.contentComponents) {
@@ -47,24 +48,25 @@
         }
 
         Column(
-            modifier = Modifier.weight(1f),
+            modifier = Modifier.weight(1f).verticalScroll(rememberScrollState()),
             verticalArrangement = Arrangement.spacedBy(space = spacing, alignment = Alignment.Top)
         ) {
             for (component in layout.headerComponents) {
-                AnimatedVisibility(component.isVisible) {
-                    with(component.component as ComposeVolumePanelUiComponent) {
-                        Content(Modifier.weight(1f))
-                    }
+                AnimatedVisibility(visible = component.isVisible) {
+                    with(component.component as ComposeVolumePanelUiComponent) { Content(Modifier) }
                 }
             }
             Row(
-                modifier = Modifier.fillMaxWidth().wrapContentHeight(),
+                modifier = Modifier.fillMaxWidth(),
                 horizontalArrangement = Arrangement.spacedBy(spacing),
             ) {
                 for (component in layout.footerComponents) {
-                    AnimatedVisibility(component.isVisible) {
+                    AnimatedVisibility(
+                        visible = component.isVisible,
+                        modifier = Modifier.weight(1f),
+                    ) {
                         with(component.component as ComposeVolumePanelUiComponent) {
-                            Content(Modifier.weight(1f))
+                            Content(Modifier)
                         }
                     }
                 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VerticalVolumePanelContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VerticalVolumePanelContent.kt
index 2285128..dd76781 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VerticalVolumePanelContent.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VerticalVolumePanelContent.kt
@@ -17,12 +17,13 @@
 package com.android.systemui.volume.panel.ui.composable
 
 import androidx.compose.animation.AnimatedVisibility
-import androidx.compose.animation.animateContentSize
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.unit.dp
@@ -34,14 +35,12 @@
     modifier: Modifier = Modifier,
 ) {
     Column(
-        modifier = modifier.animateContentSize(),
+        modifier = modifier.verticalScroll(rememberScrollState()),
         verticalArrangement = Arrangement.spacedBy(20.dp),
     ) {
         for (component in layout.headerComponents) {
             AnimatedVisibility(component.isVisible) {
-                with(component.component as ComposeVolumePanelUiComponent) {
-                    Content(Modifier.weight(1f))
-                }
+                with(component.component as ComposeVolumePanelUiComponent) { Content(Modifier) }
             }
         }
         for (component in layout.contentComponents) {
@@ -55,9 +54,12 @@
                 horizontalArrangement = Arrangement.spacedBy(if (isLargeScreen) 28.dp else 20.dp),
             ) {
                 for (component in layout.footerComponents) {
-                    AnimatedVisibility(component.isVisible) {
+                    AnimatedVisibility(
+                        visible = component.isVisible,
+                        modifier = Modifier.weight(1f),
+                    ) {
                         with(component.component as ComposeVolumePanelUiComponent) {
-                            Content(Modifier.weight(1f))
+                            Content(Modifier)
                         }
                     }
                 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelComposeScope.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelComposeScope.kt
index 8df8d2e..af69091 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelComposeScope.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelComposeScope.kt
@@ -29,7 +29,7 @@
 
     /** Is true when Volume Panel is using large-screen layout and false the otherwise. */
     val isLargeScreen: Boolean
-        get() = state.isWideScreen
+        get() = state.isLargeScreen
 }
 
 val VolumePanelComposeScope.isPortrait: Boolean
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt
index 8a1e6a8..910cd5e 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt
@@ -16,12 +16,13 @@
 
 package com.android.systemui.volume.panel.ui.composable
 
-import android.content.res.Configuration
 import androidx.compose.foundation.clickable
 import androidx.compose.foundation.isSystemInDarkTheme
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.displayCutout
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.heightIn
@@ -37,13 +38,17 @@
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.platform.LocalLayoutDirection
 import androidx.compose.ui.res.dimensionResource
 import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.max
 import com.android.compose.theme.PlatformTheme
 import com.android.systemui.res.R
 import com.android.systemui.volume.panel.ui.layout.ComponentsLayout
 import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelState
 import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelViewModel
+import kotlin.math.max
 
 private val padding = 24.dp
 
@@ -66,12 +71,12 @@
         val components by viewModel.componentsLayout.collectAsState(null)
 
         with(VolumePanelComposeScope(state)) {
-            var boxModifier = modifier.fillMaxSize().clickable(onClick = onDismiss)
-            if (!isPortrait) {
-                boxModifier = boxModifier.padding(horizontal = 48.dp)
-            }
             Box(
-                modifier = boxModifier,
+                modifier =
+                    modifier
+                        .fillMaxSize()
+                        .clickable(onClick = onDismiss)
+                        .volumePanelPaddings(isPortrait = isPortrait),
                 contentAlignment = Alignment.BottomCenter,
             ) {
                 val radius = dimensionResource(R.dimen.volume_panel_corner_radius)
@@ -81,8 +86,8 @@
                             interactionSource = null,
                             indication = null,
                             onClick = {
-                                // prevent windowCloseOnTouchOutside from dismissing when tapped on
-                                // the panel itself.
+                                // prevent windowCloseOnTouchOutside from dismissing when tapped
+                                // on the panel itself.
                             },
                         ),
                     shape = RoundedCornerShape(topStart = radius, topEnd = radius),
@@ -111,17 +116,31 @@
     layout: ComponentsLayout,
     modifier: Modifier = Modifier
 ) {
-    var columnModifier = modifier.widthIn(max = 800.dp)
-    if (!isLargeScreen && orientation != Configuration.ORIENTATION_PORTRAIT) {
-        columnModifier = columnModifier.heightIn(max = 332.dp)
-    }
-    Column(modifier = columnModifier, verticalArrangement = Arrangement.spacedBy(padding)) {
-        if (orientation == Configuration.ORIENTATION_PORTRAIT || isLargeScreen) {
-            VerticalVolumePanelContent(layout)
+    val arrangement: Arrangement.Vertical =
+        if (isLargeScreen) {
+            Arrangement.spacedBy(20.dp)
         } else {
-            HorizontalVolumePanelContent(layout)
+            if (isPortrait) Arrangement.spacedBy(padding) else Arrangement.spacedBy(4.dp)
         }
-        BottomBar(layout = layout, modifier = Modifier)
+    Column(
+        modifier = modifier.widthIn(max = 800.dp),
+        verticalArrangement = arrangement,
+    ) {
+        if (isPortrait || isLargeScreen) {
+            VerticalVolumePanelContent(
+                modifier = Modifier.weight(weight = 1f, fill = false),
+                layout = layout
+            )
+        } else {
+            HorizontalVolumePanelContent(
+                modifier = Modifier.weight(weight = 1f, fill = false).heightIn(max = 212.dp),
+                layout = layout,
+            )
+        }
+        BottomBar(
+            modifier = Modifier,
+            layout = layout,
+        )
     }
 }
 
@@ -141,3 +160,28 @@
         }
     }
 }
+
+/**
+ * Makes sure volume panel stays symmetrically in the middle of the screen while still avoiding
+ * being under the cutouts.
+ */
+@Composable
+private fun Modifier.volumePanelPaddings(isPortrait: Boolean): Modifier {
+    val cutout = WindowInsets.displayCutout
+    return with(LocalDensity.current) {
+        val horizontalCutout =
+            max(
+                cutout.getLeft(density = this, layoutDirection = LocalLayoutDirection.current),
+                cutout.getRight(density = this, layoutDirection = LocalLayoutDirection.current)
+            )
+        val minHorizontalPadding = if (isPortrait) 0.dp else 48.dp
+        val horizontalPadding = max(horizontalCutout.toDp(), minHorizontalPadding)
+
+        padding(
+            start = horizontalPadding,
+            top = cutout.getTop(this).toDp(),
+            end = horizontalPadding,
+            bottom = cutout.getBottom(this).toDp(),
+        )
+    }
+}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
index 2e781e6..c7186da 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
@@ -39,7 +39,6 @@
 import androidx.compose.ui.node.DrawModifierNode
 import androidx.compose.ui.node.ModifierNodeElement
 import androidx.compose.ui.platform.testTag
-import androidx.compose.ui.semantics.testTag
 import androidx.compose.ui.unit.Constraints
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.round
@@ -204,6 +203,17 @@
         measurable: Measurable,
         constraints: Constraints,
     ): MeasureResult {
+        val overscrollScene = layoutImpl.state.currentOverscrollSpec?.scene
+        if (overscrollScene != null && overscrollScene != scene.key) {
+            // There is an overscroll in progress on another scene
+            // By measuring composable elements, Compose can cache relevant information.
+            // This reduces the need for re-measure when users return from an overscroll animation.
+            val placeable = measurable.measure(constraints)
+            return layout(placeable.width, placeable.height) {
+                // We don't want to draw it, no need to place the element.
+            }
+        }
+
         val placeable = measure(layoutImpl, scene, element, sceneState, measurable, constraints)
         return layout(placeable.width, placeable.height) {
             place(layoutImpl, scene, element, sceneState, placeable, placementScope = this)
@@ -253,11 +263,13 @@
 ): Boolean {
     val transition = layoutImpl.state.currentTransition
 
-    // Always draw the element if there is no ongoing transition or if the element is not shared.
+    // Always draw the element if there is no ongoing transition or if the element is not shared or
+    // if the current scene is the one that is currently over scrolling with [OverscrollSpec].
     if (
         transition == null ||
             transition.fromScene !in element.sceneStates ||
-            transition.toScene !in element.sceneStates
+            transition.toScene !in element.sceneStates ||
+            layoutImpl.state.currentOverscrollSpec?.scene == scene.key
     ) {
         return true
     }
@@ -286,12 +298,14 @@
     val fromScene = transition.fromScene
     val toScene = transition.toScene
 
-    return scenePicker.sceneDuringTransition(
-        element = element,
-        transition = transition,
-        fromSceneZIndex = layoutImpl.scenes.getValue(fromScene).zIndex,
-        toSceneZIndex = layoutImpl.scenes.getValue(toScene).zIndex,
-    ) == scene
+    val chosenByPicker =
+        scenePicker.sceneDuringTransition(
+            element = element,
+            transition = transition,
+            fromSceneZIndex = layoutImpl.scenes.getValue(fromScene).zIndex,
+            toSceneZIndex = layoutImpl.scenes.getValue(toScene).zIndex,
+        ) == scene
+    return chosenByPicker || layoutImpl.state.currentOverscrollSpec?.scene == scene
 }
 
 private fun isSharedElementEnabled(
@@ -549,6 +563,40 @@
         return idleValue
     }
 
+    if (transition is TransitionState.HasOverscrollProperties) {
+        val overscroll = layoutImpl.state.currentOverscrollSpec
+        if (overscroll?.scene == scene.key) {
+            val elementSpec = overscroll.transformationSpec.transformations(element.key, scene.key)
+            val propertySpec = transformation(elementSpec) ?: return currentValue()
+            val overscrollState = checkNotNull(if (scene.key == toScene) toState else fromState)
+            val targetValue =
+                propertySpec.transform(
+                    layoutImpl,
+                    scene,
+                    element,
+                    overscrollState,
+                    transition,
+                    idleValue,
+                )
+
+            // Make sure we don't read progress if values are the same and we don't need to
+            // interpolate, so we don't invalidate the phase where this is read.
+            if (targetValue == idleValue) {
+                return targetValue
+            }
+
+            // TODO(b/290184746): Make sure that we don't overflow transformations associated to a
+            // range.
+            val directionSign = if (transition.isUpOrLeft) -1 else 1
+            val overscrollProgress = transition.progress.let { if (it > 1f) it - 1f else it }
+            val progress = directionSign * overscrollProgress
+            val rangeProgress = propertySpec.range?.progress(progress) ?: progress
+
+            // Interpolate between the value at rest and the over scrolled value.
+            return lerp(idleValue, targetValue, rangeProgress)
+        }
+    }
+
     // The element is shared: interpolate between the value in fromScene and the value in toScene.
     // TODO(b/290184746): Support non linear shared paths as well as a way to make sure that shared
     // elements follow the finger direction.
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
index 76e7c95..187d82a 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
@@ -27,7 +27,6 @@
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.round
@@ -56,14 +55,17 @@
         if (isDrivingTransition || force) {
             layoutState.startTransition(newTransition, newTransition.key)
 
-            // Initialize SwipeTransition.swipeSpec. Note that this must be called right after
-            // layoutState.startTransition() is called, because it computes the
-            // layoutState.transformationSpec().
+            // Initialize SwipeTransition.transformationSpec and .swipeSpec. Note that this must be
+            // called right after layoutState.startTransition() is called, because it computes the
+            // current layoutState.transformationSpec().
+            val transformationSpec = layoutState.transformationSpec
+            newTransition.transformationSpec = transformationSpec
             newTransition.swipeSpec =
-                layoutState.transformationSpec.swipeSpec ?: layoutState.transitions.defaultSwipeSpec
+                transformationSpec.swipeSpec ?: layoutState.transitions.defaultSwipeSpec
         } else {
-            // We were not driving the transition and we don't force the update, so the spec won't
-            // be used and it doesn't matter which one we set here.
+            // We were not driving the transition and we don't force the update, so the specs won't
+            // be used and it doesn't matter which ones we set here.
+            newTransition.transformationSpec = TransformationSpec.Empty
             newTransition.swipeSpec = SceneTransitions.DefaultSwipeSpec
         }
 
@@ -285,16 +287,21 @@
     ): Pair<Scene, Float> {
         val toScene = swipeTransition._toScene
         val fromScene = swipeTransition._fromScene
-        val absoluteDistance = swipeTransition.distance.absoluteValue
+        val distance = swipeTransition.distance()
 
-        // If the swipe was not committed, don't do anything.
-        if (swipeTransition._currentScene != toScene) {
+        // If the swipe was not committed or if the swipe distance is not computed yet, don't do
+        // anything.
+        if (
+            swipeTransition._currentScene != toScene ||
+                distance == SwipeTransition.DistanceUnspecified
+        ) {
             return fromScene to 0f
         }
 
         // If the offset is past the distance then let's change fromScene so that the user can swipe
         // to the next screen or go back to the previous one.
         val offset = swipeTransition.dragOffset
+        val absoluteDistance = distance.absoluteValue
         return if (offset <= -absoluteDistance && swipes!!.upOrLeftResult?.toScene == toScene.key) {
             toScene to absoluteDistance
         } else if (
@@ -347,16 +354,17 @@
 
             // Compute the destination scene (and therefore offset) to settle in.
             val offset = swipeTransition.dragOffset
-            val distance = swipeTransition.distance
+            val distance = swipeTransition.distance()
             var targetScene: Scene
             var targetOffset: Float
             if (
-                shouldCommitSwipe(
-                    offset,
-                    distance,
-                    velocity,
-                    wasCommitted = swipeTransition._currentScene == toScene,
-                )
+                distance != SwipeTransition.DistanceUnspecified &&
+                    shouldCommitSwipe(
+                        offset,
+                        distance,
+                        velocity,
+                        wasCommitted = swipeTransition._currentScene == toScene,
+                    )
             ) {
                 targetScene = toScene
                 targetOffset = distance
@@ -372,7 +380,15 @@
                 // We wanted to change to a new scene but we are not allowed to, so we animate back
                 // to the current scene.
                 targetScene = swipeTransition._currentScene
-                targetOffset = if (targetScene == fromScene) 0f else distance
+                targetOffset =
+                    if (targetScene == fromScene) {
+                        0f
+                    } else {
+                        check(distance != SwipeTransition.DistanceUnspecified) {
+                            "distance is equal to ${SwipeTransition.DistanceUnspecified}"
+                        }
+                        distance
+                    }
             }
 
             animateTo(targetScene = targetScene, targetOffset = targetOffset)
@@ -459,22 +475,20 @@
 ): SwipeTransition {
     val upOrLeftResult = swipes.upOrLeftResult
     val downOrRightResult = swipes.downOrRightResult
-    val userActionDistance = result.distance ?: DefaultSwipeDistance
-    val absoluteDistance =
-        with(userActionDistance) {
-            layoutImpl.density.absoluteDistance(fromScene.targetSize, orientation)
+    val isUpOrLeft =
+        when (result) {
+            upOrLeftResult -> true
+            downOrRightResult -> false
+            else -> error("Unknown result $result ($upOrLeftResult $downOrRightResult)")
         }
 
     return SwipeTransition(
         key = result.transitionKey,
         _fromScene = fromScene,
         _toScene = layoutImpl.scene(result.toScene),
-        distance =
-            when (result) {
-                upOrLeftResult -> -absoluteDistance
-                downOrRightResult -> absoluteDistance
-                else -> error("Unknown result $result ($upOrLeftResult $downOrRightResult)")
-            },
+        userActionDistanceScope = layoutImpl.userActionDistanceScope,
+        orientation = orientation,
+        isUpOrLeft = isUpOrLeft,
     )
 }
 
@@ -482,19 +496,28 @@
     val key: TransitionKey?,
     val _fromScene: Scene,
     val _toScene: Scene,
-    /**
-     * The signed distance between [fromScene] and [toScene]. It is negative if [fromScene] is above
-     * or to the left of [toScene]
-     */
-    val distance: Float,
-) : TransitionState.Transition(_fromScene.key, _toScene.key) {
+    private val userActionDistanceScope: UserActionDistanceScope,
+    override val orientation: Orientation,
+    override val isUpOrLeft: Boolean,
+) :
+    TransitionState.Transition(_fromScene.key, _toScene.key),
+    TransitionState.HasOverscrollProperties {
     var _currentScene by mutableStateOf(_fromScene)
     override val currentScene: SceneKey
         get() = _currentScene.key
 
     override val progress: Float
         get() {
+            // Important: If we are going to return early because distance is equal to 0, we should
+            // still make sure we read the offset before returning so that the calling code still
+            // subscribes to the offset value.
             val offset = if (isAnimatingOffset) offsetAnimatable.value else dragOffset
+
+            val distance = distance()
+            if (distance == DistanceUnspecified) {
+                return 0f
+            }
+
             return offset / distance
         }
 
@@ -518,9 +541,50 @@
     /** Job to check that there is at most one offset animation in progress. */
     private var offsetAnimationJob: Job? = null
 
+    /**
+     * The [TransformationSpecImpl] associated to this transition.
+     *
+     * Note: This is lateinit because this [SwipeTransition] is needed by
+     * [BaseSceneTransitionLayoutState] to compute the [TransitionSpec], and it will be set right
+     * after [BaseSceneTransitionLayoutState.startTransition] is called with this transition.
+     */
+    lateinit var transformationSpec: TransformationSpecImpl
+
     /** The spec to use when animating this transition to either [fromScene] or [toScene]. */
     lateinit var swipeSpec: SpringSpec<Float>
 
+    private var lastDistance = DistanceUnspecified
+
+    /**
+     * The signed distance between [fromScene] and [toScene]. It is negative if [fromScene] is above
+     * or to the left of [toScene].
+     *
+     * Note that this distance can be equal to [DistanceUnspecified] during the first frame of a
+     * transition when the distance depends on the size or position of an element that is composed
+     * in the scene we are going to.
+     */
+    fun distance(): Float {
+        if (lastDistance != DistanceUnspecified) {
+            return lastDistance
+        }
+
+        val absoluteDistance =
+            with(transformationSpec.distance ?: DefaultSwipeDistance) {
+                userActionDistanceScope.absoluteDistance(
+                    _fromScene.targetSize,
+                    orientation,
+                )
+            }
+
+        if (absoluteDistance <= 0f) {
+            return DistanceUnspecified
+        }
+
+        val distance = if (isUpOrLeft) -absoluteDistance else absoluteDistance
+        lastDistance = distance
+        return distance
+    }
+
     /** Ends any previous [offsetAnimationJob] and runs the new [job]. */
     private fun startOffsetAnimation(job: () -> Job) {
         cancelOffsetAnimation()
@@ -563,6 +627,7 @@
         }
         isAnimatingOffset = true
 
+        val animationSpec = transformationSpec
         offsetAnimatable.animateTo(
             targetValue = targetOffset,
             animationSpec = swipeSpec,
@@ -571,10 +636,14 @@
 
         finishOffsetAnimation()
     }
+
+    companion object {
+        const val DistanceUnspecified = 0f
+    }
 }
 
 private object DefaultSwipeDistance : UserActionDistance {
-    override fun Density.absoluteDistance(
+    override fun UserActionDistanceScope.absoluteDistance(
         fromSceneSize: IntSize,
         orientation: Orientation,
     ): Float {
@@ -722,14 +791,21 @@
             )
 
         fun hasNextScene(amount: Float): Boolean {
-            val fromScene = layoutImpl.scene(layoutState.transitionState.currentScene)
+            val transitionState = layoutState.transitionState
+            val scene = transitionState.currentScene
+            val fromScene = layoutImpl.scene(scene)
             val nextScene =
                 when {
                     amount < 0f -> fromScene.userActions[actionUpOrLeft]
                     amount > 0f -> fromScene.userActions[actionDownOrRight]
                     else -> null
                 }
-            return nextScene != null
+            if (nextScene != null) return true
+
+            if (transitionState !is TransitionState.Idle) return false
+
+            val overscrollSpec = layoutImpl.state.transitions.overscrollSpec(scene, orientation)
+            return overscrollSpec != null
         }
 
         val source = this
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
index e1f8a09..1e3842a 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
@@ -25,6 +25,7 @@
 import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
 import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.unit.Density
@@ -394,36 +395,52 @@
     /** The scene we should be transitioning to during the [UserAction]. */
     val toScene: SceneKey,
 
-    /**
-     * The distance the action takes to animate from 0% to 100%.
-     *
-     * If `null`, a default distance will be used that depends on the [UserAction] performed.
-     */
-    val distance: UserActionDistance? = null,
-
     /** The key of the transition that should be used. */
     val transitionKey: TransitionKey? = null,
-) {
-    constructor(
-        toScene: SceneKey,
-        distance: Dp,
-        transitionKey: TransitionKey? = null,
-    ) : this(toScene, FixedDistance(distance), transitionKey)
-}
+)
 
 interface UserActionDistance {
     /**
      * Return the **absolute** distance of the user action given the size of the scene we are
      * animating from and the [orientation].
+     *
+     * Note: This function will be called for each drag event until it returns a value > 0f. This
+     * for instance allows you to return 0f or a negative value until the first layout pass of a
+     * scene, so that you can use the size and position of elements in the scene we are
+     * transitioning to when computing this absolute distance.
      */
-    fun Density.absoluteDistance(fromSceneSize: IntSize, orientation: Orientation): Float
+    fun UserActionDistanceScope.absoluteDistance(
+        fromSceneSize: IntSize,
+        orientation: Orientation
+    ): Float
+}
+
+interface UserActionDistanceScope : Density {
+    /**
+     * Return the *target* size of [this] element in the given [scene], i.e. the size of the element
+     * when idle, or `null` if the element is not composed and measured in that scene (yet).
+     */
+    fun ElementKey.targetSize(scene: SceneKey): IntSize?
+
+    /**
+     * Return the *target* offset of [this] element in the given [scene], i.e. the size of the
+     * element when idle, or `null` if the element is not composed and placed in that scene (yet).
+     */
+    fun ElementKey.targetOffset(scene: SceneKey): Offset?
+
+    /**
+     * Return the *target* size of [this] scene, i.e. the size of the scene when idle, or `null` if
+     * the scene was never composed.
+     */
+    fun SceneKey.targetSize(): IntSize?
 }
 
 /** The user action has a fixed [absoluteDistance]. */
-private class FixedDistance(private val distance: Dp) : UserActionDistance {
-    override fun Density.absoluteDistance(fromSceneSize: IntSize, orientation: Orientation): Float {
-        return distance.toPx()
-    }
+class FixedDistance(private val distance: Dp) : UserActionDistance {
+    override fun UserActionDistanceScope.absoluteDistance(
+        fromSceneSize: IntSize,
+        orientation: Orientation,
+    ): Float = distance.toPx()
 }
 
 /**
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
index 08399ff..3093d47 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
@@ -25,8 +25,13 @@
 import androidx.compose.runtime.snapshots.SnapshotStateMap
 import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.ApproachLayoutModifierNode
+import androidx.compose.ui.layout.ApproachMeasureScope
 import androidx.compose.ui.layout.LookaheadScope
-import androidx.compose.ui.layout.intermediateLayout
+import androidx.compose.ui.layout.Measurable
+import androidx.compose.ui.layout.MeasureResult
+import androidx.compose.ui.node.ModifierNodeElement
+import androidx.compose.ui.unit.Constraints
 import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.util.fastForEach
@@ -96,9 +101,18 @@
                 ?: mutableMapOf<ValueKey, MutableMap<ElementKey?, SnapshotStateMap<SceneKey, *>>>()
                     .also { _sharedValues = it }
 
+    // TODO(b/317958526): Lazily allocate scene gesture handlers the first time they are needed.
     private val horizontalGestureHandler: SceneGestureHandler
     private val verticalGestureHandler: SceneGestureHandler
 
+    private var _userActionDistanceScope: UserActionDistanceScope? = null
+    internal val userActionDistanceScope: UserActionDistanceScope
+        get() =
+            _userActionDistanceScope
+                ?: UserActionDistanceScopeImpl(layoutImpl = this).also {
+                    _userActionDistanceScope = it
+                }
+
     init {
         updateScenes(builder)
 
@@ -172,7 +186,6 @@
     }
 
     @Composable
-    @OptIn(ExperimentalComposeUiApi::class)
     internal fun Content(modifier: Modifier) {
         Box(
             modifier
@@ -181,37 +194,7 @@
                 // swipes.
                 .swipeToScene(horizontalGestureHandler)
                 .swipeToScene(verticalGestureHandler)
-                // Animate the size of this layout.
-                .intermediateLayout { measurable, constraints ->
-                    // Measure content normally.
-                    val placeable = measurable.measure(constraints)
-
-                    val width: Int
-                    val height: Int
-                    val transition = state.currentTransition
-                    if (transition == null) {
-                        width = placeable.width
-                        height = placeable.height
-                    } else {
-                        // Interpolate the size.
-                        val fromSize = scene(transition.fromScene).targetSize
-                        val toSize = scene(transition.toScene).targetSize
-
-                        // Optimization: make sure we don't read state.progress if fromSize ==
-                        // toSize to avoid running this code every frame when the layout size does
-                        // not change.
-                        if (fromSize == toSize) {
-                            width = fromSize.width
-                            height = fromSize.height
-                        } else {
-                            val size = lerp(fromSize, toSize, transition.progress)
-                            width = size.width.coerceAtLeast(0)
-                            height = size.height.coerceAtLeast(0)
-                        }
-                    }
-
-                    layout(width, height) { placeable.place(0, 0) }
-                }
+                .then(LayoutElement(layoutImpl = this))
         ) {
             LookaheadScope {
                 val scenesToCompose =
@@ -254,3 +237,54 @@
         scenes.values.forEach { it.targetSize = size }
     }
 }
+
+private data class LayoutElement(private val layoutImpl: SceneTransitionLayoutImpl) :
+    ModifierNodeElement<LayoutNode>() {
+    override fun create(): LayoutNode = LayoutNode(layoutImpl)
+
+    override fun update(node: LayoutNode) {
+        node.layoutImpl = layoutImpl
+    }
+}
+
+private class LayoutNode(var layoutImpl: SceneTransitionLayoutImpl) :
+    Modifier.Node(), ApproachLayoutModifierNode {
+    override fun isMeasurementApproachComplete(lookaheadSize: IntSize): Boolean {
+        return layoutImpl.state.currentTransition == null
+    }
+
+    @ExperimentalComposeUiApi
+    override fun ApproachMeasureScope.approachMeasure(
+        measurable: Measurable,
+        constraints: Constraints,
+    ): MeasureResult {
+        // Measure content normally.
+        val placeable = measurable.measure(constraints)
+
+        val width: Int
+        val height: Int
+        val transition = layoutImpl.state.currentTransition
+        if (transition == null) {
+            width = placeable.width
+            height = placeable.height
+        } else {
+            // Interpolate the size.
+            val fromSize = layoutImpl.scene(transition.fromScene).targetSize
+            val toSize = layoutImpl.scene(transition.toScene).targetSize
+
+            // Optimization: make sure we don't read state.progress if fromSize ==
+            // toSize to avoid running this code every frame when the layout size does
+            // not change.
+            if (fromSize == toSize) {
+                width = fromSize.width
+                height = fromSize.height
+            } else {
+                val size = lerp(fromSize, toSize, transition.progress)
+                width = size.width.coerceAtLeast(0)
+                height = size.height.coerceAtLeast(0)
+            }
+        }
+
+        return layout(width, height) { placeable.place(0, 0) }
+    }
+}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index 662f33f..0fa19bb 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
@@ -16,6 +16,7 @@
 
 package com.android.compose.animation.scene
 
+import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.SideEffect
@@ -221,6 +222,23 @@
                 isTransitioning(from = other, to = scene)
         }
     }
+
+    interface HasOverscrollProperties {
+        /**
+         * The position of the [TransitionState.Transition.toScene].
+         *
+         * Used to understand the direction of the overscroll.
+         */
+        val isUpOrLeft: Boolean
+
+        /**
+         * The relative orientation between [TransitionState.Transition.fromScene] and
+         * [TransitionState.Transition.toScene].
+         *
+         * Used to understand the orientation of the overscroll.
+         */
+        val orientation: Orientation
+    }
 }
 
 internal abstract class BaseSceneTransitionLayoutState(
@@ -237,6 +255,25 @@
      */
     internal var transformationSpec: TransformationSpecImpl = TransformationSpec.Empty
 
+    private var fromOverscrollSpec: OverscrollSpecImpl? = null
+    private var toOverscrollSpec: OverscrollSpecImpl? = null
+
+    /**
+     * @return the overscroll [OverscrollSpecImpl] if it is defined for the current
+     *   [transitionState] and we are currently over scrolling.
+     */
+    internal val currentOverscrollSpec: OverscrollSpecImpl?
+        get() {
+            val transition = currentTransition ?: return null
+            if (transition !is TransitionState.HasOverscrollProperties) return null
+            val progress = transition.progress
+            return when {
+                progress < 0f -> fromOverscrollSpec
+                progress > 1f -> toOverscrollSpec
+                else -> null
+            }
+        }
+
     private val activeTransitionLinks = mutableMapOf<StateLink, LinkedTransition>()
 
     /** Whether we can transition to the given [scene]. */
@@ -266,10 +303,13 @@
         transitionKey: TransitionKey?,
     ) {
         // Compute the [TransformationSpec] when the transition starts.
+        val fromScene = transition.fromScene
+        val toScene = transition.toScene
+        val orientation = (transition as? TransitionState.HasOverscrollProperties)?.orientation
         transformationSpec =
-            transitions
-                .transitionSpec(transition.fromScene, transition.toScene, key = transitionKey)
-                .transformationSpec()
+            transitions.transitionSpec(fromScene, toScene, key = transitionKey).transformationSpec()
+        fromOverscrollSpec = orientation?.let { transitions.overscrollSpec(fromScene, it) }
+        toOverscrollSpec = orientation?.let { transitions.overscrollSpec(toScene, it) }
         cancelActiveTransitionLinks()
         setupTransitionLinks(transition)
         transitionState = transition
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
index b8f9359..2dd41cd 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
@@ -21,6 +21,7 @@
 import androidx.compose.animation.core.SpringSpec
 import androidx.compose.animation.core.snap
 import androidx.compose.animation.core.spring
+import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.util.fastForEach
@@ -41,18 +42,22 @@
 internal constructor(
     internal val defaultSwipeSpec: SpringSpec<Float>,
     internal val transitionSpecs: List<TransitionSpecImpl>,
+    internal val overscrollSpecs: List<OverscrollSpecImpl>,
 ) {
-    private val cache =
+    private val transitionCache =
         mutableMapOf<
             SceneKey, MutableMap<SceneKey, MutableMap<TransitionKey?, TransitionSpecImpl>>
         >()
 
+    private val overscrollCache =
+        mutableMapOf<SceneKey, MutableMap<Orientation, OverscrollSpecImpl?>>()
+
     internal fun transitionSpec(
         from: SceneKey,
         to: SceneKey,
         key: TransitionKey?,
     ): TransitionSpecImpl {
-        return cache
+        return transitionCache
             .getOrPut(from) { mutableMapOf() }
             .getOrPut(to) { mutableMapOf() }
             .getOrPut(key) { findSpec(from, to, key) }
@@ -105,6 +110,28 @@
     private fun defaultTransition(from: SceneKey, to: SceneKey) =
         TransitionSpecImpl(key = null, from, to, TransformationSpec.EmptyProvider)
 
+    internal fun overscrollSpec(scene: SceneKey, orientation: Orientation): OverscrollSpecImpl? =
+        overscrollCache
+            .getOrPut(scene) { mutableMapOf() }
+            .getOrPut(orientation) { overscroll(scene, orientation) { it.scene == scene } }
+
+    private fun overscroll(
+        scene: SceneKey,
+        orientation: Orientation,
+        filter: (OverscrollSpecImpl) -> Boolean,
+    ): OverscrollSpecImpl? {
+        var match: OverscrollSpecImpl? = null
+        overscrollSpecs.fastForEach { spec ->
+            if (spec.orientation == orientation && filter(spec)) {
+                if (match != null) {
+                    error("Found multiple transition specs for transition $scene")
+                }
+                match = spec
+            }
+        }
+        return match
+    }
+
     companion object {
         internal val DefaultSwipeSpec =
             spring(
@@ -112,7 +139,12 @@
                 visibilityThreshold = OffsetVisibilityThreshold,
             )
 
-        val Empty = SceneTransitions(DefaultSwipeSpec, transitionSpecs = emptyList())
+        val Empty =
+            SceneTransitions(
+                defaultSwipeSpec = DefaultSwipeSpec,
+                transitionSpecs = emptyList(),
+                overscrollSpecs = emptyList(),
+            )
     }
 }
 
@@ -139,7 +171,7 @@
      */
     fun reversed(): TransitionSpec
 
-    /*
+    /**
      * The [TransformationSpec] associated to this [TransitionSpec].
      *
      * Note that this is called once every a transition associated to this [TransitionSpec] is
@@ -163,6 +195,14 @@
      */
     val swipeSpec: SpringSpec<Float>?
 
+    /**
+     * The distance it takes for this transition to animate from 0% to 100% when it is driven by a
+     * [UserAction].
+     *
+     * If `null`, a default distance will be used that depends on the [UserAction] performed.
+     */
+    val distance: UserActionDistance?
+
     /** The list of [Transformation] applied to elements during this transition. */
     val transformations: List<Transformation>
 
@@ -171,6 +211,7 @@
             TransformationSpecImpl(
                 progressSpec = snap(),
                 swipeSpec = null,
+                distance = null,
                 transformations = emptyList(),
             )
         internal val EmptyProvider = { Empty }
@@ -193,6 +234,7 @@
                 TransformationSpecImpl(
                     progressSpec = reverse.progressSpec,
                     swipeSpec = reverse.swipeSpec,
+                    distance = reverse.distance,
                     transformations = reverse.transformations.map { it.reversed() }
                 )
             }
@@ -202,6 +244,24 @@
     override fun transformationSpec(): TransformationSpecImpl = this.transformationSpec.invoke()
 }
 
+/** The definition of the overscroll behavior of the [scene]. */
+interface OverscrollSpec {
+    /** The scene we are over scrolling. */
+    val scene: SceneKey
+
+    /** The orientation of this [OverscrollSpec]. */
+    val orientation: Orientation
+
+    /** The [TransformationSpec] associated to this [OverscrollSpec]. */
+    val transformationSpec: TransformationSpec
+}
+
+internal class OverscrollSpecImpl(
+    override val scene: SceneKey,
+    override val orientation: Orientation,
+    override val transformationSpec: TransformationSpecImpl,
+) : OverscrollSpec
+
 /**
  * An implementation of [TransformationSpec] that allows the quick retrieval of an element
  * [ElementTransformations].
@@ -209,6 +269,7 @@
 internal class TransformationSpecImpl(
     override val progressSpec: AnimationSpec<Float>,
     override val swipeSpec: SpringSpec<Float>?,
+    override val distance: UserActionDistance?,
     override val transformations: List<Transformation>,
 ) : TransformationSpec {
     private val cache = mutableMapOf<ElementKey, MutableMap<SceneKey, ElementTransformations>>()
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
index d93911d..bc52a28 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt
@@ -18,6 +18,7 @@
 
 import androidx.compose.animation.core.AnimationSpec
 import androidx.compose.animation.core.SpringSpec
+import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
@@ -72,23 +73,30 @@
         key: TransitionKey? = null,
         builder: TransitionBuilder.() -> Unit = {},
     ): TransitionSpec
+
+    /**
+     * Define the animation to be played when the [scene] is overscrolled in the given
+     * [orientation].
+     *
+     * The overscroll animation always starts from a progress of 0f, and reaches 1f when moving the
+     * [distance] down/right, -1f when moving in the opposite direction.
+     */
+    fun overscroll(
+        scene: SceneKey,
+        orientation: Orientation,
+        builder: OverscrollBuilder.() -> Unit = {},
+    ): OverscrollSpec
 }
 
 @TransitionDsl
-interface TransitionBuilder : PropertyTransformationBuilder {
+interface OverscrollBuilder : PropertyTransformationBuilder {
     /**
-     * The [AnimationSpec] used to animate the associated transition progress from `0` to `1` when
-     * the transition is triggered (i.e. it is not gesture-based).
-     */
-    var spec: AnimationSpec<Float>
-
-    /**
-     * The [SpringSpec] used to animate the associated transition progress when the transition was
-     * started by a swipe and is now animating back to a scene because the user lifted their finger.
+     * The distance it takes for this transition to animate from 0% to 100% when it is driven by a
+     * [UserAction].
      *
-     * If `null`, then the [SceneTransitionsBuilder.defaultSwipeSpec] will be used.
+     * If `null`, a default distance will be used that depends on the [UserAction] performed.
      */
-    var swipeSpec: SpringSpec<Float>?
+    var distance: UserActionDistance?
 
     /**
      * Define a progress-based range for the transformations inside [builder].
@@ -109,6 +117,23 @@
         end: Float? = null,
         builder: PropertyTransformationBuilder.() -> Unit,
     )
+}
+
+@TransitionDsl
+interface TransitionBuilder : OverscrollBuilder, PropertyTransformationBuilder {
+    /**
+     * The [AnimationSpec] used to animate the associated transition progress from `0` to `1` when
+     * the transition is triggered (i.e. it is not gesture-based).
+     */
+    var spec: AnimationSpec<Float>
+
+    /**
+     * The [SpringSpec] used to animate the associated transition progress when the transition was
+     * started by a swipe and is now animating back to a scene because the user lifted their finger.
+     *
+     * If `null`, then the [SceneTransitionsBuilder.defaultSwipeSpec] will be used.
+     */
+    var swipeSpec: SpringSpec<Float>?
 
     /**
      * Define a timestamp-based range for the transformations inside [builder].
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
index 9b16d46..65e8ea5 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt
@@ -21,7 +21,9 @@
 import androidx.compose.animation.core.Spring
 import androidx.compose.animation.core.SpringSpec
 import androidx.compose.animation.core.VectorConverter
+import androidx.compose.animation.core.snap
 import androidx.compose.animation.core.spring
+import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.unit.Dp
 import com.android.compose.animation.scene.transformation.AnchoredSize
@@ -41,13 +43,18 @@
     builder: SceneTransitionsBuilder.() -> Unit,
 ): SceneTransitions {
     val impl = SceneTransitionsBuilderImpl().apply(builder)
-    return SceneTransitions(impl.defaultSwipeSpec, impl.transitionSpecs)
+    return SceneTransitions(
+        impl.defaultSwipeSpec,
+        impl.transitionSpecs,
+        impl.transitionOverscrollSpecs
+    )
 }
 
 private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder {
     override var defaultSwipeSpec: SpringSpec<Float> = SceneTransitions.DefaultSwipeSpec
 
     val transitionSpecs = mutableListOf<TransitionSpecImpl>()
+    val transitionOverscrollSpecs = mutableListOf<OverscrollSpecImpl>()
 
     override fun to(
         to: SceneKey,
@@ -66,6 +73,25 @@
         return transition(from = from, to = to, key = key, builder)
     }
 
+    override fun overscroll(
+        scene: SceneKey,
+        orientation: Orientation,
+        builder: OverscrollBuilder.() -> Unit
+    ): OverscrollSpec {
+        fun transformationSpec(): TransformationSpecImpl {
+            val impl = OverscrollBuilderImpl().apply(builder)
+            return TransformationSpecImpl(
+                progressSpec = snap(),
+                swipeSpec = null,
+                distance = impl.distance,
+                transformations = impl.transformations,
+            )
+        }
+        val spec = OverscrollSpecImpl(scene, orientation, transformationSpec())
+        transitionOverscrollSpecs.add(spec)
+        return spec
+    }
+
     private fun transition(
         from: SceneKey?,
         to: SceneKey?,
@@ -77,6 +103,7 @@
             return TransformationSpecImpl(
                 progressSpec = impl.spec,
                 swipeSpec = impl.swipeSpec,
+                distance = impl.distance,
                 transformations = impl.transformations,
             )
         }
@@ -87,27 +114,11 @@
     }
 }
 
-internal class TransitionBuilderImpl : TransitionBuilder {
+internal open class OverscrollBuilderImpl : OverscrollBuilder {
     val transformations = mutableListOf<Transformation>()
-    override var spec: AnimationSpec<Float> = spring(stiffness = Spring.StiffnessLow)
-    override var swipeSpec: SpringSpec<Float>? = null
-
     private var range: TransformationRange? = null
-    private var reversed = false
-    private val durationMillis: Int by lazy {
-        val spec = spec
-        if (spec !is DurationBasedAnimationSpec) {
-            error("timestampRange {} can only be used with a DurationBasedAnimationSpec")
-        }
-
-        spec.vectorize(Float.VectorConverter).durationMillis
-    }
-
-    override fun reversed(builder: TransitionBuilder.() -> Unit) {
-        reversed = true
-        builder()
-        reversed = false
-    }
+    protected var reversed = false
+    override var distance: UserActionDistance? = null
 
     override fun fractionRange(
         start: Float?,
@@ -119,28 +130,6 @@
         range = null
     }
 
-    override fun sharedElement(matcher: ElementMatcher, enabled: Boolean) {
-        transformations.add(SharedElementTransformation(matcher, enabled))
-    }
-
-    override fun timestampRange(
-        startMillis: Int?,
-        endMillis: Int?,
-        builder: PropertyTransformationBuilder.() -> Unit
-    ) {
-        if (startMillis != null && (startMillis < 0 || startMillis > durationMillis)) {
-            error("invalid start value: startMillis=$startMillis durationMillis=$durationMillis")
-        }
-
-        if (endMillis != null && (endMillis < 0 || endMillis > durationMillis)) {
-            error("invalid end value: endMillis=$startMillis durationMillis=$durationMillis")
-        }
-
-        val start = startMillis?.let { it.toFloat() / durationMillis }
-        val end = endMillis?.let { it.toFloat() / durationMillis }
-        fractionRange(start, end, builder)
-    }
-
     private fun transformation(transformation: PropertyTransformation<*>) {
         val transformation =
             if (range != null) {
@@ -195,3 +184,45 @@
         transformation(AnchoredSize(matcher, anchor, anchorWidth, anchorHeight))
     }
 }
+
+internal class TransitionBuilderImpl : OverscrollBuilderImpl(), TransitionBuilder {
+    override var spec: AnimationSpec<Float> = spring(stiffness = Spring.StiffnessLow)
+    override var swipeSpec: SpringSpec<Float>? = null
+    override var distance: UserActionDistance? = null
+    private val durationMillis: Int by lazy {
+        val spec = spec
+        if (spec !is DurationBasedAnimationSpec) {
+            error("timestampRange {} can only be used with a DurationBasedAnimationSpec")
+        }
+
+        spec.vectorize(Float.VectorConverter).durationMillis
+    }
+
+    override fun reversed(builder: TransitionBuilder.() -> Unit) {
+        reversed = true
+        builder()
+        reversed = false
+    }
+
+    override fun sharedElement(matcher: ElementMatcher, enabled: Boolean) {
+        transformations.add(SharedElementTransformation(matcher, enabled))
+    }
+
+    override fun timestampRange(
+        startMillis: Int?,
+        endMillis: Int?,
+        builder: PropertyTransformationBuilder.() -> Unit
+    ) {
+        if (startMillis != null && (startMillis < 0 || startMillis > durationMillis)) {
+            error("invalid start value: startMillis=$startMillis durationMillis=$durationMillis")
+        }
+
+        if (endMillis != null && (endMillis < 0 || endMillis > durationMillis)) {
+            error("invalid end value: endMillis=$startMillis durationMillis=$durationMillis")
+        }
+
+        val start = startMillis?.let { it.toFloat() / durationMillis }
+        val end = endMillis?.let { it.toFloat() / durationMillis }
+        fractionRange(start, end, builder)
+    }
+}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/UserActionDistanceScopeImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/UserActionDistanceScopeImpl.kt
new file mode 100644
index 0000000..228d19f
--- /dev/null
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/UserActionDistanceScopeImpl.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 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.compose.animation.scene
+
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.unit.IntSize
+
+internal class UserActionDistanceScopeImpl(
+    private val layoutImpl: SceneTransitionLayoutImpl,
+) : UserActionDistanceScope {
+    override val density: Float
+        get() = layoutImpl.density.density
+
+    override val fontScale: Float
+        get() = layoutImpl.density.fontScale
+
+    override fun ElementKey.targetSize(scene: SceneKey): IntSize? {
+        return layoutImpl.elements[this]?.sceneStates?.get(scene)?.targetSize.takeIf {
+            it != Element.SizeUnspecified
+        }
+    }
+
+    override fun ElementKey.targetOffset(scene: SceneKey): Offset? {
+        return layoutImpl.elements[this]?.sceneStates?.get(scene)?.targetOffset.takeIf {
+            it != Offset.Unspecified
+        }
+    }
+
+    override fun SceneKey.targetSize(): IntSize? {
+        return layoutImpl.scenes[this]?.targetSize.takeIf { it != IntSize.Zero }
+    }
+}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
index 33be1dc..059a10e 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
@@ -18,9 +18,13 @@
 
 import androidx.compose.animation.core.tween
 import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.gestures.rememberScrollableState
+import androidx.compose.foundation.gestures.scrollable
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.offset
 import androidx.compose.foundation.layout.size
@@ -34,8 +38,14 @@
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.layout.intermediateLayout
+import androidx.compose.ui.platform.LocalViewConfiguration
+import androidx.compose.ui.test.assertTopPositionInRootIsEqualTo
 import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.onRoot
+import androidx.compose.ui.test.performTouchInput
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -528,4 +538,157 @@
             after { assertThat(fooCompositions).isEqualTo(1) }
         }
     }
+
+    @Test
+    fun elementTransitionDuringOverscroll() {
+        // The draggable touch slop, i.e. the min px distance a touch pointer must move before it is
+        // detected as a drag event.
+        var touchSlop = 0f
+        val overscrollTranslateY = 10.dp
+        val layoutWidth = 200.dp
+        val layoutHeight = 400.dp
+
+        val state =
+            MutableSceneTransitionLayoutState(
+                initialScene = TestScenes.SceneA,
+                transitions =
+                    transitions {
+                        overscroll(TestScenes.SceneB, Orientation.Vertical) {
+                            translate(TestElements.Foo, y = overscrollTranslateY)
+                        }
+                    }
+            )
+                as MutableSceneTransitionLayoutStateImpl
+
+        rule.setContent {
+            touchSlop = LocalViewConfiguration.current.touchSlop
+            SceneTransitionLayout(
+                state = state,
+                modifier = Modifier.size(layoutWidth, layoutHeight)
+            ) {
+                scene(
+                    key = TestScenes.SceneA,
+                    userActions = mapOf(Swipe.Down to TestScenes.SceneB)
+                ) {
+                    Spacer(Modifier.fillMaxSize())
+                }
+                scene(TestScenes.SceneB) {
+                    Spacer(Modifier.element(TestElements.Foo).fillMaxSize())
+                }
+            }
+        }
+
+        assertThat(state.currentTransition).isNull()
+        assertThat(state.currentOverscrollSpec).isNull()
+
+        // Swipe by half of verticalSwipeDistance.
+        rule.onRoot().performTouchInput {
+            val middleTop = Offset((layoutWidth / 2).toPx(), 0f)
+            down(middleTop)
+            // Scroll 50%
+            moveBy(Offset(0f, touchSlop + layoutHeight.toPx() * 0.5f), delayMillis = 1_000)
+        }
+
+        val fooElement = rule.onNodeWithTag(TestElements.Foo.testTag, useUnmergedTree = true)
+        fooElement.assertTopPositionInRootIsEqualTo(0.dp)
+        val transition = state.currentTransition
+        assertThat(transition).isNotNull()
+        assertThat(transition!!.progress).isEqualTo(0.5f)
+
+        rule.onRoot().performTouchInput {
+            // Scroll another 100%
+            moveBy(Offset(0f, layoutHeight.toPx()), delayMillis = 1_000)
+        }
+
+        // Scroll 150% (Scene B overscroll by 50%)
+        assertThat(transition.progress).isEqualTo(1.5f)
+        assertThat(state.currentOverscrollSpec).isNotNull()
+        fooElement.assertTopPositionInRootIsEqualTo(overscrollTranslateY * 0.5f)
+
+        rule.onRoot().performTouchInput {
+            // Scroll another 100%
+            moveBy(Offset(0f, layoutHeight.toPx()), delayMillis = 1_000)
+        }
+
+        // Scroll 250% (Scene B overscroll by 150%)
+        assertThat(transition.progress).isEqualTo(2.5f)
+        assertThat(state.currentOverscrollSpec).isNotNull()
+        fooElement.assertTopPositionInRootIsEqualTo(overscrollTranslateY * 1.5f)
+    }
+
+    @Test
+    fun elementTransitionDuringNestedScrollOverscroll() {
+        // The draggable touch slop, i.e. the min px distance a touch pointer must move before it is
+        // detected as a drag event.
+        var touchSlop = 0f
+        val overscrollTranslateY = 10.dp
+        val layoutWidth = 200.dp
+        val layoutHeight = 400.dp
+
+        val state =
+            MutableSceneTransitionLayoutState(
+                initialScene = TestScenes.SceneB,
+                transitions =
+                    transitions {
+                        overscroll(TestScenes.SceneB, Orientation.Vertical) {
+                            translate(TestElements.Foo, y = overscrollTranslateY)
+                        }
+                    }
+            )
+                as MutableSceneTransitionLayoutStateImpl
+
+        rule.setContent {
+            touchSlop = LocalViewConfiguration.current.touchSlop
+            SceneTransitionLayout(
+                state = state,
+                modifier = Modifier.size(layoutWidth, layoutHeight)
+            ) {
+                scene(TestScenes.SceneA) { Spacer(Modifier.fillMaxSize()) }
+                scene(TestScenes.SceneB, userActions = mapOf(Swipe.Up to TestScenes.SceneA)) {
+                    Box(
+                        Modifier
+                            // Unconsumed scroll gesture will be intercepted by STL
+                            .verticalNestedScrollToScene()
+                            // A scrollable that does not consume the scroll gesture
+                            .scrollable(
+                                rememberScrollableState(consumeScrollDelta = { 0f }),
+                                Orientation.Vertical
+                            )
+                            .fillMaxSize()
+                    ) {
+                        Spacer(Modifier.element(TestElements.Foo).fillMaxSize())
+                    }
+                }
+            }
+        }
+
+        assertThat(state.currentTransition).isNull()
+        assertThat(state.currentOverscrollSpec).isNull()
+        val fooElement = rule.onNodeWithTag(TestElements.Foo.testTag, useUnmergedTree = true)
+        fooElement.assertTopPositionInRootIsEqualTo(0.dp)
+
+        // Swipe by half of verticalSwipeDistance.
+        rule.onRoot().performTouchInput {
+            val middleTop = Offset((layoutWidth / 2).toPx(), 0f)
+            down(middleTop)
+            // Scroll 50%
+            moveBy(Offset(0f, touchSlop + layoutHeight.toPx() * 0.5f), delayMillis = 1_000)
+        }
+
+        val transition = state.currentTransition
+        assertThat(state.currentOverscrollSpec).isNotNull()
+        assertThat(transition).isNotNull()
+        assertThat(transition!!.progress).isEqualTo(-0.5f)
+        fooElement.assertTopPositionInRootIsEqualTo(overscrollTranslateY * 0.5f)
+
+        rule.onRoot().performTouchInput {
+            // Scroll another 100%
+            moveBy(Offset(0f, layoutHeight.toPx()), delayMillis = 1_000)
+        }
+
+        // Scroll 150% (Scene B overscroll by 50%)
+        assertThat(transition.progress).isEqualTo(-1.5f)
+        assertThat(state.currentOverscrollSpec).isNotNull()
+        fooElement.assertTopPositionInRootIsEqualTo(overscrollTranslateY * 1.5f)
+    }
 }
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt
index fe53d5b..d28ac6a 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneGestureHandlerTest.kt
@@ -52,7 +52,7 @@
         private val testScope: MonotonicClockTestScope,
     ) {
         var canChangeScene: (SceneKey) -> Boolean = { true }
-        private val layoutState =
+        val layoutState =
             MutableSceneTransitionLayoutStateImpl(
                 SceneA,
                 EmptyTestTransitions,
@@ -932,4 +932,28 @@
         advanceUntilIdle()
         assertIdle(SceneB)
     }
+
+    @Test
+    fun scrollFromIdleWithNoTargetScene_shouldUseOverscrollSpecIfAvailable() = runGestureTest {
+        layoutState.transitions = transitions {
+            overscroll(SceneC, Orientation.Vertical) { fade(TestElements.Foo) }
+        }
+        // Start at scene C.
+        navigateToSceneC()
+
+        val scene = layoutState.transitionState.currentScene
+        // We should have overscroll spec for scene C
+        assertThat(layoutState.transitions.overscrollSpec(scene, Orientation.Vertical)).isNotNull()
+        assertThat(layoutState.currentOverscrollSpec).isNull()
+
+        val nestedScroll = nestedScrollConnection(nestedScrollBehavior = EdgeAlways)
+        nestedScroll.scroll(available = downOffset(fractionOfScreen = 0.1f))
+
+        // We scrolled down, under scene C there is nothing, so we can use the overscroll spec
+        assertThat(layoutState.currentOverscrollSpec).isNotNull()
+        assertThat(layoutState.currentOverscrollSpec?.scene).isEqualTo(SceneC)
+        val transition = layoutState.currentTransition
+        assertThat(transition).isNotNull()
+        assertThat(transition!!.progress).isEqualTo(-0.1f)
+    }
 }
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
index f81a7f2..3cbcd73 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt
@@ -16,6 +16,8 @@
 
 package com.android.compose.animation.scene
 
+import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.runtime.mutableStateOf
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.compose.animation.scene.TestScenes.SceneA
@@ -389,4 +391,118 @@
         assertThat(childState.isTransitioning(SceneA, SceneB)).isTrue()
         assertThat(parentState.isTransitioning(SceneC, SceneD)).isFalse()
     }
+
+    private fun startOverscrollableTransistionFromAtoB(
+        progress: () -> Float,
+        sceneTransitions: SceneTransitions,
+    ): MutableSceneTransitionLayoutStateImpl {
+        val state =
+            MutableSceneTransitionLayoutStateImpl(
+                SceneA,
+                sceneTransitions,
+            )
+        state.startTransition(
+            object :
+                TransitionState.Transition(SceneA, SceneB),
+                TransitionState.HasOverscrollProperties {
+                override val currentScene: SceneKey = SceneA
+                override val progress: Float
+                    get() = progress()
+
+                override val isInitiatedByUserInput: Boolean = false
+                override val isUserInputOngoing: Boolean = false
+                override val isUpOrLeft: Boolean = false
+                override val orientation: Orientation = Orientation.Vertical
+            },
+            transitionKey = null
+        )
+        assertThat(state.isTransitioning()).isTrue()
+        return state
+    }
+
+    @Test
+    fun overscrollDsl_definedForToScene() = runMonotonicClockTest {
+        val progress = mutableStateOf(0f)
+        val state =
+            startOverscrollableTransistionFromAtoB(
+                progress = { progress.value },
+                sceneTransitions =
+                    transitions {
+                        overscroll(SceneB, Orientation.Vertical) { fade(TestElements.Foo) }
+                    }
+            )
+        assertThat(state.currentOverscrollSpec).isNull()
+
+        // overscroll for SceneA is NOT defined
+        progress.value = -0.1f
+        assertThat(state.currentOverscrollSpec).isNull()
+
+        // scroll from SceneA to SceneB
+        progress.value = 0.5f
+        assertThat(state.currentOverscrollSpec).isNull()
+
+        progress.value = 1f
+        assertThat(state.currentOverscrollSpec).isNull()
+
+        // overscroll for SceneB is defined
+        progress.value = 1.1f
+        assertThat(state.currentOverscrollSpec).isNotNull()
+        assertThat(state.currentOverscrollSpec?.scene).isEqualTo(SceneB)
+    }
+
+    @Test
+    fun overscrollDsl_definedForFromScene() = runMonotonicClockTest {
+        val progress = mutableStateOf(0f)
+        val state =
+            startOverscrollableTransistionFromAtoB(
+                progress = { progress.value },
+                sceneTransitions =
+                    transitions {
+                        overscroll(SceneA, Orientation.Vertical) { fade(TestElements.Foo) }
+                    }
+            )
+        assertThat(state.currentOverscrollSpec).isNull()
+
+        // overscroll for SceneA is defined
+        progress.value = -0.1f
+        assertThat(state.currentOverscrollSpec).isNotNull()
+        assertThat(state.currentOverscrollSpec?.scene).isEqualTo(SceneA)
+
+        // scroll from SceneA to SceneB
+        progress.value = 0.5f
+        assertThat(state.currentOverscrollSpec).isNull()
+
+        progress.value = 1f
+        assertThat(state.currentOverscrollSpec).isNull()
+
+        // overscroll for SceneB is NOT defined
+        progress.value = 1.1f
+        assertThat(state.currentOverscrollSpec).isNull()
+    }
+
+    @Test
+    fun overscrollDsl_notDefinedScenes() = runMonotonicClockTest {
+        val progress = mutableStateOf(0f)
+        val state =
+            startOverscrollableTransistionFromAtoB(
+                progress = { progress.value },
+                sceneTransitions = transitions {}
+            )
+        assertThat(state.currentOverscrollSpec).isNull()
+
+        // overscroll for SceneA is NOT defined
+        progress.value = -0.1f
+        assertThat(state.currentOverscrollSpec).isNull()
+
+        // scroll from SceneA to SceneB
+        progress.value = 0.5f
+        assertThat(state.currentOverscrollSpec).isNull()
+
+        progress.value = 1f
+        assertThat(state.currentOverscrollSpec).isNull()
+
+        // overscroll for SceneB is NOT defined
+        progress.value = 1.1f
+        assertThat(state.currentOverscrollSpec).isNull()
+    }
 }
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
index 543ed04..99372a5 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
@@ -16,9 +16,11 @@
 
 package com.android.compose.animation.scene
 
+import androidx.compose.foundation.gestures.Orientation
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.offset
 import androidx.compose.foundation.layout.size
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
@@ -33,6 +35,7 @@
 import androidx.compose.ui.test.performTouchInput
 import androidx.compose.ui.test.swipeWithVelocity
 import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.unit.dp
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.google.common.truth.Truth.assertThat
@@ -61,8 +64,10 @@
 
     @get:Rule val rule = createComposeRule()
 
-    private fun layoutState(initialScene: SceneKey = TestScenes.SceneA) =
-        MutableSceneTransitionLayoutState(initialScene, EmptyTestTransitions)
+    private fun layoutState(
+        initialScene: SceneKey = TestScenes.SceneA,
+        transitions: SceneTransitions = EmptyTestTransitions,
+    ) = MutableSceneTransitionLayoutState(initialScene, transitions)
 
     /** The content under test. */
     @Composable
@@ -370,8 +375,16 @@
         // detected as a drag event.
         var touchSlop = 0f
 
-        val layoutState = layoutState()
         val verticalSwipeDistance = 50.dp
+        val layoutState =
+            layoutState(
+                transitions =
+                    transitions {
+                        from(TestScenes.SceneA, to = TestScenes.SceneB) {
+                            distance = FixedDistance(verticalSwipeDistance)
+                        }
+                    }
+            )
         assertThat(verticalSwipeDistance).isNotEqualTo(LayoutHeight)
 
         rule.setContent {
@@ -383,14 +396,7 @@
             ) {
                 scene(
                     TestScenes.SceneA,
-                    userActions =
-                        mapOf(
-                            Swipe.Down to
-                                UserActionResult(
-                                    toScene = TestScenes.SceneB,
-                                    distance = verticalSwipeDistance,
-                                )
-                        ),
+                    userActions = mapOf(Swipe.Down to TestScenes.SceneB),
                 ) {
                     Spacer(Modifier.fillMaxSize())
                 }
@@ -548,4 +554,64 @@
         assertThat(state.isTransitioning(from = TestScenes.SceneA, to = TestScenes.SceneB)).isTrue()
         assertThat(state.transformationSpec.transformations).hasSize(2)
     }
+
+    @Test
+    fun dynamicSwipeDistance() {
+        val swipeDistance =
+            object : UserActionDistance {
+                override fun UserActionDistanceScope.absoluteDistance(
+                    fromSceneSize: IntSize,
+                    orientation: Orientation,
+                ): Float {
+                    // Foo is going to have a vertical offset of 50dp. Let's make the swipe distance
+                    // the difference between the bottom of the scene and the bottom of the element,
+                    // so that we use the offset and size of the element as well as the size of the
+                    // scene.
+                    val fooSize = TestElements.Foo.targetSize(TestScenes.SceneB) ?: return 0f
+                    val fooOffset = TestElements.Foo.targetOffset(TestScenes.SceneB) ?: return 0f
+                    val sceneSize = TestScenes.SceneB.targetSize() ?: return 0f
+                    return sceneSize.height - fooOffset.y - fooSize.height
+                }
+            }
+
+        val state =
+            MutableSceneTransitionLayoutState(
+                TestScenes.SceneA,
+                transitions {
+                    from(TestScenes.SceneA, to = TestScenes.SceneB) { distance = swipeDistance }
+                }
+            )
+
+        val layoutSize = 200.dp
+        val fooYOffset = 50.dp
+        val fooSize = 25.dp
+
+        var touchSlop = 0f
+        rule.setContent {
+            touchSlop = LocalViewConfiguration.current.touchSlop
+
+            SceneTransitionLayout(state, Modifier.size(layoutSize)) {
+                scene(TestScenes.SceneA, userActions = mapOf(Swipe.Up to TestScenes.SceneB)) {
+                    Box(Modifier.fillMaxSize())
+                }
+                scene(TestScenes.SceneB) {
+                    Box(Modifier.fillMaxSize()) {
+                        Box(Modifier.offset(y = fooYOffset).element(TestElements.Foo).size(fooSize))
+                    }
+                }
+            }
+        }
+
+        // Swipe up by half the expected distance to get to 50% progress.
+        val expectedDistance = layoutSize - fooYOffset - fooSize
+        rule.onRoot().performTouchInput {
+            val middle = (layoutSize / 2).toPx()
+            down(Offset(middle, middle))
+            moveBy(Offset(0f, -touchSlop - (expectedDistance / 2f).toPx()), delayMillis = 1_000)
+        }
+
+        rule.waitForIdle()
+        assertThat(state.isTransitioning(from = TestScenes.SceneA, to = TestScenes.SceneB)).isTrue()
+        assertThat(state.currentTransition!!.progress).isWithin(0.01f).of(0.5f)
+    }
 }
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
index 1beafcc..c9c3ecc 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt
@@ -20,9 +20,11 @@
 import androidx.compose.animation.core.TweenSpec
 import androidx.compose.animation.core.spring
 import androidx.compose.animation.core.tween
+import androidx.compose.foundation.gestures.Orientation
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.compose.animation.scene.transformation.Transformation
 import com.android.compose.animation.scene.transformation.TransformationRange
+import com.android.compose.animation.scene.transformation.Translate
 import com.google.common.truth.Correspondence
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
@@ -223,6 +225,17 @@
             .isSameInstanceAs(specFromAToC)
     }
 
+    @Test
+    fun overscrollSpec() {
+        val transitions = transitions {
+            overscroll(TestScenes.SceneA, Orientation.Vertical) { translate(TestElements.Bar) }
+        }
+
+        val overscrollSpec = transitions.overscrollSpecs.single()
+        val transformation = overscrollSpec.transformationSpec.transformations.single()
+        assertThat(transformation).isInstanceOf(Translate::class.java)
+    }
+
     companion object {
         private val TRANSFORMATION_RANGE =
             Correspondence.transforming<Transformation, TransformationRange?>(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/assist/data/repository/AssistRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/assist/data/repository/AssistRepositoryTest.kt
new file mode 100644
index 0000000..80077a21
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/assist/data/repository/AssistRepositoryTest.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2024 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.assist.data.repository
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class AssistRepositoryTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+
+    private val underTest = kosmos.assistRepository
+
+    @Test
+    fun invocationType() =
+        testScope.runTest {
+            val invocationType by collectLastValue(underTest.latestInvocationType)
+            underTest.setLatestInvocationType(2)
+            runCurrent()
+
+            assertThat(invocationType).isEqualTo(2)
+        }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/assist/domain/interactor/AssistInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/assist/domain/interactor/AssistInteractorTest.kt
new file mode 100644
index 0000000..c12f1ac
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/assist/domain/interactor/AssistInteractorTest.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2024 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.assist.domain.interactor
+
+import android.platform.test.annotations.EnableFlags
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.Flags
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class AssistInteractorTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+
+    private val underTest = kosmos.assistInteractor
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_CONTEXTUAL_TIPS, Flags.FLAG_ENABLE_CONTEXTUAL_TIP_FOR_POWER_OFF)
+    fun onAssistantStarted() =
+        testScope.runTest {
+            val invocationType by collectLastValue(underTest.latestInvocationType)
+            underTest.onAssistantStarted(3)
+            runCurrent()
+
+            assertThat(invocationType).isEqualTo(3)
+        }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
index 259f349..5034631 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
@@ -44,12 +44,18 @@
 import com.android.systemui.biometrics.ui.viewmodel.DeviceEntryUdfpsTouchOverlayViewModel
 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.dump.DumpManager
 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.power.shared.model.WakeSleepReason
+import com.android.systemui.power.shared.model.WakefulnessState
 import com.android.systemui.res.R
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.statusbar.LockscreenShadeTransitionController
+import com.android.systemui.statusbar.phone.ScreenOffAnimationController
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
 import com.android.systemui.statusbar.phone.SystemUIDialogManager
 import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController
@@ -58,6 +64,10 @@
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
@@ -68,6 +78,7 @@
 import org.mockito.Captor
 import org.mockito.Mock
 import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when` as whenever
 import org.mockito.junit.MockitoJUnit
@@ -120,6 +131,9 @@
     @Mock private lateinit var shadeInteractor: ShadeInteractor
     @Captor private lateinit var layoutParamsCaptor: ArgumentCaptor<WindowManager.LayoutParams>
     @Mock private lateinit var udfpsOverlayInteractor: UdfpsOverlayInteractor
+    private lateinit var powerRepository: FakePowerRepository
+    private lateinit var powerInteractor: PowerInteractor
+    private lateinit var testScope: TestScope
 
     private val onTouch = { _: View, _: MotionEvent, _: Boolean -> true }
     private var overlayParams: UdfpsOverlayParams = UdfpsOverlayParams()
@@ -127,6 +141,15 @@
 
     @Before
     fun setup() {
+        testScope = TestScope(StandardTestDispatcher())
+        powerRepository = FakePowerRepository()
+        powerInteractor =
+            PowerInteractor(
+                powerRepository,
+                mock(FalsingCollector::class.java),
+                mock(ScreenOffAnimationController::class.java),
+                statusBarStateController,
+            )
         whenever(inflater.inflate(R.layout.udfps_view, null, false)).thenReturn(udfpsView)
         whenever(inflater.inflate(R.layout.udfps_bp_view, null))
             .thenReturn(mock(UdfpsBpView::class.java))
@@ -178,6 +201,8 @@
                 { defaultUdfpsTouchOverlayViewModel },
                 shadeInteractor,
                 udfpsOverlayInteractor,
+                powerInteractor,
+                testScope,
             )
         block()
     }
@@ -277,6 +302,66 @@
             }
         }
 
+    @Test
+    fun showUdfpsOverlay_awake() =
+        testScope.runTest {
+            withReason(REASON_AUTH_KEYGUARD) {
+                mSetFlagsRule.enableFlags(Flags.FLAG_UDFPS_VIEW_PERFORMANCE)
+                powerRepository.updateWakefulness(
+                    rawState = WakefulnessState.AWAKE,
+                    lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                    lastSleepReason = WakeSleepReason.OTHER,
+                )
+                controllerOverlay.show(udfpsController, overlayParams)
+                runCurrent()
+                verify(windowManager).addView(any(), any())
+            }
+        }
+
+    @Test
+    fun showUdfpsOverlay_whileGoingToSleep() =
+        testScope.runTest {
+            withReason(REASON_AUTH_KEYGUARD) {
+                mSetFlagsRule.enableFlags(Flags.FLAG_UDFPS_VIEW_PERFORMANCE)
+                powerRepository.updateWakefulness(
+                    rawState = WakefulnessState.STARTING_TO_SLEEP,
+                    lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                    lastSleepReason = WakeSleepReason.OTHER,
+                )
+                controllerOverlay.show(udfpsController, overlayParams)
+                runCurrent()
+                verify(windowManager, never()).addView(any(), any())
+
+                // we hide to end the job that listens for the finishedGoingToSleep signal
+                controllerOverlay.hide()
+            }
+        }
+
+    @Test
+    fun showUdfpsOverlay_afterFinishedGoingToSleep() =
+        testScope.runTest {
+            withReason(REASON_AUTH_KEYGUARD) {
+                mSetFlagsRule.enableFlags(Flags.FLAG_UDFPS_VIEW_PERFORMANCE)
+                powerRepository.updateWakefulness(
+                    rawState = WakefulnessState.STARTING_TO_SLEEP,
+                    lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                    lastSleepReason = WakeSleepReason.OTHER,
+                )
+                controllerOverlay.show(udfpsController, overlayParams)
+                runCurrent()
+                verify(windowManager, never()).addView(any(), any())
+
+                powerRepository.updateWakefulness(
+                    rawState = WakefulnessState.ASLEEP,
+                    lastWakeReason = WakeSleepReason.POWER_BUTTON,
+                    lastSleepReason = WakeSleepReason.OTHER,
+                )
+                runCurrent()
+                verify(windowManager)
+                    .addView(eq(controllerOverlay.getTouchOverlay()), layoutParamsCaptor.capture())
+            }
+        }
+
     private fun showUdfpsOverlay() {
         val didShow = controllerOverlay.show(udfpsController, overlayParams)
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 529403a..561cdbb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -86,6 +86,7 @@
 import com.android.systemui.biometrics.ui.viewmodel.DeviceEntryUdfpsTouchOverlayViewModel;
 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
+import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
@@ -94,10 +95,15 @@
 import com.android.systemui.log.SessionTracker;
 import com.android.systemui.plugins.FalsingManager;
 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.power.shared.model.WakeSleepReason;
+import com.android.systemui.power.shared.model.WakefulnessState;
 import com.android.systemui.res.R;
 import com.android.systemui.shade.domain.interactor.ShadeInteractor;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
 import com.android.systemui.statusbar.VibratorHelper;
+import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.phone.SystemUIDialogManager;
 import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
@@ -125,6 +131,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import kotlinx.coroutines.CoroutineScope;
+
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 @RunWithLooper(setAsMainLooper = true)
@@ -238,6 +246,8 @@
     private ScreenLifecycle.Observer mScreenObserver;
     private FingerprintSensorPropertiesInternal mOpticalProps;
     private FingerprintSensorPropertiesInternal mUltrasonicProps;
+    private PowerInteractor mPowerInteractor;
+    private FakePowerRepository mPowerRepository;
     @Mock
     private InputManager mInputManager;
     @Mock
@@ -253,6 +263,19 @@
 
     @Before
     public void setUp() {
+        mPowerRepository = new FakePowerRepository();
+        mPowerInteractor = new PowerInteractor(
+                mPowerRepository,
+                mock(FalsingCollector.class),
+                mock(ScreenOffAnimationController.class),
+                mStatusBarStateController
+        );
+        mPowerRepository.updateWakefulness(
+                WakefulnessState.AWAKE,
+                WakeSleepReason.POWER_BUTTON,
+                WakeSleepReason.OTHER,
+                /* powerButtonLaunchGestureTriggered */ false
+        );
         mContext.getOrCreateTestableResources()
                 .addOverride(com.android.internal.R.bool.config_ignoreUdfpsVote, false);
 
@@ -346,7 +369,9 @@
                 mKeyguardTransitionInteractor,
                 mDeviceEntryUdfpsTouchOverlayViewModel,
                 mDefaultUdfpsTouchOverlayViewModel,
-                mUdfpsOverlayInteractor
+                mUdfpsOverlayInteractor,
+                mPowerInteractor,
+                mock(CoroutineScope.class)
         );
         verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
         mOverlayController = mOverlayCaptor.getValue();
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
index a8fe16b..92396e0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/CommunalSceneStartableTest.kt
@@ -20,6 +20,7 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.communal.domain.interactor.communalInteractor
+import com.android.systemui.communal.domain.interactor.setCommunalAvailable
 import com.android.systemui.communal.shared.model.CommunalSceneKey
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.dock.DockManager
@@ -33,6 +34,7 @@
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.launch
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.advanceTimeBy
 import kotlinx.coroutines.test.runCurrent
@@ -50,7 +52,7 @@
     private lateinit var underTest: CommunalSceneStartable
 
     @Before
-    fun setUp() =
+    fun setUp() {
         with(kosmos) {
             underTest =
                 CommunalSceneStartable(
@@ -61,7 +63,15 @@
                         bgScope = applicationCoroutineScope,
                     )
                     .apply { start() }
+
+            // Make communal available so that communalInteractor.desiredScene accurately reflects
+            // scene changes instead of just returning Blank.
+            with(kosmos.testScope) {
+                launch { setCommunalAvailable(true) }
+                testScheduler.runCurrent()
+            }
         }
+    }
 
     @Test
     fun keyguardGoesAway_forceBlankScene() =
@@ -83,25 +93,6 @@
         }
 
     @Test
-    fun deviceDreaming_forceBlankScene() =
-        with(kosmos) {
-            testScope.runTest {
-                val scene by collectLastValue(communalInteractor.desiredScene)
-
-                communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
-                assertThat(scene).isEqualTo(CommunalSceneKey.Communal)
-
-                fakeKeyguardTransitionRepository.sendTransitionSteps(
-                    from = KeyguardState.GLANCEABLE_HUB,
-                    to = KeyguardState.DREAMING,
-                    testScope = this
-                )
-
-                assertThat(scene).isEqualTo(CommunalSceneKey.Blank)
-            }
-        }
-
-    @Test
     fun deviceDocked_forceCommunalScene() =
         with(kosmos) {
             testScope.runTest {
@@ -115,13 +106,6 @@
                     testScope = this
                 )
                 assertThat(scene).isEqualTo(CommunalSceneKey.Communal)
-
-                fakeKeyguardTransitionRepository.sendTransitionSteps(
-                    from = KeyguardState.GLANCEABLE_HUB,
-                    to = KeyguardState.DREAMING,
-                    testScope = this
-                )
-                assertThat(scene).isEqualTo(CommunalSceneKey.Blank)
             }
         }
 
@@ -249,4 +233,10 @@
             fakeDockManager.setDockEvent(DockManager.STATE_DOCKED)
             runCurrent()
         }
+
+    private suspend fun TestScope.enableCommunal() =
+        with(kosmos) {
+            setCommunalAvailable(true)
+            runCurrent()
+        }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
index 4156d83..cd29652 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalInteractorTest.kt
@@ -18,7 +18,9 @@
 package com.android.systemui.communal.domain.interactor
 
 import android.app.smartspace.SmartspaceTarget
+import android.appwidget.AppWidgetProviderInfo
 import android.content.pm.UserInfo
+import android.os.UserHandle
 import android.provider.Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED
 import android.widget.RemoteViews
 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -51,6 +53,8 @@
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags
 import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.settings.FakeUserTracker
+import com.android.systemui.settings.fakeUserTracker
 import com.android.systemui.smartspace.data.repository.FakeSmartspaceRepository
 import com.android.systemui.smartspace.data.repository.fakeSmartspaceRepository
 import com.android.systemui.testKosmos
@@ -96,6 +100,7 @@
     private lateinit var communalPrefsRepository: FakeCommunalPrefsRepository
     private lateinit var editWidgetsActivityStarter: EditWidgetsActivityStarter
     private lateinit var sceneInteractor: SceneInteractor
+    private lateinit var userTracker: FakeUserTracker
 
     private lateinit var underTest: CommunalInteractor
 
@@ -113,6 +118,7 @@
         editWidgetsActivityStarter = kosmos.editWidgetsActivityStarter
         communalPrefsRepository = kosmos.fakeCommunalPrefsRepository
         sceneInteractor = kosmos.sceneInteractor
+        userTracker = kosmos.fakeUserTracker
 
         whenever(mainUser.isMain).thenReturn(true)
         whenever(secondaryUser.isMain).thenReturn(false)
@@ -207,25 +213,19 @@
             keyguardRepository.setKeyguardOccluded(false)
             tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
 
-            // Widgets are available.
-            val widgets =
-                listOf(
-                    CommunalWidgetContentModel(
-                        appWidgetId = 0,
-                        priority = 30,
-                        providerInfo = mock(),
-                    ),
-                    CommunalWidgetContentModel(
-                        appWidgetId = 1,
-                        priority = 20,
-                        providerInfo = mock(),
-                    ),
-                    CommunalWidgetContentModel(
-                        appWidgetId = 2,
-                        priority = 10,
-                        providerInfo = mock(),
-                    ),
-                )
+            val userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK)
+            userRepository.setUserInfos(userInfos)
+            userTracker.set(
+                userInfos = userInfos,
+                selectedUserIndex = 0,
+            )
+            runCurrent()
+
+            // Widgets available.
+            val widget1 = createWidgetForUser(1, USER_INFO_WORK.id)
+            val widget2 = createWidgetForUser(2, MAIN_USER_INFO.id)
+            val widget3 = createWidgetForUser(3, MAIN_USER_INFO.id)
+            val widgets = listOf(widget1, widget2, widget3)
             widgetRepository.setCommunalWidgets(widgets)
 
             val widgetContent by collectLastValue(underTest.widgetContent)
@@ -455,6 +455,9 @@
     @Test
     fun listensToSceneChange() =
         testScope.runTest {
+            kosmos.setCommunalAvailable(true)
+            runCurrent()
+
             var desiredScene = collectLastValue(underTest.desiredScene)
             runCurrent()
             assertThat(desiredScene()).isEqualTo(CommunalSceneKey.Blank)
@@ -479,6 +482,30 @@
         }
 
     @Test
+    fun desiredScene_communalNotAvailable_returnsBlank() =
+        testScope.runTest {
+            kosmos.setCommunalAvailable(true)
+            runCurrent()
+
+            val desiredScene by collectLastValue(underTest.desiredScene)
+
+            underTest.onSceneChanged(CommunalSceneKey.Communal)
+            assertThat(desiredScene).isEqualTo(CommunalSceneKey.Communal)
+
+            kosmos.setCommunalAvailable(false)
+            runCurrent()
+
+            // Scene returns blank when communal is not available.
+            assertThat(desiredScene).isEqualTo(CommunalSceneKey.Blank)
+
+            kosmos.setCommunalAvailable(true)
+            runCurrent()
+
+            // After re-enabling, scene goes back to Communal.
+            assertThat(desiredScene).isEqualTo(CommunalSceneKey.Communal)
+        }
+
+    @Test
     fun transitionProgress_onTargetScene_fullProgress() =
         testScope.runTest {
             val targetScene = CommunalSceneKey.Blank
@@ -604,8 +631,28 @@
         }
 
     @Test
+    fun isCommunalShowing() =
+        testScope.runTest {
+            kosmos.setCommunalAvailable(true)
+            runCurrent()
+
+            var isCommunalShowing = collectLastValue(underTest.isCommunalShowing)
+            runCurrent()
+            assertThat(isCommunalShowing()).isEqualTo(false)
+
+            underTest.onSceneChanged(CommunalSceneKey.Communal)
+
+            isCommunalShowing = collectLastValue(underTest.isCommunalShowing)
+            runCurrent()
+            assertThat(isCommunalShowing()).isEqualTo(true)
+        }
+
+    @Test
     fun isCommunalShowing_whenSceneContainerDisabled() =
         testScope.runTest {
+            kosmos.setCommunalAvailable(true)
+            runCurrent()
+
             // Verify default is false
             val isCommunalShowing by collectLastValue(underTest.isCommunalShowing)
             runCurrent()
@@ -752,6 +799,38 @@
             verify(editWidgetsActivityStarter).startActivity(widgetKey)
         }
 
+    @Test
+    fun filterWidgets_whenUserProfileRemoved() =
+        testScope.runTest {
+            // Keyguard showing, and tutorial completed.
+            keyguardRepository.setKeyguardShowing(true)
+            keyguardRepository.setKeyguardOccluded(false)
+            tutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
+
+            // Only main user exists.
+            val userInfos = listOf(MAIN_USER_INFO)
+            userRepository.setUserInfos(userInfos)
+            userTracker.set(
+                userInfos = userInfos,
+                selectedUserIndex = 0,
+            )
+            runCurrent()
+
+            val widgetContent by collectLastValue(underTest.widgetContent)
+            // Given three widgets, and one of them is associated with pre-existing work profile.
+            val widget1 = createWidgetForUser(1, USER_INFO_WORK.id)
+            val widget2 = createWidgetForUser(2, MAIN_USER_INFO.id)
+            val widget3 = createWidgetForUser(3, MAIN_USER_INFO.id)
+            val widgets = listOf(widget1, widget2, widget3)
+            widgetRepository.setCommunalWidgets(widgets)
+
+            // One widget is filtered out and the remaining two link to main user id.
+            assertThat(checkNotNull(widgetContent).size).isEqualTo(2)
+            widgetContent!!.forEachIndexed { _, model ->
+                assertThat(model.providerInfo.profile?.identifier).isEqualTo(MAIN_USER_INFO.id)
+            }
+        }
+
     private fun smartspaceTimer(id: String, timestamp: Long = 0L): SmartspaceTarget {
         val timer = mock(SmartspaceTarget::class.java)
         whenever(timer.smartspaceTargetId).thenReturn(id)
@@ -760,4 +839,17 @@
         whenever(timer.creationTimeMillis).thenReturn(timestamp)
         return timer
     }
+
+    private fun createWidgetForUser(appWidgetId: Int, userId: Int): CommunalWidgetContentModel =
+        mock<CommunalWidgetContentModel> {
+            whenever(this.appWidgetId).thenReturn(appWidgetId)
+            val providerInfo = mock<AppWidgetProviderInfo>()
+            whenever(providerInfo.profile).thenReturn(UserHandle(userId))
+            whenever(this.providerInfo).thenReturn(providerInfo)
+        }
+
+    private companion object {
+        val MAIN_USER_INFO = UserInfo(0, "primary", UserInfo.FLAG_MAIN)
+        val USER_INFO_WORK = UserInfo(10, "work", UserInfo.FLAG_PROFILE)
+    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt
index 5211c55..8b78592 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/domain/interactor/CommunalTutorialInteractorTest.kt
@@ -16,7 +16,6 @@
 
 package com.android.systemui.communal.domain.interactor
 
-import android.content.pm.UserInfo
 import android.provider.Settings.Secure.HUB_MODE_TUTORIAL_COMPLETED
 import android.provider.Settings.Secure.HUB_MODE_TUTORIAL_NOT_STARTED
 import android.provider.Settings.Secure.HUB_MODE_TUTORIAL_STARTED
@@ -61,7 +60,6 @@
         communalInteractor = kosmos.communalInteractor
         userRepository = kosmos.fakeUserRepository
 
-        userRepository.setUserInfos(listOf(MAIN_USER_INFO))
         kosmos.fakeFeatureFlagsClassic.set(Flags.COMMUNAL_SERVICE_ENABLED, true)
         mSetFlagsRule.enableFlags(FLAG_COMMUNAL_HUB)
 
@@ -72,7 +70,7 @@
     fun tutorialUnavailable_whenKeyguardNotVisible() =
         testScope.runTest {
             val isTutorialAvailable by collectLastValue(underTest.isTutorialAvailable)
-            setCommunalAvailable(true)
+            kosmos.setCommunalAvailable(true)
             communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_NOT_STARTED)
             keyguardRepository.setKeyguardShowing(false)
             assertThat(isTutorialAvailable).isFalse()
@@ -82,10 +80,7 @@
     fun tutorialUnavailable_whenTutorialIsCompleted() =
         testScope.runTest {
             val isTutorialAvailable by collectLastValue(underTest.isTutorialAvailable)
-            setCommunalAvailable(true)
-            keyguardRepository.setKeyguardShowing(true)
-            keyguardRepository.setKeyguardOccluded(false)
-            communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
+            goToCommunal()
             communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
             assertThat(isTutorialAvailable).isFalse()
         }
@@ -94,7 +89,7 @@
     fun tutorialUnavailable_whenCommunalNotAvailable() =
         testScope.runTest {
             val isTutorialAvailable by collectLastValue(underTest.isTutorialAvailable)
-            setCommunalAvailable(false)
+            kosmos.setCommunalAvailable(false)
             communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_NOT_STARTED)
             keyguardRepository.setKeyguardShowing(true)
             assertThat(isTutorialAvailable).isFalse()
@@ -104,10 +99,7 @@
     fun tutorialAvailable_whenTutorialNotStarted() =
         testScope.runTest {
             val isTutorialAvailable by collectLastValue(underTest.isTutorialAvailable)
-            setCommunalAvailable(true)
-            keyguardRepository.setKeyguardShowing(true)
-            keyguardRepository.setKeyguardOccluded(false)
-            communalInteractor.onSceneChanged(CommunalSceneKey.Blank)
+            kosmos.setCommunalAvailable(true)
             communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_NOT_STARTED)
             assertThat(isTutorialAvailable).isTrue()
         }
@@ -116,10 +108,7 @@
     fun tutorialAvailable_whenTutorialIsStarted() =
         testScope.runTest {
             val isTutorialAvailable by collectLastValue(underTest.isTutorialAvailable)
-            setCommunalAvailable(true)
-            keyguardRepository.setKeyguardShowing(true)
-            keyguardRepository.setKeyguardOccluded(false)
-            communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
+            goToCommunal()
             communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_STARTED)
             assertThat(isTutorialAvailable).isTrue()
         }
@@ -129,10 +118,9 @@
         testScope.runTest {
             val tutorialSettingState by
                 collectLastValue(communalTutorialRepository.tutorialSettingState)
-            userRepository.setSelectedUserInfo(MAIN_USER_INFO)
             communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_NOT_STARTED)
 
-            communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
+            goToCommunal()
 
             assertThat(tutorialSettingState).isEqualTo(HUB_MODE_TUTORIAL_STARTED)
         }
@@ -142,10 +130,10 @@
         testScope.runTest {
             val tutorialSettingState by
                 collectLastValue(communalTutorialRepository.tutorialSettingState)
-            userRepository.setSelectedUserInfo(MAIN_USER_INFO)
+
             communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_STARTED)
 
-            communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
+            goToCommunal()
 
             assertThat(tutorialSettingState).isEqualTo(HUB_MODE_TUTORIAL_STARTED)
         }
@@ -155,10 +143,9 @@
         testScope.runTest {
             val tutorialSettingState by
                 collectLastValue(communalTutorialRepository.tutorialSettingState)
-            userRepository.setSelectedUserInfo(MAIN_USER_INFO)
             communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
 
-            communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
+            goToCommunal()
 
             assertThat(tutorialSettingState).isEqualTo(HUB_MODE_TUTORIAL_COMPLETED)
         }
@@ -168,7 +155,7 @@
         testScope.runTest {
             val tutorialSettingState by
                 collectLastValue(communalTutorialRepository.tutorialSettingState)
-            userRepository.setSelectedUserInfo(MAIN_USER_INFO)
+            kosmos.setCommunalAvailable(true)
             communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_NOT_STARTED)
 
             communalInteractor.onSceneChanged(CommunalSceneKey.Blank)
@@ -181,8 +168,7 @@
         testScope.runTest {
             val tutorialSettingState by
                 collectLastValue(communalTutorialRepository.tutorialSettingState)
-            userRepository.setSelectedUserInfo(MAIN_USER_INFO)
-            communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
+            goToCommunal()
             communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_STARTED)
 
             communalInteractor.onSceneChanged(CommunalSceneKey.Blank)
@@ -195,8 +181,7 @@
         testScope.runTest {
             val tutorialSettingState by
                 collectLastValue(communalTutorialRepository.tutorialSettingState)
-            userRepository.setSelectedUserInfo(MAIN_USER_INFO)
-            communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
+            goToCommunal()
             communalTutorialRepository.setTutorialSettingState(HUB_MODE_TUTORIAL_COMPLETED)
 
             communalInteractor.onSceneChanged(CommunalSceneKey.Blank)
@@ -204,17 +189,8 @@
             assertThat(tutorialSettingState).isEqualTo(HUB_MODE_TUTORIAL_COMPLETED)
         }
 
-    private suspend fun setCommunalAvailable(available: Boolean) {
-        if (available) {
-            keyguardRepository.setIsEncryptedOrLockdown(false)
-            userRepository.setSelectedUserInfo(MAIN_USER_INFO)
-            keyguardRepository.setKeyguardShowing(true)
-        } else {
-            keyguardRepository.setIsEncryptedOrLockdown(true)
-        }
-    }
-
-    private companion object {
-        val MAIN_USER_INFO = UserInfo(0, "primary", UserInfo.FLAG_MAIN)
+    private suspend fun goToCommunal() {
+        kosmos.setCommunalAvailable(true)
+        communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
index 352bacc..5ee88cb 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
@@ -17,6 +17,9 @@
 package com.android.systemui.communal.view.viewmodel
 
 import android.app.smartspace.SmartspaceTarget
+import android.appwidget.AppWidgetProviderInfo
+import android.content.pm.UserInfo
+import android.os.UserHandle
 import android.provider.Settings
 import android.widget.RemoteViews
 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -39,6 +42,7 @@
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.log.logcatLogBuffer
 import com.android.systemui.media.controls.ui.view.MediaHost
+import com.android.systemui.settings.fakeUserTracker
 import com.android.systemui.smartspace.data.repository.FakeSmartspaceRepository
 import com.android.systemui.smartspace.data.repository.fakeSmartspaceRepository
 import com.android.systemui.testKosmos
@@ -59,6 +63,7 @@
 class CommunalEditModeViewModelTest : SysuiTestCase() {
     @Mock private lateinit var mediaHost: MediaHost
     @Mock private lateinit var uiEventLogger: UiEventLogger
+    @Mock private lateinit var providerInfo: AppWidgetProviderInfo
 
     private val kosmos = testKosmos()
     private val testScope = kosmos.testScope
@@ -78,6 +83,11 @@
         widgetRepository = kosmos.fakeCommunalWidgetRepository
         smartspaceRepository = kosmos.fakeSmartspaceRepository
         mediaRepository = kosmos.fakeCommunalMediaRepository
+        kosmos.fakeUserTracker.set(
+            userInfos = listOf(MAIN_USER_INFO),
+            selectedUserIndex = 0,
+        )
+        whenever(providerInfo.profile).thenReturn(UserHandle(MAIN_USER_INFO.id))
 
         underTest =
             CommunalEditModeViewModel(
@@ -100,12 +110,12 @@
                     CommunalWidgetContentModel(
                         appWidgetId = 0,
                         priority = 30,
-                        providerInfo = mock(),
+                        providerInfo = providerInfo,
                     ),
                     CommunalWidgetContentModel(
                         appWidgetId = 1,
                         priority = 20,
-                        providerInfo = mock(),
+                        providerInfo = providerInfo,
                     ),
                 )
             widgetRepository.setCommunalWidgets(widgets)
@@ -156,12 +166,12 @@
                     CommunalWidgetContentModel(
                         appWidgetId = 0,
                         priority = 30,
-                        providerInfo = mock(),
+                        providerInfo = providerInfo,
                     ),
                     CommunalWidgetContentModel(
                         appWidgetId = 1,
                         priority = 20,
-                        providerInfo = mock(),
+                        providerInfo = providerInfo,
                     ),
                 )
             widgetRepository.setCommunalWidgets(widgets)
@@ -205,4 +215,8 @@
         underTest.onReorderWidgetCancel()
         verify(uiEventLogger).log(CommunalUiEvent.COMMUNAL_HUB_REORDER_WIDGET_CANCEL)
     }
+
+    private companion object {
+        val MAIN_USER_INFO = UserInfo(0, "primary", UserInfo.FLAG_MAIN)
+    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
index cc322d0..1e523dd 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
@@ -17,7 +17,9 @@
 package com.android.systemui.communal.view.viewmodel
 
 import android.app.smartspace.SmartspaceTarget
+import android.appwidget.AppWidgetProviderInfo
 import android.content.pm.UserInfo
+import android.os.UserHandle
 import android.provider.Settings
 import android.widget.RemoteViews
 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -45,13 +47,13 @@
 import com.android.systemui.log.logcatLogBuffer
 import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager
 import com.android.systemui.media.controls.ui.view.MediaHost
+import com.android.systemui.settings.fakeUserTracker
 import com.android.systemui.shade.domain.interactor.shadeInteractor
 import com.android.systemui.smartspace.data.repository.FakeSmartspaceRepository
 import com.android.systemui.smartspace.data.repository.fakeSmartspaceRepository
 import com.android.systemui.testKosmos
 import com.android.systemui.user.data.repository.FakeUserRepository
 import com.android.systemui.user.data.repository.fakeUserRepository
-import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -71,6 +73,7 @@
 class CommunalViewModelTest : SysuiTestCase() {
     @Mock private lateinit var mediaHost: MediaHost
     @Mock private lateinit var user: UserInfo
+    @Mock private lateinit var providerInfo: AppWidgetProviderInfo
 
     private val kosmos = testKosmos()
     private val testScope = kosmos.testScope
@@ -98,6 +101,12 @@
         kosmos.fakeFeatureFlagsClassic.set(COMMUNAL_SERVICE_ENABLED, true)
         mSetFlagsRule.enableFlags(FLAG_COMMUNAL_HUB)
 
+        kosmos.fakeUserTracker.set(
+            userInfos = listOf(MAIN_USER_INFO),
+            selectedUserIndex = 0,
+        )
+        whenever(providerInfo.profile).thenReturn(UserHandle(MAIN_USER_INFO.id))
+
         underTest =
             CommunalViewModel(
                 testScope,
@@ -147,12 +156,12 @@
                     CommunalWidgetContentModel(
                         appWidgetId = 0,
                         priority = 30,
-                        providerInfo = mock(),
+                        providerInfo = providerInfo,
                     ),
                     CommunalWidgetContentModel(
                         appWidgetId = 1,
                         priority = 20,
-                        providerInfo = mock(),
+                        providerInfo = providerInfo,
                     ),
                 )
             widgetRepository.setCommunalWidgets(widgets)
@@ -225,4 +234,8 @@
         userRepository.setUserInfos(listOf(user))
         userRepository.setSelectedUserInfo(user)
     }
+
+    private companion object {
+        val MAIN_USER_INFO = UserInfo(0, "primary", UserInfo.FLAG_MAIN)
+    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartableTest.kt
index 8488843..2c9d72c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartableTest.kt
@@ -16,7 +16,9 @@
 
 package com.android.systemui.communal.widgets
 
+import android.appwidget.AppWidgetProviderInfo
 import android.content.pm.UserInfo
+import android.os.UserHandle
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
@@ -32,6 +34,7 @@
 import com.android.systemui.kosmos.applicationCoroutineScope
 import com.android.systemui.kosmos.testDispatcher
 import com.android.systemui.kosmos.testScope
+import com.android.systemui.settings.fakeUserTracker
 import com.android.systemui.testKosmos
 import com.android.systemui.user.data.repository.fakeUserRepository
 import com.android.systemui.util.mockito.mock
@@ -65,7 +68,7 @@
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
-        kosmos.fakeUserRepository.setUserInfos(listOf(MAIN_USER_INFO))
+        kosmos.fakeUserRepository.setUserInfos(listOf(MAIN_USER_INFO, USER_INFO_WORK))
         kosmos.fakeFeatureFlagsClassic.set(Flags.COMMUNAL_SERVICE_ENABLED, true)
         mSetFlagsRule.enableFlags(FLAG_COMMUNAL_HUB)
 
@@ -76,6 +79,7 @@
             CommunalAppWidgetHostStartable(
                 appWidgetHost,
                 kosmos.communalInteractor,
+                kosmos.fakeUserTracker,
                 kosmos.applicationCoroutineScope,
                 kosmos.testDispatcher,
             )
@@ -170,6 +174,46 @@
             }
         }
 
+    @Test
+    fun removeWidgetsForDeletedProfile_whenCommunalIsAvailable() =
+        with(kosmos) {
+            testScope.runTest {
+                // Communal is available and work profile is configured.
+                setCommunalAvailable(true)
+                kosmos.fakeUserTracker.set(
+                    userInfos = listOf(MAIN_USER_INFO, USER_INFO_WORK),
+                    selectedUserIndex = 0,
+                )
+                val widget1 = createWidgetForUser(1, USER_INFO_WORK.id)
+                val widget2 = createWidgetForUser(2, MAIN_USER_INFO.id)
+                val widget3 = createWidgetForUser(3, MAIN_USER_INFO.id)
+                val widgets = listOf(widget1, widget2, widget3)
+                fakeCommunalWidgetRepository.setCommunalWidgets(widgets)
+
+                underTest.start()
+                runCurrent()
+
+                val communalWidgets by
+                    collectLastValue(fakeCommunalWidgetRepository.communalWidgets)
+                assertThat(communalWidgets).containsExactly(widget1, widget2, widget3)
+
+                // Unlock the device and remove work profile.
+                fakeKeyguardRepository.setKeyguardShowing(false)
+                kosmos.fakeUserTracker.set(
+                    userInfos = listOf(MAIN_USER_INFO),
+                    selectedUserIndex = 0,
+                )
+                runCurrent()
+
+                // Communal becomes available.
+                fakeKeyguardRepository.setKeyguardShowing(true)
+                runCurrent()
+
+                // Widget created for work profile is removed.
+                assertThat(communalWidgets).containsExactly(widget2, widget3)
+            }
+        }
+
     private suspend fun setCommunalAvailable(available: Boolean) =
         with(kosmos) {
             fakeKeyguardRepository.setIsEncryptedOrLockdown(false)
@@ -179,7 +223,16 @@
             fakeSettings.putIntForUser(GLANCEABLE_HUB_ENABLED, settingsValue, MAIN_USER_INFO.id)
         }
 
+    private fun createWidgetForUser(appWidgetId: Int, userId: Int): CommunalWidgetContentModel =
+        mock<CommunalWidgetContentModel> {
+            whenever(this.appWidgetId).thenReturn(appWidgetId)
+            val providerInfo = mock<AppWidgetProviderInfo>()
+            whenever(providerInfo.profile).thenReturn(UserHandle(userId))
+            whenever(this.providerInfo).thenReturn(providerInfo)
+        }
+
     private companion object {
         val MAIN_USER_INFO = UserInfo(0, "primary", UserInfo.FLAG_MAIN)
+        val USER_INFO_WORK = UserInfo(10, "work", UserInfo.FLAG_PROFILE)
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt
index 12611cb..88f5e1b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/widgets/CommunalWidgetHostTest.kt
@@ -17,8 +17,10 @@
 package com.android.systemui.communal.widgets
 
 import android.appwidget.AppWidgetManager
+import android.appwidget.AppWidgetProviderInfo
 import android.content.ComponentName
 import android.content.pm.UserInfo
+import android.os.Bundle
 import android.os.UserHandle
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
@@ -33,8 +35,8 @@
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor
 import com.android.systemui.user.domain.interactor.selectedUserInteractor
 import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.nullable
 import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.mockito.withArgCaptor
 import com.google.common.truth.Truth.assertThat
 import java.util.Optional
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -43,6 +45,7 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.eq
 import org.mockito.Mock
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
@@ -91,7 +94,7 @@
                         any<Int>(),
                         any<UserHandle>(),
                         any<ComponentName>(),
-                        nullable()
+                        any<Bundle>(),
                     )
                 )
                 .thenReturn(true)
@@ -100,8 +103,14 @@
             val result = underTest.allocateIdAndBindWidget(provider)
 
             verify(appWidgetHost).allocateAppWidgetId()
-            verify(appWidgetManager).bindAppWidgetIdIfAllowed(widgetId, user, provider, null)
+            val bundle =
+                withArgCaptor<Bundle> {
+                    verify(appWidgetManager)
+                        .bindAppWidgetIdIfAllowed(eq(widgetId), eq(user), eq(provider), capture())
+                }
             assertThat(result).isEqualTo(widgetId)
+            assertThat(bundle.getInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY))
+                .isEqualTo(AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD)
         }
 
     @Test
@@ -117,7 +126,7 @@
                         any<Int>(),
                         any<UserHandle>(),
                         any<ComponentName>(),
-                        nullable()
+                        any<Bundle>()
                     )
                 )
                 .thenReturn(true)
@@ -126,8 +135,14 @@
             val result = underTest.allocateIdAndBindWidget(provider, user)
 
             verify(appWidgetHost).allocateAppWidgetId()
-            verify(appWidgetManager).bindAppWidgetIdIfAllowed(widgetId, user, provider, null)
+            val bundle =
+                withArgCaptor<Bundle> {
+                    verify(appWidgetManager)
+                        .bindAppWidgetIdIfAllowed(eq(widgetId), eq(user), eq(provider), capture())
+                }
             assertThat(result).isEqualTo(widgetId)
+            assertThat(bundle.getInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY))
+                .isEqualTo(AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD)
         }
 
     @Test
@@ -144,14 +159,15 @@
                         any<Int>(),
                         any<UserHandle>(),
                         any<ComponentName>(),
-                        nullable()
+                        any<Bundle>()
                     )
                 )
                 .thenReturn(false)
             val result = underTest.allocateIdAndBindWidget(provider, user)
 
             verify(appWidgetHost).allocateAppWidgetId()
-            verify(appWidgetManager).bindAppWidgetIdIfAllowed(widgetId, user, provider, null)
+            verify(appWidgetManager)
+                .bindAppWidgetIdIfAllowed(eq(widgetId), eq(user), eq(provider), any())
             verify(appWidgetHost).deleteAppWidgetId(widgetId)
             assertThat(result).isNull()
         }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
index a6715df..c670506 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayAnimationsControllerTest.kt
@@ -11,7 +11,6 @@
 import com.android.systemui.dreams.ui.viewmodel.DreamOverlayViewModel
 import com.android.systemui.log.core.FakeLogBuffer
 import com.android.systemui.statusbar.BlurUtils
-import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
@@ -46,7 +45,6 @@
     @Mock private lateinit var hostViewController: ComplicationHostViewController
     @Mock private lateinit var statusBarViewController: DreamOverlayStatusBarViewController
     @Mock private lateinit var stateController: DreamOverlayStateController
-    @Mock private lateinit var configController: ConfigurationController
     @Mock private lateinit var transitionViewModel: DreamOverlayViewModel
     private val logBuffer = FakeLogBuffer.Factory.create()
     private lateinit var controller: DreamOverlayAnimationsController
@@ -62,7 +60,6 @@
                 stateController,
                 DREAM_BLUR_RADIUS,
                 transitionViewModel,
-                configController,
                 DREAM_IN_BLUR_ANIMATION_DURATION,
                 DREAM_IN_COMPLICATIONS_ANIMATION_DURATION,
                 DREAM_IN_TRANSLATION_Y_DISTANCE,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
index 558e7e6..3a28471 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepositoryTest.kt
@@ -33,6 +33,7 @@
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.filterIsInstance
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import kotlinx.coroutines.test.runCurrent
@@ -215,6 +216,39 @@
         }
 
     @Test
+    fun onFingerprintFailed_failedAuthenticationStatusWithOtherStatuses() =
+        testScope.runTest {
+            val failStatus by
+                collectLastValue(
+                    underTest.authenticationStatus.filterIsInstance<
+                        FailFingerprintAuthenticationStatus
+                    >()
+                )
+            runCurrent()
+
+            verify(keyguardUpdateMonitor).registerCallback(updateMonitorCallback.capture())
+            updateMonitorCallback.value.onBiometricAcquired(
+                BiometricSourceType.FINGERPRINT,
+                /* acquireInfo */ 0,
+            )
+            updateMonitorCallback.value.onBiometricAuthFailed(
+                BiometricSourceType.FINGERPRINT,
+            )
+            updateMonitorCallback.value.onBiometricHelp(
+                /* msgId */ 7,
+                /* errString */ "Not recognized.",
+                BiometricSourceType.FINGERPRINT,
+            )
+            updateMonitorCallback.value.onBiometricError(
+                /* msgId */ 7,
+                /* errString */ "Too many attempts.",
+                BiometricSourceType.FINGERPRINT,
+            )
+
+            assertThat(failStatus).isNotNull()
+        }
+
+    @Test
     fun onFingerprintError_errorAuthenticationStatus() =
         testScope.runTest {
             val authenticationStatus by collectLastValue(underTest.authenticationStatus)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelTest.kt
index 199ffa6..3f6e229 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModelTest.kt
@@ -19,15 +19,15 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
 import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
 import com.android.systemui.biometrics.shared.model.FingerprintSensorType
 import com.android.systemui.biometrics.shared.model.SensorStrength
 import com.android.systemui.coroutines.collectValues
-import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
-import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
 import com.android.systemui.keyguard.shared.model.TransitionState
@@ -63,7 +63,7 @@
     }
 
     @Test
-    fun deviceEntryParentViewAppear() =
+    fun deviceEntryParentViewAppear_udfpsEnrolledAndEnabled() =
         testScope.runTest {
             fingerprintPropertyRepository.setProperties(
                 sensorId = 0,
@@ -90,6 +90,33 @@
         }
 
     @Test
+    fun deviceEntryParentViewDisappear_udfpsNotEnrolledAndEnabled() =
+        testScope.runTest {
+            fingerprintPropertyRepository.setProperties(
+                sensorId = 0,
+                strength = SensorStrength.STRONG,
+                sensorType = FingerprintSensorType.UDFPS_OPTICAL,
+                sensorLocations = emptyMap(),
+            )
+            biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
+            val values by collectValues(underTest.deviceEntryParentViewAlpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0f),
+                    step(0.1f),
+                    step(0.2f),
+                    step(0.3f),
+                    step(1f),
+                ),
+                testScope,
+            )
+
+            values.forEach { assertThat(it).isEqualTo(0f) }
+        }
+
+    @Test
     fun deviceEntryBackgroundViewDisappear() =
         testScope.runTest {
             val values by collectValues(underTest.deviceEntryBackgroundViewAlpha)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModelTest.kt
new file mode 100644
index 0000000..f8a6fc7
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModelTest.kt
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2024 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.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class AlternateBouncerToDozingTransitionViewModelTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+    private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
+    private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository
+    private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
+    private lateinit var underTest: AlternateBouncerToDozingTransitionViewModel
+
+    @Before
+    fun setUp() {
+        keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
+        fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository
+        biometricSettingsRepository = kosmos.biometricSettingsRepository
+        underTest = kosmos.alternateBouncerToDozingTransitionViewModel
+    }
+
+    @Test
+    fun deviceEntryParentViewAppear_udfpsEnrolledAndEnabled() =
+        testScope.runTest {
+            fingerprintPropertyRepository.supportsUdfps()
+            biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+            val values by collectValues(underTest.deviceEntryParentViewAlpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0f),
+                    step(0.1f),
+                    step(0.2f),
+                    step(0.3f),
+                    step(1f),
+                ),
+                testScope,
+            )
+
+            values.forEach { assertThat(it).isEqualTo(1f) }
+        }
+
+    @Test
+    fun deviceEntryParentViewDisappear_udfpsNotEnrolledAndEnabled() =
+        testScope.runTest {
+            fingerprintPropertyRepository.supportsUdfps()
+            biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
+            val values by collectValues(underTest.deviceEntryParentViewAlpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0f),
+                    step(0.1f),
+                    step(0.2f),
+                    step(0.3f),
+                    step(1f),
+                ),
+                testScope,
+            )
+
+            values.forEach { assertThat(it).isEqualTo(0f) }
+        }
+
+    @Test
+    fun deviceEntryBackgroundViewDisappear() =
+        testScope.runTest {
+            val values by collectValues(underTest.deviceEntryBackgroundViewAlpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0f),
+                    step(0.1f),
+                    step(0.2f),
+                    step(0.3f),
+                    step(1f),
+                ),
+                testScope,
+            )
+
+            values.forEach { assertThat(it).isEqualTo(0f) }
+        }
+
+    private fun step(value: Float, state: TransitionState = RUNNING): TransitionStep {
+        return TransitionStep(
+            from = KeyguardState.ALTERNATE_BOUNCER,
+            to = KeyguardState.DOZING,
+            value = value,
+            transitionState = state,
+            ownerName = "AlternateBouncerToDozingTransitionViewModelTest"
+        )
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelTest.kt
new file mode 100644
index 0000000..7e937db
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelTest.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2024 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.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DozingToGoneTransitionViewModelTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+    private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
+    private lateinit var underTest: DozingToGoneTransitionViewModel
+
+    @Before
+    fun setUp() {
+        keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
+        underTest = kosmos.dozingToGoneTransitionViewModel
+    }
+
+    @Test
+    fun deviceEntryParentViewDisappear() =
+        testScope.runTest {
+            val values by collectValues(underTest.deviceEntryParentViewAlpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0f),
+                    step(0.1f),
+                    step(0.2f),
+                    step(0.3f),
+                    step(1f),
+                ),
+                testScope,
+            )
+
+            values.forEach { assertThat(it).isEqualTo(0f) }
+        }
+
+    private fun step(value: Float, state: TransitionState = RUNNING): TransitionStep {
+        return TransitionStep(
+            from = KeyguardState.DOZING,
+            to = KeyguardState.GONE,
+            value = value,
+            transitionState = state,
+            ownerName = "DozingToGoneTransitionViewModelTest"
+        )
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModelTest.kt
new file mode 100644
index 0000000..bf71bec
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModelTest.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2024 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.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DozingToPrimaryBouncerTransitionViewModelTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+    private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
+    private lateinit var underTest: DozingToPrimaryBouncerTransitionViewModel
+
+    @Before
+    fun setUp() {
+        keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
+        underTest = kosmos.dozingToPrimaryBouncerTransitionViewModel
+    }
+
+    @Test
+    fun deviceEntryParentViewDisappear() =
+        testScope.runTest {
+            val values by collectValues(underTest.deviceEntryParentViewAlpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0f),
+                    step(0.1f),
+                    step(0.2f),
+                    step(0.3f),
+                    step(1f),
+                ),
+                testScope,
+            )
+
+            values.forEach { assertThat(it).isEqualTo(0f) }
+        }
+
+    private fun step(value: Float, state: TransitionState = RUNNING): TransitionStep {
+        return TransitionStep(
+            from = KeyguardState.DOZING,
+            to = KeyguardState.PRIMARY_BOUNCER,
+            value = value,
+            transitionState = state,
+            ownerName = "DozingToPrimaryBouncerTransitionViewModelTest"
+        )
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelTest.kt
index 4defe8a..aba21c9 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelTest.kt
@@ -19,12 +19,14 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
 import com.android.systemui.coroutines.collectValues
 import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.keyguard.shared.model.TransitionStep
 import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
 import com.android.systemui.testKosmos
 import com.google.common.collect.Range
 import com.google.common.truth.Truth.assertThat
@@ -38,6 +40,7 @@
     val kosmos = testKosmos()
     val testScope = kosmos.testScope
 
+    val configurationRepository by lazy { kosmos.fakeConfigurationRepository }
     val underTest by lazy { kosmos.dreamingToGlanceableHubTransitionViewModel }
 
     @Test
@@ -66,7 +69,12 @@
     @Test
     fun dreamOverlayTranslationX() =
         testScope.runTest {
-            val values by collectValues(underTest.dreamOverlayTranslationX(100))
+            configurationRepository.setDimensionPixelSize(
+                R.dimen.dreaming_to_hub_transition_dream_overlay_translation_x,
+                -100
+            )
+
+            val values by collectValues(underTest.dreamOverlayTranslationX)
             assertThat(values).isEmpty()
 
             kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelTest.kt
new file mode 100644
index 0000000..11890c7
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelTest.kt
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2024 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.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.res.R
+import com.android.systemui.testKosmos
+import com.google.common.collect.Range
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class GlanceableHubToDreamingTransitionViewModelTest : SysuiTestCase() {
+    val kosmos = testKosmos()
+    val testScope = kosmos.testScope
+
+    val configurationRepository by lazy { kosmos.fakeConfigurationRepository }
+    val underTest by lazy { kosmos.glanceableHubToDreamingTransitionViewModel }
+
+    @Test
+    fun dreamOverlayAlpha() =
+        testScope.runTest {
+            val values by collectValues(underTest.dreamOverlayAlpha)
+            assertThat(values).isEmpty()
+
+            kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0f),
+                    // Should start running here...
+                    step(0.1f),
+                    step(0.5f),
+                    // Up to here...
+                    step(1f),
+                ),
+                testScope,
+            )
+
+            assertThat(values).hasSize(2)
+            values.forEach { assertThat(it).isIn(Range.closed(0f, 1f)) }
+        }
+
+    @Test
+    fun dreamOverlayTranslationX() =
+        testScope.runTest {
+            configurationRepository.setDimensionPixelSize(
+                R.dimen.hub_to_dreaming_transition_dream_overlay_translation_x,
+                100
+            )
+
+            val values by collectValues(underTest.dreamOverlayTranslationX)
+            assertThat(values).isEmpty()
+
+            kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0.3f),
+                    step(0.6f),
+                ),
+                testScope,
+            )
+
+            assertThat(values).hasSize(3)
+            values.forEach { assertThat(it).isIn(Range.closed(-100f, 0f)) }
+        }
+
+    private fun step(
+        value: Float,
+        state: TransitionState = TransitionState.RUNNING
+    ): TransitionStep {
+        return TransitionStep(
+            from = KeyguardState.GLANCEABLE_HUB,
+            to = KeyguardState.DREAMING,
+            value = value,
+            transitionState = state,
+            ownerName = GlanceableHubToDreamingTransitionViewModelTest::class.java.simpleName
+        )
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelTest.kt
new file mode 100644
index 0000000..59a6ce7
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelTest.kt
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2024 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.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.biometrics.data.repository.fakeFingerprintPropertyRepository
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.fakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class GoneToDozingTransitionViewModelTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+    private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository
+    private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
+    private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
+    private lateinit var underTest: GoneToDozingTransitionViewModel
+
+    @Before
+    fun setUp() {
+        fingerprintPropertyRepository = kosmos.fakeFingerprintPropertyRepository
+        biometricSettingsRepository = kosmos.fakeBiometricSettingsRepository
+        keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
+        underTest = kosmos.goneToDozingTransitionViewModel
+    }
+
+    @Test
+    fun deviceEntryParentViewAppear_udfpsEnrolledAndEnabled() =
+        testScope.runTest {
+            fingerprintPropertyRepository.supportsUdfps()
+            biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+
+            val values by collectValues(underTest.deviceEntryParentViewAlpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0f),
+                    step(0.1f),
+                    step(0.2f),
+                    step(0.3f),
+                    step(1f),
+                ),
+                testScope,
+            )
+
+            values.forEach { assertThat(it).isEqualTo(1f) }
+        }
+
+    @Test
+    fun deviceEntryParentViewDisappear_noUdfpsEnrolled_noUpdates() =
+        testScope.runTest {
+            fingerprintPropertyRepository.supportsUdfps()
+            biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
+
+            val values by collectValues(underTest.deviceEntryParentViewAlpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0f),
+                    step(0.1f),
+                    step(0.2f),
+                    step(0.3f),
+                    step(1f),
+                ),
+                testScope,
+            )
+
+            values.forEach { assertThat(it).isNull() }
+        }
+
+    private fun step(value: Float, state: TransitionState = RUNNING): TransitionStep {
+        return TransitionStep(
+            from = KeyguardState.GONE,
+            to = KeyguardState.DOZING,
+            value = value,
+            transitionState = state,
+            ownerName = "GoneToDozingTransitionViewModelTest"
+        )
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelTest.kt
new file mode 100644
index 0000000..28f5eba
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelTest.kt
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2024 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.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class LockscreenToDozingTransitionViewModelTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+    private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
+    private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository
+    private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
+    private lateinit var underTest: LockscreenToDozingTransitionViewModel
+
+    @Before
+    fun setUp() {
+        keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
+        fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository
+        biometricSettingsRepository = kosmos.biometricSettingsRepository
+        underTest = kosmos.lockscreenToDozingTransitionViewModel
+    }
+
+    @Test
+    fun deviceEntryParentViewAppear_udfpsEnrolledAndEnabled() =
+        testScope.runTest {
+            fingerprintPropertyRepository.supportsUdfps()
+            biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+            val values by collectValues(underTest.deviceEntryParentViewAlpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0f),
+                    step(0.1f),
+                    step(0.2f),
+                    step(0.3f),
+                    step(1f),
+                ),
+                testScope,
+            )
+
+            values.forEach { assertThat(it).isEqualTo(1f) }
+        }
+
+    @Test
+    fun deviceEntryParentViewDisappear_udfpsNotEnrolled() =
+        testScope.runTest {
+            fingerprintPropertyRepository.supportsUdfps()
+            biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
+            val values by collectValues(underTest.deviceEntryParentViewAlpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0f),
+                    step(0.1f),
+                    step(0.2f),
+                    step(0.3f),
+                    step(1f),
+                ),
+                testScope,
+            )
+
+            values.forEach { assertThat(it).isEqualTo(0f) }
+        }
+
+    @Test
+    fun deviceEntryBackgroundViewDisappear() =
+        testScope.runTest {
+            val values by collectValues(underTest.deviceEntryBackgroundViewAlpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0f),
+                    step(0.1f),
+                    step(0.2f),
+                    step(0.3f),
+                    step(1f),
+                ),
+                testScope,
+            )
+
+            values.forEach { assertThat(it).isEqualTo(0f) }
+        }
+
+    private fun step(value: Float, state: TransitionState = RUNNING): TransitionStep {
+        return TransitionStep(
+            from = KeyguardState.LOCKSCREEN,
+            to = KeyguardState.DOZING,
+            value = value,
+            transitionState = state,
+            ownerName = "LockscreenToDozingTransitionViewModelTest"
+        )
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModelTest.kt
new file mode 100644
index 0000000..28473b2
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModelTest.kt
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2024 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.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.biometricSettingsRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class PrimaryBouncerToDozingTransitionViewModelTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+    private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
+    private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository
+    private lateinit var biometricSettingsRepository: FakeBiometricSettingsRepository
+    private lateinit var underTest: PrimaryBouncerToDozingTransitionViewModel
+
+    @Before
+    fun setUp() {
+        keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
+        fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository
+        biometricSettingsRepository = kosmos.biometricSettingsRepository
+        underTest = kosmos.primaryBouncerToDozingTransitionViewModel
+    }
+
+    @Test
+    fun deviceEntryParentViewAppear_udfpsEnrolledAndEnabled() =
+        testScope.runTest {
+            fingerprintPropertyRepository.supportsUdfps()
+            biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
+            val values by collectValues(underTest.deviceEntryParentViewAlpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0f),
+                    step(0.1f),
+                    step(0.2f),
+                    step(0.3f),
+                    step(1f),
+                ),
+                testScope,
+            )
+
+            values.forEach { assertThat(it).isEqualTo(1f) }
+        }
+
+    @Test
+    fun deviceEntryParentView_udfpsNotEnrolledAndEnabled_noUpdates() =
+        testScope.runTest {
+            fingerprintPropertyRepository.supportsUdfps()
+            biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false)
+            val values by collectValues(underTest.deviceEntryParentViewAlpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0f),
+                    step(0.1f),
+                    step(0.2f),
+                    step(0.3f),
+                    step(1f),
+                ),
+                testScope,
+            )
+
+            values.forEach { assertThat(it).isNull() }
+        }
+
+    @Test
+    fun deviceEntryBackgroundViewDisappear() =
+        testScope.runTest {
+            val values by collectValues(underTest.deviceEntryBackgroundViewAlpha)
+
+            keyguardTransitionRepository.sendTransitionSteps(
+                listOf(
+                    step(0f, TransitionState.STARTED),
+                    step(0f),
+                    step(0.1f),
+                    step(0.2f),
+                    step(0.3f),
+                    step(1f),
+                ),
+                testScope,
+            )
+
+            values.forEach { assertThat(it).isEqualTo(0f) }
+        }
+
+    private fun step(value: Float, state: TransitionState = RUNNING): TransitionStep {
+        return TransitionStep(
+            from = KeyguardState.PRIMARY_BOUNCER,
+            to = KeyguardState.DOZING,
+            value = value,
+            transitionState = state,
+            ownerName = "PrimaryBouncerToDozingTransitionViewModelTest"
+        )
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/domain/interactor/SpatializerInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/domain/interactor/SpatializerInteractorTest.kt
new file mode 100644
index 0000000..a932dd6
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/domain/interactor/SpatializerInteractorTest.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2024 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.media.domain.interactor
+
+import android.media.AudioDeviceAttributes
+import android.media.AudioDeviceInfo
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.settingslib.media.domain.interactor.SpatializerInteractor
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.media.spatializerRepository
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class SpatializerInteractorTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos()
+    private val underTest = SpatializerInteractor(kosmos.spatializerRepository)
+
+    @Test
+    fun setSpatialAudioEnabledFalse_isEnabled_false() {
+        with(kosmos) {
+            testScope.runTest {
+                underTest.setSpatialAudioEnabled(deviceAttributes, false)
+
+                assertThat(underTest.isSpatialAudioEnabled(deviceAttributes)).isFalse()
+            }
+        }
+    }
+
+    @Test
+    fun setSpatialAudioEnabledTrue_isEnabled_true() {
+        with(kosmos) {
+            testScope.runTest {
+                underTest.setSpatialAudioEnabled(deviceAttributes, true)
+
+                assertThat(underTest.isSpatialAudioEnabled(deviceAttributes)).isTrue()
+            }
+        }
+    }
+
+    @Test
+    fun setHeadTrackingEnabledFalse_isEnabled_false() {
+        with(kosmos) {
+            testScope.runTest {
+                underTest.setHeadTrackingEnabled(deviceAttributes, false)
+
+                assertThat(underTest.isHeadTrackingEnabled(deviceAttributes)).isFalse()
+            }
+        }
+    }
+
+    @Test
+    fun setHeadTrackingEnabledTrue_isEnabled_true() {
+        with(kosmos) {
+            testScope.runTest {
+                underTest.setHeadTrackingEnabled(deviceAttributes, true)
+
+                assertThat(underTest.isHeadTrackingEnabled(deviceAttributes)).isTrue()
+            }
+        }
+    }
+
+    private companion object {
+        val deviceAttributes =
+            AudioDeviceAttributes(
+                AudioDeviceAttributes.ROLE_OUTPUT,
+                AudioDeviceInfo.TYPE_BLE_HEADSET,
+                "test_address",
+            )
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
index 4e72843..fff0a31 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
@@ -40,6 +40,7 @@
 import com.android.systemui.bouncer.ui.viewmodel.bouncerViewModel
 import com.android.systemui.classifier.domain.interactor.falsingInteractor
 import com.android.systemui.classifier.falsingCollector
+import com.android.systemui.classifier.falsingManager
 import com.android.systemui.communal.domain.interactor.communalInteractor
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
@@ -265,6 +266,7 @@
                 displayId = displayTracker.defaultDisplayId,
                 sceneLogger = mock(),
                 falsingCollector = kosmos.falsingCollector,
+                falsingManager = kosmos.falsingManager,
                 powerInteractor = powerInteractor,
                 bouncerInteractor = bouncerInteractor,
                 simBouncerInteractor = dagger.Lazy { kosmos.simBouncerInteractor },
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/PanelExpansionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/PanelExpansionInteractorTest.kt
new file mode 100644
index 0000000..9b0adb1
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/PanelExpansionInteractorTest.kt
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.scene.domain.interactor
+
+import android.platform.test.annotations.DisableFlags
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.Flags.FLAG_SCENE_CONTAINER
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
+import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
+import com.android.systemui.flags.EnableSceneContainer
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.shared.model.ObservableTransitionState
+import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.fakeSceneDataSource
+import com.android.systemui.shade.data.repository.fakeShadeRepository
+import com.android.systemui.statusbar.notification.stack.ui.viewmodel.panelExpansionInteractor
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.flowOf
+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
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class PanelExpansionInteractorTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+    private val deviceEntryRepository = kosmos.fakeDeviceEntryRepository
+    private val deviceUnlockedInteractor = kosmos.deviceUnlockedInteractor
+    private val sceneInteractor = kosmos.sceneInteractor
+    private val transitionState =
+        MutableStateFlow<ObservableTransitionState>(
+            ObservableTransitionState.Idle(SceneKey.Lockscreen)
+        )
+    private val fakeSceneDataSource = kosmos.fakeSceneDataSource
+    private val fakeShadeRepository = kosmos.fakeShadeRepository
+
+    private lateinit var underTest: PanelExpansionInteractor
+
+    @Before
+    fun setUp() {
+        sceneInteractor.setTransitionState(transitionState)
+    }
+
+    @Test
+    @EnableSceneContainer
+    fun legacyPanelExpansion_whenIdle_whenLocked() =
+        testScope.runTest {
+            underTest = kosmos.panelExpansionInteractor
+            setUnlocked(false)
+            val panelExpansion by collectLastValue(underTest.legacyPanelExpansion)
+
+            changeScene(SceneKey.Lockscreen) { assertThat(panelExpansion).isEqualTo(1f) }
+            assertThat(panelExpansion).isEqualTo(1f)
+
+            changeScene(SceneKey.Bouncer) { assertThat(panelExpansion).isEqualTo(1f) }
+            assertThat(panelExpansion).isEqualTo(1f)
+
+            changeScene(SceneKey.Shade) { assertThat(panelExpansion).isEqualTo(1f) }
+            assertThat(panelExpansion).isEqualTo(1f)
+
+            changeScene(SceneKey.QuickSettings) { assertThat(panelExpansion).isEqualTo(1f) }
+            assertThat(panelExpansion).isEqualTo(1f)
+
+            changeScene(SceneKey.Communal) { assertThat(panelExpansion).isEqualTo(1f) }
+            assertThat(panelExpansion).isEqualTo(1f)
+        }
+
+    @Test
+    @EnableSceneContainer
+    fun legacyPanelExpansion_whenIdle_whenUnlocked() =
+        testScope.runTest {
+            underTest = kosmos.panelExpansionInteractor
+            setUnlocked(true)
+            val panelExpansion by collectLastValue(underTest.legacyPanelExpansion)
+
+            changeScene(SceneKey.Gone) { assertThat(panelExpansion).isEqualTo(0f) }
+            assertThat(panelExpansion).isEqualTo(0f)
+
+            changeScene(SceneKey.Shade) { progress ->
+                assertThat(panelExpansion).isEqualTo(progress)
+            }
+            assertThat(panelExpansion).isEqualTo(1f)
+
+            changeScene(SceneKey.QuickSettings) {
+                // Shade's already expanded, so moving to QS should also be 1f.
+                assertThat(panelExpansion).isEqualTo(1f)
+            }
+            assertThat(panelExpansion).isEqualTo(1f)
+
+            changeScene(SceneKey.Communal) { assertThat(panelExpansion).isEqualTo(1f) }
+            assertThat(panelExpansion).isEqualTo(1f)
+        }
+
+    @Test
+    @DisableFlags(FLAG_SCENE_CONTAINER)
+    fun legacyPanelExpansion_whenInLegacyMode() =
+        testScope.runTest {
+            underTest = kosmos.panelExpansionInteractor
+            val leet = 0.1337f
+            fakeShadeRepository.setLegacyShadeExpansion(leet)
+            setUnlocked(false)
+            val panelExpansion by collectLastValue(underTest.legacyPanelExpansion)
+
+            changeScene(SceneKey.Lockscreen)
+            assertThat(panelExpansion).isEqualTo(leet)
+
+            changeScene(SceneKey.Bouncer)
+            assertThat(panelExpansion).isEqualTo(leet)
+
+            changeScene(SceneKey.Shade)
+            assertThat(panelExpansion).isEqualTo(leet)
+
+            changeScene(SceneKey.QuickSettings)
+            assertThat(panelExpansion).isEqualTo(leet)
+
+            changeScene(SceneKey.Communal)
+            assertThat(panelExpansion).isEqualTo(leet)
+        }
+
+    private fun TestScope.setUnlocked(isUnlocked: Boolean) {
+        val isDeviceUnlocked by collectLastValue(deviceUnlockedInteractor.isDeviceUnlocked)
+        deviceEntryRepository.setUnlocked(isUnlocked)
+        runCurrent()
+
+        assertThat(isDeviceUnlocked).isEqualTo(isUnlocked)
+    }
+
+    private fun TestScope.changeScene(
+        toScene: SceneKey,
+        assertDuringProgress: ((progress: Float) -> Unit) = {},
+    ) {
+        val currentScene by collectLastValue(sceneInteractor.currentScene)
+        val progressFlow = MutableStateFlow(0f)
+        transitionState.value =
+            ObservableTransitionState.Transition(
+                fromScene = checkNotNull(currentScene),
+                toScene = toScene,
+                progress = progressFlow,
+                isInitiatedByUserInput = true,
+                isUserInputOngoing = flowOf(true),
+            )
+        runCurrent()
+        assertDuringProgress(progressFlow.value)
+
+        progressFlow.value = 0.2f
+        runCurrent()
+        assertDuringProgress(progressFlow.value)
+
+        progressFlow.value = 0.6f
+        runCurrent()
+        assertDuringProgress(progressFlow.value)
+
+        progressFlow.value = 1f
+        runCurrent()
+        assertDuringProgress(progressFlow.value)
+
+        transitionState.value = ObservableTransitionState.Idle(toScene)
+        fakeSceneDataSource.changeScene(toScene)
+        runCurrent()
+        assertDuringProgress(progressFlow.value)
+
+        assertThat(currentScene).isEqualTo(toScene)
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
index f49b477..4e16236 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
@@ -32,6 +32,7 @@
 import com.android.systemui.bouncer.domain.interactor.bouncerInteractor
 import com.android.systemui.bouncer.domain.interactor.simBouncerInteractor
 import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.classifier.falsingManager
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
 import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor
@@ -115,6 +116,7 @@
                 displayId = Display.DEFAULT_DISPLAY,
                 sceneLogger = mock(),
                 falsingCollector = falsingCollector,
+                falsingManager = kosmos.falsingManager,
                 powerInteractor = powerInteractor,
                 bouncerInteractor = bouncerInteractor,
                 simBouncerInteractor = { kosmos.simBouncerInteractor },
@@ -970,6 +972,20 @@
             )
         }
 
+    @Test
+    fun respondToFalsingDetections() =
+        testScope.runTest {
+            val currentScene by collectLastValue(sceneInteractor.currentScene)
+            val transitionStateFlow = prepareState()
+            underTest.start()
+            emulateSceneTransition(transitionStateFlow, toScene = SceneKey.Bouncer)
+            assertThat(currentScene).isNotEqualTo(SceneKey.Lockscreen)
+
+            kosmos.falsingManager.sendFalsingBelief()
+
+            assertThat(currentScene).isEqualTo(SceneKey.Lockscreen)
+        }
+
     private fun TestScope.emulateSceneTransition(
         transitionStateFlow: MutableStateFlow<ObservableTransitionState>,
         toScene: SceneKey,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
index 87d25dd..6456669 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/BaseHeadsUpManagerTest.java
@@ -19,8 +19,6 @@
 import static android.app.Notification.FLAG_FSI_REQUESTED_BUT_DENIED;
 
 import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer;
-import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED;
-import static com.android.systemui.util.concurrency.MockExecutorHandlerKt.mockExecutorHandler;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -41,31 +39,23 @@
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.Person;
-import android.content.Context;
 import android.content.Intent;
-import android.graphics.Region;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.testing.TestableLooper;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.test.filters.SmallTest;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
 
-import com.android.internal.logging.UiEventLogger;
 import com.android.internal.logging.testing.UiEventLoggerFake;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.res.R;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.util.concurrency.DelayableExecutor;
 import com.android.systemui.util.concurrency.FakeExecutor;
 import com.android.systemui.util.settings.FakeGlobalSettings;
-import com.android.systemui.util.settings.GlobalSettings;
 import com.android.systemui.util.time.FakeSystemClock;
-import com.android.systemui.util.time.SystemClock;
 
 import org.junit.Rule;
 import org.junit.Test;
@@ -83,8 +73,8 @@
 
     private static final String TEST_PACKAGE_NAME = "BaseHeadsUpManagerTest";
 
-    private static final int TEST_TOUCH_ACCEPTANCE_TIME = 200;
-    private static final int TEST_A11Y_AUTO_DISMISS_TIME = 1_000;
+    static final int TEST_TOUCH_ACCEPTANCE_TIME = 200;
+    static final int TEST_A11Y_AUTO_DISMISS_TIME = 1_000;
 
     private UiEventLoggerFake mUiEventLoggerFake = new UiEventLoggerFake();
     private final HeadsUpManagerLogger mLogger = spy(new HeadsUpManagerLogger(logcatLogBuffer()));
@@ -110,143 +100,6 @@
         assertThat(TEST_STICKY_AUTO_DISMISS_TIME).isLessThan(TEST_A11Y_AUTO_DISMISS_TIME);
     }
 
-    private final class TestableHeadsUpManager extends BaseHeadsUpManager {
-
-        private HeadsUpEntry mLastCreatedEntry;
-
-        TestableHeadsUpManager(Context context,
-                HeadsUpManagerLogger logger,
-                DelayableExecutor executor,
-                GlobalSettings globalSettings,
-                SystemClock systemClock,
-                AccessibilityManagerWrapper accessibilityManagerWrapper,
-                UiEventLogger uiEventLogger) {
-            super(context, logger, mockExecutorHandler(executor), globalSettings, systemClock,
-                    executor, accessibilityManagerWrapper, uiEventLogger);
-
-            mTouchAcceptanceDelay = TEST_TOUCH_ACCEPTANCE_TIME;
-            mMinimumDisplayTime = TEST_MINIMUM_DISPLAY_TIME;
-            mAutoDismissTime = TEST_AUTO_DISMISS_TIME;
-            mStickyForSomeTimeAutoDismissTime = TEST_STICKY_AUTO_DISMISS_TIME;
-
-        }
-
-        @Override
-        protected HeadsUpEntry createHeadsUpEntry() {
-            mLastCreatedEntry = spy(super.createHeadsUpEntry());
-            return mLastCreatedEntry;
-        }
-
-        @Override
-        public int getContentFlag() {
-            return FLAG_CONTENT_VIEW_CONTRACTED;
-        }
-
-        // The following are only implemented by HeadsUpManagerPhone. If you need them, use that.
-        @Override
-        public void addHeadsUpPhoneListener(@NonNull OnHeadsUpPhoneListenerChange listener) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void addSwipedOutNotification(@NonNull String key) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void extendHeadsUp() {
-            throw new UnsupportedOperationException();
-        }
-
-        @Nullable
-        @Override
-        public Region getTouchableRegion() {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public boolean isHeadsUpGoingAway() {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void onExpandingFinished() {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public boolean removeNotification(@NonNull String key, boolean releaseImmediately,
-                boolean animate) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void setAnimationStateHandler(@NonNull AnimationStateHandler handler) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void setGutsShown(@NonNull NotificationEntry entry, boolean gutsShown) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void setHeadsUpGoingAway(boolean headsUpGoingAway) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void setRemoteInputActive(@NonNull NotificationEntry entry,
-                boolean remoteInputActive) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void setTrackingHeadsUp(boolean tracking) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public boolean shouldSwallowClick(@NonNull String key) {
-            throw new UnsupportedOperationException();
-        }
-    }
-
-    protected StatusBarNotification createSbn(int id, Notification n) {
-        return new StatusBarNotification(
-                TEST_PACKAGE_NAME /* pkg */,
-                TEST_PACKAGE_NAME,
-                id,
-                null /* tag */,
-                TEST_UID,
-                0 /* initialPid */,
-                n,
-                new UserHandle(ActivityManager.getCurrentUser()),
-                null /* overrideGroupKey */,
-                0 /* postTime */);
-    }
-
-    protected StatusBarNotification createSbn(int id, Notification.Builder n) {
-        return createSbn(id, n.build());
-    }
-
-    protected StatusBarNotification createSbn(int id) {
-        final Notification.Builder b = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .setContentTitle("Title")
-                .setContentText("Text");
-        return createSbn(id, b);
-    }
-
-    protected NotificationEntry createEntry(int id, Notification n) {
-        return new NotificationEntryBuilder().setSbn(createSbn(id, n)).build();
-    }
-
-    protected NotificationEntry createEntry(int id) {
-        return new NotificationEntryBuilder().setSbn(createSbn(id)).build();
-    }
-
-
     private BaseHeadsUpManager createHeadsUpManager() {
         return new TestableHeadsUpManager(mContext, mLogger, mExecutor, mGlobalSettings,
                 mSystemClock, mAccessibilityMgr, mUiEventLoggerFake);
@@ -257,7 +110,7 @@
                 .setSmallIcon(R.drawable.ic_person)
                 .setFullScreenIntent(mock(PendingIntent.class), /* highPriority */ true)
                 .build();
-        return createEntry(id, notif);
+        return HeadsUpManagerTestUtil.createEntry(id, notif);
     }
 
     private NotificationEntry createStickyForSomeTimeEntry(int id) {
@@ -265,7 +118,7 @@
                 .setSmallIcon(R.drawable.ic_person)
                 .setFlag(FLAG_FSI_REQUESTED_BUT_DENIED, true)
                 .build();
-        return createEntry(id, notif);
+        return HeadsUpManagerTestUtil.createEntry(id, notif);
     }
 
     private PendingIntent createFullScreenIntent() {
@@ -279,7 +132,7 @@
                 .setSmallIcon(R.drawable.ic_person)
                 .setFullScreenIntent(createFullScreenIntent(), /* highPriority */ true)
                 .build();
-        return createEntry(id, notif);
+        return HeadsUpManagerTestUtil.createEntry(id, notif);
     }
 
 
@@ -296,7 +149,7 @@
     @Test
     public void testShowNotification_addsEntry() {
         final BaseHeadsUpManager alm = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         alm.showNotification(entry);
 
@@ -308,7 +161,7 @@
     @Test
     public void testShowNotification_autoDismisses() {
         final BaseHeadsUpManager alm = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         alm.showNotification(entry);
         mSystemClock.advanceTime(TEST_AUTO_DISMISS_TIME * 3 / 2);
@@ -319,7 +172,7 @@
     @Test
     public void testRemoveNotification_removeDeferred() {
         final BaseHeadsUpManager alm = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         alm.showNotification(entry);
 
@@ -332,7 +185,7 @@
     @Test
     public void testRemoveNotification_forceRemove() {
         final BaseHeadsUpManager alm = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         alm.showNotification(entry);
 
@@ -346,7 +199,7 @@
     public void testReleaseAllImmediately() {
         final BaseHeadsUpManager alm = createHeadsUpManager();
         for (int i = 0; i < TEST_NUM_NOTIFICATIONS; i++) {
-            final NotificationEntry entry = createEntry(i);
+            final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(i, mContext);
             entry.setRow(mRow);
             alm.showNotification(entry);
         }
@@ -359,7 +212,7 @@
     @Test
     public void testCanRemoveImmediately_notShownLongEnough() {
         final BaseHeadsUpManager alm = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         alm.showNotification(entry);
 
@@ -370,7 +223,8 @@
     @Test
     public void testHunRemovedLogging() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry notifEntry = createEntry(/* id = */ 0);
+        final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0,
+                mContext);
         final BaseHeadsUpManager.HeadsUpEntry headsUpEntry = mock(
                 BaseHeadsUpManager.HeadsUpEntry.class);
         headsUpEntry.mEntry = notifEntry;
@@ -413,7 +267,7 @@
     @Test
     public void testShouldHeadsUpBecomePinned_noFSI_false() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         assertFalse(hum.shouldHeadsUpBecomePinned(entry));
     }
@@ -422,7 +276,7 @@
     @Test
     public void testShowNotification_autoDismissesIncludingTouchAcceptanceDelay() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
         useAccessibilityTimeout(false);
 
         hum.showNotification(entry);
@@ -435,7 +289,7 @@
     @Test
     public void testShowNotification_autoDismissesWithDefaultTimeout() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
         useAccessibilityTimeout(false);
 
         hum.showNotification(entry);
@@ -476,7 +330,7 @@
     @Test
     public void testShowNotification_autoDismissesWithAccessibilityTimeout() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
         useAccessibilityTimeout(true);
 
         hum.showNotification(entry);
@@ -504,7 +358,7 @@
     @Test
     public void testRemoveNotification_beforeMinimumDisplayTime() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
         useAccessibilityTimeout(false);
 
         hum.showNotification(entry);
@@ -523,7 +377,7 @@
     @Test
     public void testRemoveNotification_afterMinimumDisplayTime() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
         useAccessibilityTimeout(false);
 
         hum.showNotification(entry);
@@ -541,7 +395,7 @@
     @Test
     public void testRemoveNotification_releaseImmediately() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         hum.showNotification(entry);
 
@@ -555,7 +409,8 @@
     @Test
     public void testIsSticky_rowPinnedAndExpanded_true() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry notifEntry = createEntry(/* id = */ 0);
+        final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0,
+                mContext);
         when(mRow.isPinned()).thenReturn(true);
         notifEntry.setRow(mRow);
 
@@ -571,7 +426,8 @@
     @Test
     public void testIsSticky_remoteInputActive_true() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry notifEntry = createEntry(/* id = */ 0);
+        final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0,
+                mContext);
 
         hum.showNotification(notifEntry);
 
@@ -607,7 +463,8 @@
     @Test
     public void testIsSticky_false() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry notifEntry = createEntry(/* id = */ 0);
+        final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0,
+                mContext);
 
         hum.showNotification(notifEntry);
 
@@ -653,14 +510,14 @@
 
         final BaseHeadsUpManager.HeadsUpEntry ongoingCall = hum.new HeadsUpEntry();
         ongoingCall.setEntry(new NotificationEntryBuilder()
-                .setSbn(createSbn(/* id = */ 0,
+                .setSbn(HeadsUpManagerTestUtil.createSbn(/* id = */ 0,
                         new Notification.Builder(mContext, "")
                                 .setCategory(Notification.CATEGORY_CALL)
                                 .setOngoing(true)))
                 .build());
 
         final BaseHeadsUpManager.HeadsUpEntry activeRemoteInput = hum.new HeadsUpEntry();
-        activeRemoteInput.setEntry(createEntry(/* id = */ 1));
+        activeRemoteInput.setEntry(HeadsUpManagerTestUtil.createEntry(/* id = */ 1, mContext));
         activeRemoteInput.mRemoteInputActive = true;
 
         assertThat(ongoingCall.compareTo(activeRemoteInput)).isLessThan(0);
@@ -675,14 +532,14 @@
         final Person person = new Person.Builder().setName("person").build();
         final PendingIntent intent = mock(PendingIntent.class);
         incomingCall.setEntry(new NotificationEntryBuilder()
-                .setSbn(createSbn(/* id = */ 0,
+                .setSbn(HeadsUpManagerTestUtil.createSbn(/* id = */ 0,
                         new Notification.Builder(mContext, "")
                                 .setStyle(Notification.CallStyle
                                         .forIncomingCall(person, intent, intent))))
                 .build());
 
         final BaseHeadsUpManager.HeadsUpEntry activeRemoteInput = hum.new HeadsUpEntry();
-        activeRemoteInput.setEntry(createEntry(/* id = */ 1));
+        activeRemoteInput.setEntry(HeadsUpManagerTestUtil.createEntry(/* id = */ 1, mContext));
         activeRemoteInput.mRemoteInputActive = true;
 
         assertThat(incomingCall.compareTo(activeRemoteInput)).isLessThan(0);
@@ -712,7 +569,8 @@
     @Test
     public void testSetUserActionMayIndirectlyRemove() {
         final BaseHeadsUpManager hum = createHeadsUpManager();
-        final NotificationEntry notifEntry = createEntry(/* id = */ 0);
+        final NotificationEntry notifEntry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0,
+                mContext);
 
         hum.showNotification(notifEntry);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java
similarity index 88%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java
index c350de2..ec23f76 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhoneTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerPhoneTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.phone;
+package com.android.systemui.statusbar.policy;
 
 import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer;
 import static com.android.systemui.util.concurrency.MockExecutorHandlerKt.mockExecutorHandler;
@@ -26,10 +26,10 @@
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
-import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
 import androidx.test.filters.SmallTest;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -39,11 +39,9 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider;
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
-import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
-import com.android.systemui.statusbar.policy.BaseHeadsUpManagerTest;
-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.statusbar.phone.ConfigurationControllerImpl;
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 import com.android.systemui.util.kotlin.JavaAdapter;
 import com.android.systemui.util.settings.GlobalSettings;
@@ -61,7 +59,7 @@
 import kotlinx.coroutines.flow.StateFlowKt;
 
 @SmallTest
-@RunWith(AndroidTestingRunner.class)
+@RunWith(AndroidJUnit4.class)
 @TestableLooper.RunWithLooper
 public class HeadsUpManagerPhoneTest extends BaseHeadsUpManagerTest {
     @Rule public MockitoRule rule = MockitoJUnit.rule();
@@ -152,7 +150,7 @@
     @Test
     public void testSnooze() {
         final HeadsUpManager hmp = createHeadsUpManagerPhone();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         hmp.showNotification(entry);
         hmp.snooze();
@@ -163,7 +161,7 @@
     @Test
     public void testSwipedOutNotification() {
         final HeadsUpManager hmp = createHeadsUpManagerPhone();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         hmp.showNotification(entry);
         hmp.addSwipedOutNotification(entry.getKey());
@@ -179,7 +177,7 @@
     @Test
     public void testCanRemoveImmediately_swipedOut() {
         final HeadsUpManager hmp = createHeadsUpManagerPhone();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         hmp.showNotification(entry);
         hmp.addSwipedOutNotification(entry.getKey());
@@ -192,8 +190,10 @@
     @Test
     public void testCanRemoveImmediately_notTopEntry() {
         final HeadsUpManager hmp = createHeadsUpManagerPhone();
-        final NotificationEntry earlierEntry = createEntry(/* id = */ 0);
-        final NotificationEntry laterEntry = createEntry(/* id = */ 1);
+        final NotificationEntry earlierEntry =
+                HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
+        final NotificationEntry laterEntry =
+                HeadsUpManagerTestUtil.createEntry(/* id = */ 1, mContext);
         laterEntry.setRow(mRow);
 
         hmp.showNotification(earlierEntry);
@@ -206,7 +206,7 @@
     @Test
     public void testExtendHeadsUp() {
         final HeadsUpManagerPhone hmp = createHeadsUpManagerPhone();
-        final NotificationEntry entry = createEntry(/* id = */ 0);
+        final NotificationEntry entry = HeadsUpManagerTestUtil.createEntry(/* id = */ 0, mContext);
 
         hmp.showNotification(entry);
         hmp.extendHeadsUp();
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTestUtil.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTestUtil.java
new file mode 100644
index 0000000..c70b03b
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTestUtil.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2024 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.policy;
+import android.app.ActivityManager;
+import android.os.UserHandle;
+
+import android.content.Context;
+import android.service.notification.StatusBarNotification;
+import android.app.Notification;
+
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+
+/**
+ * Test helper class for HeadsUpEntry creation.
+ */
+public class HeadsUpManagerTestUtil {
+
+    private static final String TEST_PACKAGE_NAME = "HeadsUpManagerTestUtil";
+    private static final int TEST_UID = 0;
+
+    protected static StatusBarNotification createSbn(int id, Notification.Builder n) {
+        return createSbn(id, n.build());
+    }
+
+    protected static StatusBarNotification createSbn(int id, Context context) {
+        final Notification.Builder b = new Notification.Builder(context, "")
+                .setSmallIcon(com.android.systemui.res.R.drawable.ic_person)
+                .setContentTitle("Title")
+                .setContentText("Text");
+        return createSbn(id, b);
+    }
+
+    protected static StatusBarNotification createSbn(int id, Notification n) {
+        return new StatusBarNotification(
+                TEST_PACKAGE_NAME /* pkg */,
+                TEST_PACKAGE_NAME,
+                id,
+                null /* tag */,
+                TEST_UID,
+                0 /* initialPid */,
+                n,
+                new UserHandle(ActivityManager.getCurrentUser()),
+                null /* overrideGroupKey */,
+                0 /* postTime */);
+    }
+
+    protected static NotificationEntry createEntry(int id, Notification n) {
+        return new NotificationEntryBuilder().setSbn(createSbn(id, n)).build();
+    }
+
+    protected static NotificationEntry createEntry(int id, Context context) {
+        return new NotificationEntryBuilder().setSbn(
+                HeadsUpManagerTestUtil.createSbn(id, context)).build();
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java
new file mode 100644
index 0000000..2747629
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/TestableHeadsUpManager.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2024 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.policy;
+
+import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED;
+import static com.android.systemui.util.concurrency.MockExecutorHandlerKt.mockExecutorHandler;
+
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import android.graphics.Region;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.android.systemui.util.settings.GlobalSettings;
+import com.android.systemui.util.time.SystemClock;
+
+class TestableHeadsUpManager extends BaseHeadsUpManager {
+
+    private HeadsUpEntry mLastCreatedEntry;
+
+    TestableHeadsUpManager(Context context,
+            HeadsUpManagerLogger logger,
+            DelayableExecutor executor,
+            GlobalSettings globalSettings,
+            SystemClock systemClock,
+            AccessibilityManagerWrapper accessibilityManagerWrapper,
+            UiEventLogger uiEventLogger) {
+        super(context, logger, mockExecutorHandler(executor), globalSettings, systemClock,
+                executor, accessibilityManagerWrapper, uiEventLogger);
+
+        mTouchAcceptanceDelay = BaseHeadsUpManagerTest.TEST_TOUCH_ACCEPTANCE_TIME;
+        mMinimumDisplayTime = BaseHeadsUpManagerTest.TEST_MINIMUM_DISPLAY_TIME;
+        mAutoDismissTime = BaseHeadsUpManagerTest.TEST_AUTO_DISMISS_TIME;
+        mStickyForSomeTimeAutoDismissTime = BaseHeadsUpManagerTest.TEST_STICKY_AUTO_DISMISS_TIME;
+    }
+
+    @Override
+    protected HeadsUpEntry createHeadsUpEntry() {
+        mLastCreatedEntry = spy(super.createHeadsUpEntry());
+        return mLastCreatedEntry;
+    }
+
+    @Override
+    public int getContentFlag() {
+        return FLAG_CONTENT_VIEW_CONTRACTED;
+    }
+
+    // The following are only implemented by HeadsUpManagerPhone. If you need them, use that.
+    @Override
+    public void addHeadsUpPhoneListener(@NonNull OnHeadsUpPhoneListenerChange listener) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void addSwipedOutNotification(@NonNull String key) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void extendHeadsUp() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Nullable
+    @Override
+    public Region getTouchableRegion() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isHeadsUpGoingAway() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void onExpandingFinished() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean removeNotification(@NonNull String key, boolean releaseImmediately,
+            boolean animate) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setAnimationStateHandler(@NonNull AnimationStateHandler handler) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setGutsShown(@NonNull NotificationEntry entry, boolean gutsShown) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setHeadsUpGoingAway(boolean headsUpGoingAway) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setRemoteInputActive(@NonNull NotificationEntry entry,
+            boolean remoteInputActive) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setTrackingHeadsUp(boolean tracking) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean shouldSwallowClick(@NonNull String key) {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/SpatialAudioComponentKosmos.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/SpatialAudioComponentKosmos.kt
new file mode 100644
index 0000000..737b7f3
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/SpatialAudioComponentKosmos.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 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.volume.panel.component.spatial
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.media.spatializerInteractor
+import com.android.systemui.volume.mediaOutputInteractor
+import com.android.systemui.volume.panel.component.spatial.domain.interactor.SpatialAudioComponentInteractor
+
+val Kosmos.spatialAudioComponentInteractor by
+    Kosmos.Fixture {
+        SpatialAudioComponentInteractor(
+            mediaOutputInteractor,
+            spatializerInteractor,
+            testScope.backgroundScope
+        )
+    }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/SpatialAudioAvailabilityCriteriaTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/SpatialAudioAvailabilityCriteriaTest.kt
new file mode 100644
index 0000000..36be90e
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/SpatialAudioAvailabilityCriteriaTest.kt
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2024 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.volume.panel.component.spatial.domain
+
+import android.media.session.MediaSession
+import android.media.session.PlaybackState
+import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.settingslib.media.BluetoothMediaDevice
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.media.spatializerRepository
+import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.volume.localMediaRepository
+import com.android.systemui.volume.mediaController
+import com.android.systemui.volume.mediaControllerRepository
+import com.android.systemui.volume.panel.component.spatial.spatialAudioComponentInteractor
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@RunWithLooper(setAsMainLooper = true)
+class SpatialAudioAvailabilityCriteriaTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos()
+    private val cachedBluetoothDevice: CachedBluetoothDevice = mock {
+        whenever(address).thenReturn("test_address")
+    }
+    private val bluetoothMediaDevice: BluetoothMediaDevice = mock {
+        whenever(cachedDevice).thenReturn(cachedBluetoothDevice)
+    }
+
+    private lateinit var underTest: SpatialAudioAvailabilityCriteria
+
+    @Before
+    fun setup() {
+        with(kosmos) {
+            mediaControllerRepository.setActiveLocalMediaController(
+                mediaController.apply {
+                    whenever(packageName).thenReturn("test.pkg")
+                    whenever(sessionToken).thenReturn(MediaSession.Token(0, mock {}))
+                    whenever(playbackState).thenReturn(PlaybackState.Builder().build())
+                }
+            )
+
+            underTest = SpatialAudioAvailabilityCriteria(spatialAudioComponentInteractor)
+        }
+    }
+
+    @Test
+    fun noSpatialAudio_noHeadTracking_unavailable() {
+        with(kosmos) {
+            testScope.runTest {
+                localMediaRepository.updateCurrentConnectedDevice(bluetoothMediaDevice)
+                spatializerRepository.setIsHeadTrackingAvailable(false)
+                spatializerRepository.defaultSpatialAudioAvailable = false
+
+                val isAvailable by collectLastValue(underTest.isAvailable())
+                runCurrent()
+
+                assertThat(isAvailable).isFalse()
+            }
+        }
+    }
+
+    @Test
+    fun spatialAudio_noHeadTracking_available() {
+        with(kosmos) {
+            testScope.runTest {
+                localMediaRepository.updateCurrentConnectedDevice(bluetoothMediaDevice)
+                spatializerRepository.setIsHeadTrackingAvailable(false)
+                spatializerRepository.defaultSpatialAudioAvailable = true
+
+                val isAvailable by collectLastValue(underTest.isAvailable())
+                runCurrent()
+
+                assertThat(isAvailable).isTrue()
+            }
+        }
+    }
+
+    @Test
+    fun spatialAudio_headTracking_available() {
+        with(kosmos) {
+            testScope.runTest {
+                localMediaRepository.updateCurrentConnectedDevice(bluetoothMediaDevice)
+                spatializerRepository.setIsHeadTrackingAvailable(true)
+                spatializerRepository.defaultSpatialAudioAvailable = true
+
+                val isAvailable by collectLastValue(underTest.isAvailable())
+                runCurrent()
+
+                assertThat(isAvailable).isTrue()
+            }
+        }
+    }
+
+    @Test
+    fun spatialAudio_headTracking_noDevice_unavailable() {
+        with(kosmos) {
+            testScope.runTest {
+                spatializerRepository.setIsHeadTrackingAvailable(true)
+                spatializerRepository.defaultSpatialAudioAvailable = true
+
+                val isAvailable by collectLastValue(underTest.isAvailable())
+                runCurrent()
+
+                assertThat(isAvailable).isFalse()
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractorTest.kt
new file mode 100644
index 0000000..eb6f0b2
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractorTest.kt
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2024 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.volume.panel.component.spatial.domain.interactor
+
+import android.media.AudioDeviceAttributes
+import android.media.AudioDeviceInfo
+import android.media.session.MediaSession
+import android.media.session.PlaybackState
+import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.settingslib.media.BluetoothMediaDevice
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.media.spatializerInteractor
+import com.android.systemui.media.spatializerRepository
+import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.volume.localMediaRepository
+import com.android.systemui.volume.mediaController
+import com.android.systemui.volume.mediaControllerRepository
+import com.android.systemui.volume.mediaOutputInteractor
+import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioEnabledModel
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+class SpatialAudioComponentInteractorTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos()
+    private lateinit var underTest: SpatialAudioComponentInteractor
+
+    @Before
+    fun setup() {
+        with(kosmos) {
+            val cachedBluetoothDevice: CachedBluetoothDevice = mock {
+                whenever(address).thenReturn("test_address")
+            }
+            localMediaRepository.updateCurrentConnectedDevice(
+                mock<BluetoothMediaDevice> {
+                    whenever(name).thenReturn("test_device")
+                    whenever(cachedDevice).thenReturn(cachedBluetoothDevice)
+                }
+            )
+
+            whenever(mediaController.packageName).thenReturn("test.pkg")
+            whenever(mediaController.sessionToken).thenReturn(MediaSession.Token(0, mock {}))
+            whenever(mediaController.playbackState).thenReturn(PlaybackState.Builder().build())
+
+            mediaControllerRepository.setActiveLocalMediaController(mediaController)
+
+            spatializerRepository.setIsSpatialAudioAvailable(
+                AudioDeviceAttributes(
+                    AudioDeviceAttributes.ROLE_OUTPUT,
+                    AudioDeviceInfo.TYPE_BLE_HEADSET,
+                    "test_address"
+                ),
+                true
+            )
+            spatializerRepository.setIsHeadTrackingAvailable(true)
+
+            underTest =
+                SpatialAudioComponentInteractor(
+                    mediaOutputInteractor,
+                    spatializerInteractor,
+                    testScope.backgroundScope,
+                )
+        }
+    }
+
+    @Test
+    fun setEnabled_changesIsEnabled() {
+        with(kosmos) {
+            testScope.runTest {
+                val values by collectValues(underTest.isEnabled)
+
+                underTest.setEnabled(SpatialAudioEnabledModel.Disabled)
+                runCurrent()
+                underTest.setEnabled(SpatialAudioEnabledModel.HeadTrackingEnabled)
+                runCurrent()
+                underTest.setEnabled(SpatialAudioEnabledModel.SpatialAudioEnabled)
+                runCurrent()
+
+                assertThat(values)
+                    .containsExactly(
+                        SpatialAudioEnabledModel.Disabled,
+                        SpatialAudioEnabledModel.HeadTrackingEnabled,
+                        SpatialAudioEnabledModel.SpatialAudioEnabled,
+                    )
+                    .inOrder()
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/res/drawable/bg_shutdown_finder_message.xml b/packages/SystemUI/res/drawable/bg_shutdown_finder_message.xml
new file mode 100644
index 0000000..324ae0c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/bg_shutdown_finder_message.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <corners android:radius="28dp" />
+    <solid android:color="@color/global_actions_lite_button_background" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_call.xml b/packages/SystemUI/res/drawable/ic_call.xml
new file mode 100644
index 0000000..859506a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_call.xml
@@ -0,0 +1,26 @@
+<!--
+  ~ Copyright (C) 2024 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="960"
+    android:viewportHeight="960"
+    android:tint="?attr/colorControlNormal">
+  <path
+      android:fillColor="@android:color/white"
+      android:pathData="M798,840Q673,840 551,785.5Q429,731 329,631Q229,531 174.5,409Q120,287 120,162Q120,144 132,132Q144,120 162,120L324,120Q338,120 349,129.5Q360,139 362,152L388,292Q390,308 387,319Q384,330 376,338L279,436Q299,473 326.5,507.5Q354,542 387,574Q418,605 452,631.5Q486,658 524,680L618,586Q627,577 641.5,572.5Q656,568 670,570L808,598Q822,602 831,612.5Q840,623 840,636L840,798Q840,816 828,828Q816,840 798,840ZM241,360L307,294Q307,294 307,294Q307,294 307,294L290,200Q290,200 290,200Q290,200 290,200L201,200Q201,200 201,200Q201,200 201,200Q206,241 215,281Q224,321 241,360ZM599,718Q638,735 678.5,745Q719,755 760,758Q760,758 760,758Q760,758 760,758L760,670Q760,670 760,670Q760,670 760,670L666,651Q666,651 666,651Q666,651 666,651L599,718ZM241,360Q241,360 241,360Q241,360 241,360Q241,360 241,360Q241,360 241,360L241,360Q241,360 241,360Q241,360 241,360L241,360Q241,360 241,360Q241,360 241,360L241,360ZM599,718L599,718Q599,718 599,718Q599,718 599,718L599,718Q599,718 599,718Q599,718 599,718L599,718Q599,718 599,718Q599,718 599,718Q599,718 599,718Q599,718 599,718Z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_filled_arrow_down.xml b/packages/SystemUI/res/drawable/ic_filled_arrow_down.xml
new file mode 100644
index 0000000..c85965f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_filled_arrow_down.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:viewportWidth="24"
+    android:viewportHeight="24"
+    android:width="24dp"
+    android:height="24dp">
+    <path
+        android:pathData="M7 10l5 5 5 -5z"
+        android:fillColor="#FF000000"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_filled_arrow_up.xml b/packages/SystemUI/res/drawable/ic_filled_arrow_up.xml
new file mode 100644
index 0000000..8ee7e13
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_filled_arrow_up.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2024 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:viewportWidth="24"
+    android:viewportHeight="24"
+    android:width="24dp"
+    android:height="24dp">
+    <path
+        android:pathData="M7 14l5-5 5 5z"
+        android:fillColor="#FF000000"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_finder_active.xml b/packages/SystemUI/res/drawable/ic_finder_active.xml
new file mode 100644
index 0000000..8ca221a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_finder_active.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M12,0L12,0A12,12 0,0 1,24 12L24,12A12,12 0,0 1,12 24L12,24A12,12 0,0 1,0 12L0,12A12,12 0,0 1,12 0z"
+      android:fillColor="#00677D"/>
+  <path
+      android:pathData="M12.797,4.005C11.949,3.936 11.203,4.597 11.203,5.467V6.659C8.855,7.001 6.998,8.856 6.653,11.203H5.467C4.597,11.203 3.936,11.948 4.005,12.796L4.006,12.802L4.006,12.809C4.38,16.605 7.399,19.625 11.195,20C12.051,20.087 12.803,19.404 12.803,18.547V17.355C15.154,17.012 17.013,15.154 17.355,12.803H18.54C19.406,12.803 20.079,12.058 19.992,11.196C19.618,7.4 16.606,4.388 12.812,4.006L12.804,4.006L12.797,4.005ZM11.203,9.344V8.283C9.741,8.591 8.588,9.741 8.278,11.203H9.344C9.585,10.4 10.179,9.754 10.942,9.437C11.027,9.402 11.114,9.371 11.203,9.344ZM11.998,13.171C11.358,13.175 10.828,12.651 10.827,12.004H10.827C10.827,11.959 10.83,11.915 10.835,11.871C10.885,11.427 11.185,11.056 11.59,10.902C11.694,10.863 11.806,10.838 11.921,10.83C11.948,10.833 11.976,10.834 12.003,10.834C12.65,10.834 13.177,11.356 13.179,12.007C13.177,12.622 12.695,13.13 12.091,13.175C12.06,13.172 12.029,13.17 11.998,13.171ZM17.353,11.203H18.383C18.028,8.289 15.72,5.979 12.804,5.616V6.658C15.153,7 17.004,8.852 17.353,11.203ZM14.663,11.203C14.395,10.311 13.692,9.611 12.804,9.344V8.283C14.265,8.59 15.414,9.736 15.727,11.203H14.663ZM5.615,12.803H6.654C7.001,15.15 8.855,17.002 11.203,17.346V18.391C8.287,18.034 5.972,15.719 5.615,12.803ZM11.203,14.666C10.316,14.394 9.613,13.692 9.345,12.803H8.279C8.591,14.264 9.741,15.412 11.203,15.721V14.666ZM14.661,12.811H15.729C15.418,14.272 14.266,15.422 12.804,15.73V14.662C13.689,14.396 14.391,13.699 14.661,12.811Z"
+      android:fillColor="#ffffff"
+      android:fillType="evenOdd"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_music_note_off.xml b/packages/SystemUI/res/drawable/ic_music_note_off.xml
new file mode 100644
index 0000000..d583576
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_music_note_off.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright (C) 2024 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportHeight="960"
+    android:viewportWidth="960">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M792,904L56,168L112,112L848,848L792,904ZM560,446L480,366L480,120L720,120L720,280L560,280L560,446ZM400,840Q334,840 287,793Q240,746 240,680Q240,614 287,567Q334,520 400,520Q423,520 442.5,525.5Q462,531 480,542L480,480L560,560L560,680Q560,746 513,793Q466,840 400,840Z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_volume_off.xml b/packages/SystemUI/res/drawable/ic_volume_off.xml
new file mode 100644
index 0000000..209f684
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_volume_off.xml
@@ -0,0 +1,27 @@
+<!--
+  ~ Copyright (C) 2024 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="960"
+    android:viewportHeight="960"
+    android:tint="?attr/colorControlNormal"
+    android:autoMirrored="true">
+  <path
+      android:fillColor="@android:color/white"
+      android:pathData="M792,904L671,783Q646,799 618,810.5Q590,822 560,829L560,747Q574,742 587.5,737Q601,732 613,725L480,592L480,800L280,600L120,600L120,360L248,360L56,168L112,112L848,848L792,904ZM784,672L726,614Q743,583 751.5,549Q760,515 760,479Q760,385 705,311Q650,237 560,211L560,129Q684,157 762,254.5Q840,352 840,479Q840,532 825.5,581Q811,630 784,672ZM650,538L560,448L560,318Q607,340 633.5,384Q660,428 660,480Q660,495 657.5,509.5Q655,524 650,538ZM480,368L376,264L480,160L480,368ZM400,606L400,512L328,440L328,440L200,440L200,520L314,520L400,606ZM364,476L364,476L364,476L364,476L364,476L364,476L364,476L364,476Z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/shutdown_dialog_finder_active.xml b/packages/SystemUI/res/layout/shutdown_dialog_finder_active.xml
new file mode 100644
index 0000000..b6db7fc
--- /dev/null
+++ b/packages/SystemUI/res/layout/shutdown_dialog_finder_active.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:id="@android:id/text1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="24dp"
+        android:fontFamily="google-sans"
+        android:gravity="center"
+        android:text="@string/shutdown_progress"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textDirection="locale"
+        android:textSize="18sp"
+        android:visibility="gone"
+        app:layout_constraintBottom_toTopOf="@android:id/text2"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:layout_constraintVertical_bias="0.375"
+        app:layout_constraintVertical_chainStyle="packed" />
+
+    <TextView
+        android:id="@android:id/text2"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="24dp"
+        android:fontFamily="google-sans"
+        android:gravity="center"
+        android:text="@string/shutdown_progress"
+        android:textAppearance="?android:attr/textAppearanceLarge"
+        android:textDirection="locale"
+        android:textSize="24sp"
+        app:layout_constraintBottom_toTopOf="@android:id/progress"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@android:id/text1" />
+
+    <ProgressBar
+        android:id="@android:id/progress"
+        style="?android:attr/progressBarStyleLarge"
+        android:layout_width="30dp"
+        android:layout_height="30dp"
+        android:importantForAccessibility="no"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toBottomOf="@android:id/text2" />
+
+    <TextView
+        android:id="@+id/finer_hint"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_margin="32dp"
+        android:background="@drawable/bg_shutdown_finder_message"
+        android:drawablePadding="16dp"
+        android:drawableStart="@drawable/ic_finder_active"
+        android:fontFamily="google-sans"
+        android:gravity="start"
+        android:padding="20dp"
+        android:text="@string/finder_active"
+        android:textAppearance="?android:attr/textAppearanceSmall"
+        android:textColor="@android:color/secondary_text_dark"
+        android:textDirection="locale"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintTop_toBottomOf="@android:id/progress"
+        app:layout_constraintVertical_bias="1" />
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index f1017d8..b438315 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -53,4 +53,7 @@
         <item>bottom_start:home</item>
         <item>bottom_end:create_note</item>
     </string-array>
+
+    <!-- Whether volume panel should use the large screen layout or not -->
+    <bool name="volume_panel_is_large_screen">true</bool>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 65c69f7..beaa708 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -1010,4 +1010,7 @@
 
     <!--  Whether to use a machine learning model for back gesture falsing. -->
     <bool name="config_useBackGestureML">true</bool>
+
+    <!-- Whether volume panel should use the large screen layout or not -->
+    <bool name="volume_panel_is_large_screen">false</bool>
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 5436642..32b1cad 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -898,8 +898,8 @@
     <dimen name="communal_enforced_rounded_corner_max_radius">16dp</dimen>
 
     <!-- Width and height used to filter widgets displayed in the communal widget picker -->
-    <dimen name="communal_widget_picker_desired_width">464dp</dimen>
-    <dimen name="communal_widget_picker_desired_height">307dp</dimen>
+    <dimen name="communal_widget_picker_desired_width">424dp</dimen>
+    <dimen name="communal_widget_picker_desired_height">282dp</dimen>
 
     <!-- The width/height of the unlock icon view on keyguard. -->
     <dimen name="keyguard_lock_height">42dp</dimen>
@@ -1518,6 +1518,12 @@
     <!-- GLANCEABLE_HUB -> LOCKSCREEN transition: Amount to shift lockscreen content on entering -->
     <dimen name="hub_to_lockscreen_transition_lockscreen_translation_x">824dp</dimen>
 
+    <!-- DREAMING -> GLANCEABLE_HUB transition: Amount to shift dream overlay on entering -->
+    <dimen name="dreaming_to_hub_transition_dream_overlay_translation_x">-824dp</dimen>
+
+    <!-- GLANCEABLE_HUB -> DREAMING transition: Amount to shift dream overlay on entering -->
+    <dimen name="hub_to_dreaming_transition_dream_overlay_translation_x">824dp</dimen>
+
     <!-- Distance that the full shade transition takes in order for media to fully transition to
          the shade -->
     <dimen name="lockscreen_shade_media_transition_distance">120dp</dimen>
@@ -1736,12 +1742,18 @@
     <dimen name="communal_grid_height">630dp</dimen>
     <!-- Number of columns for each communal card -->
     <integer name="communal_grid_columns_per_card">6</integer>
-    <!-- Width of area on right edge of screen in which swipes will open the communal hub -->
-    <dimen name="communal_right_edge_swipe_region_width">16dp</dimen>
+
+    <!-- The width of the swipe target to initiate opening or closing communal hub. -->
+    <dimen name="communal_gesture_initiation_width">68dp</dimen>
+
+    <!-- TODO(b/322549765): unify with communal_gesture_initiation_width -->
+    <!-- Width of area on right edge of screen in which swipes will open the communal hub when on
+    the lockscreen -->
+    <dimen name="communal_right_edge_swipe_region_width">40dp</dimen>
     <!-- Height of area at top of communal hub where swipes should open the notification shade -->
-    <dimen name="communal_top_edge_swipe_region_height">32dp</dimen>
+    <dimen name="communal_top_edge_swipe_region_height">68dp</dimen>
     <!-- Height of area at bottom of communal hub where swipes should open the bouncer -->
-    <dimen name="communal_bottom_edge_swipe_region_height">32dp</dimen>
+    <dimen name="communal_bottom_edge_swipe_region_height">68dp</dimen>
 
     <dimen name="drag_and_drop_icon_size">70dp</dimen>
 
@@ -1813,9 +1825,6 @@
     <dimen name="dream_overlay_complication_smartspace_padding">24dp</dimen>
     <dimen name="dream_overlay_complication_smartspace_max_width">408dp</dimen>
 
-    <!-- The width of the swipe target to initiate opening communal hub over dreams. -->
-    <dimen name="communal_gesture_initiation_width">48dp</dimen>
-
     <!-- The position of the end guide, which dream overlay complications can align their start with
          if their end is aligned with the parent end. Represented as the percentage over from the
          start of the parent container. -->
@@ -1861,7 +1870,6 @@
     <dimen name="dream_overlay_y_offset">80dp</dimen>
     <dimen name="dream_overlay_entry_y_offset">40dp</dimen>
     <dimen name="dream_overlay_exit_y_offset">40dp</dimen>
-    <dimen name="dream_overlay_exit_x_offset">824dp</dimen>
 
     <dimen name="status_view_margin_horizontal">0dp</dimen>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 53ad344..ea0e309 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1513,6 +1513,11 @@
     <string name="volume_ringer_status_vibrate">Vibrate</string>
     <string name="volume_ringer_status_silent">Mute</string>
 
+    <!-- Media device casting volume slider label [CHAR_LIMIT=20] -->
+    <string name="media_device_cast">Cast</string>
+    <!-- A message shown when the notification volume changing is disabled because of the muted ring stream [CHAR_LIMIT=40]-->
+    <string name="stream_notification_unavailable">Unavailable because ring is muted</string>
+
     <!-- Shown in the header of quick settings to indicate to the user that their phone ringer is on vibrate. [CHAR_LIMIT=NONE] -->
     <!-- Shown in the header of quick settings to indicate to the user that their phone ringer is on silent (muted). [CHAR_LIMIT=NONE] -->
 
@@ -2231,6 +2236,11 @@
     <!-- Tuner string -->
     <!-- Tuner string -->
 
+    <!-- Message shown during shutdown when Find My Device with Dead Battery Finder is active  [CHAR LIMIT=300] -->
+    <string name="finder_active">You can locate this phone with Find My Device even when powered off</string>
+    <!-- Shutdown Progress Dialog. This is shown if the user chooses to power off the phone. [CHAR LIMIT=60] -->
+    <string name="shutdown_progress">Shutting down\u2026</string>
+
     <!-- Text help link for care instructions for overheating devices [CHAR LIMIT=40] -->
     <string name="thermal_shutdown_dialog_help_text">See care steps</string>
     <!-- URL for care instructions for overheating devices -->
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 10393cf..ca63483 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -196,7 +196,7 @@
             final RecentsAnimationListener animationHandler, final Consumer<Boolean> resultCallback,
             Handler resultCallbackHandler) {
         boolean result = startRecentsActivity(intent, eventTime, animationHandler);
-        if (resultCallback != null) {
+        if (resultCallback != null && resultCallbackHandler != null) {
             resultCallbackHandler.post(new Runnable() {
                 @Override
                 public void run() {
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 8b2a0ec..05e07a7 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -377,7 +377,9 @@
                 if (mode == ZenMode.OFF) SysuiR.string::dnd_is_off.name
                     else SysuiR.string::dnd_is_on.name
             ).also { data ->
-                clock?.run { events.onZenDataChanged(data) }
+                mainExecutor.execute {
+                    clock?.run { events.onZenDataChanged(data) }
+                }
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
index 476497d..10d1891 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputViewController.java
@@ -19,6 +19,7 @@
 import static com.android.systemui.Flags.pinInputFieldStyledFocusState;
 import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
 
+import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
 import android.graphics.drawable.StateListDrawable;
 import android.util.TypedValue;
@@ -150,18 +151,22 @@
     }
 
     private void setKeyboardBasedFocusOutline(boolean isAnyKeyboardConnected) {
-        StateListDrawable background = (StateListDrawable) mPasswordEntry.getBackground();
-        GradientDrawable stateDrawable = (GradientDrawable) background.getStateDrawable(0);
+        Drawable background = mPasswordEntry.getBackground();
+        if (!(background instanceof StateListDrawable)) return;
+        Drawable stateDrawable = ((StateListDrawable) background).getStateDrawable(0);
+        if (!(stateDrawable instanceof GradientDrawable gradientDrawable)) return;
+
         int color = getResources().getColor(R.color.bouncer_password_focus_color);
         if (!isAnyKeyboardConnected) {
-            stateDrawable.setStroke(0, color);
+            gradientDrawable.setStroke(0, color);
         } else {
             int strokeWidthInDP = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 3,
                     getResources().getDisplayMetrics());
-            stateDrawable.setStroke(strokeWidthInDP, color);
+            gradientDrawable.setStroke(strokeWidthInDP, color);
         }
     }
 
+
     @Override
     protected void onViewDetached() {
         super.onViewDetached();
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/Magnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/Magnification.java
index d2fda4c..88fa2de 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/Magnification.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/Magnification.java
@@ -273,6 +273,10 @@
         }
     }
 
+    void onFullscreenMagnificationActivationChanged(int displayId, boolean activated) {
+        // Do nothing
+    }
+
     @MainThread
     void toggleSettingsPanelVisibility(int displayId) {
         final MagnificationSettingsController magnificationSettingsController =
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationConnectionImpl.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationConnectionImpl.java
index ba943b0..b5f3aef 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationConnectionImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationConnectionImpl.java
@@ -47,6 +47,12 @@
     }
 
     @Override
+    public void onFullscreenMagnificationActivationChanged(int displayId, boolean activated) {
+        mHandler.post(() -> mMagnification
+                .onFullscreenMagnificationActivationChanged(displayId, activated));
+    }
+
+    @Override
     public void enableWindowMagnification(int displayId, float scale, float centerX, float centerY,
             float magnificationFrameOffsetRatioX, float magnificationFrameOffsetRatioY,
             IRemoteMagnificationAnimationCallback callback) {
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
index 27f9106fd..6299739 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/MenuView.java
@@ -464,9 +464,6 @@
         Bundle fragmentArgs = new Bundle();
         fragmentArgs.putStringArray("targets", targets.toArray(new String[0]));
         args.putBundle(":settings:show_fragment_args", fragmentArgs);
-        // TODO: b/318748373 - The fragment should set its own title using the targets
-        args.putString(
-                ":settings:show_fragment_title", "Accessibility Shortcut");
         intent.replaceExtras(args);
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
         return intent;
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 74ea58c..d30f33f 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -31,6 +31,7 @@
 import com.android.internal.app.IVoiceInteractionSessionListener;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.assist.domain.interactor.AssistInteractor;
 import com.android.systemui.assist.ui.DefaultUiController;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
@@ -149,6 +150,7 @@
     private final SecureSettings mSecureSettings;
     private final SelectedUserInteractor mSelectedUserInteractor;
     private final ActivityManager mActivityManager;
+    private final AssistInteractor mInteractor;
 
     private final DeviceProvisionedController mDeviceProvisionedController;
 
@@ -192,7 +194,8 @@
             DisplayTracker displayTracker,
             SecureSettings secureSettings,
             SelectedUserInteractor selectedUserInteractor,
-            ActivityManager activityManager) {
+            ActivityManager activityManager,
+            AssistInteractor interactor) {
         mContext = context;
         mDeviceProvisionedController = controller;
         mCommandQueue = commandQueue;
@@ -206,6 +209,7 @@
         mSecureSettings = secureSettings;
         mSelectedUserInteractor = selectedUserInteractor;
         mActivityManager = activityManager;
+        mInteractor = interactor;
 
         registerVoiceInteractionSessionListener();
         registerVisualQueryRecognitionStatusListener();
@@ -314,6 +318,7 @@
                 assistComponent,
                 legacyDeviceState);
         logStartAssistLegacy(legacyInvocationType, legacyDeviceState);
+        mInteractor.onAssistantStarted(legacyInvocationType);
         startAssistInternal(args, assistComponent, isService);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/assist/data/repository/AssistRepository.kt b/packages/SystemUI/src/com/android/systemui/assist/data/repository/AssistRepository.kt
new file mode 100644
index 0000000..c416c24
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/assist/data/repository/AssistRepository.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 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.assist.data.repository
+
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+import kotlinx.coroutines.channels.BufferOverflow
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.SharedFlow
+import kotlinx.coroutines.flow.asSharedFlow
+
+@SysUISingleton
+class AssistRepository @Inject constructor() {
+    private val _latestInvocationType =
+        MutableSharedFlow<Int>(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
+    /** The type of the latest invocation of the assistant. */
+    val latestInvocationType: SharedFlow<Int> = _latestInvocationType.asSharedFlow()
+
+    /** Sets the type of the latest invocation of the assistant. */
+    fun setLatestInvocationType(type: Int) {
+        _latestInvocationType.tryEmit(type)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/assist/domain/interactor/AssistInteractor.kt b/packages/SystemUI/src/com/android/systemui/assist/domain/interactor/AssistInteractor.kt
new file mode 100644
index 0000000..d9e46aa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/assist/domain/interactor/AssistInteractor.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2024 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.assist.domain.interactor
+
+import com.android.systemui.Flags
+import com.android.systemui.assist.data.repository.AssistRepository
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+import kotlinx.coroutines.flow.SharedFlow
+
+@SysUISingleton
+class AssistInteractor
+@Inject
+constructor(
+    private val repository: AssistRepository,
+) {
+    /** The type of the latest invocation of the assistant. */
+    val latestInvocationType: SharedFlow<Int> = repository.latestInvocationType
+
+    /** Notifies that Assistant has been started. */
+    fun onAssistantStarted(type: Int) {
+        if (Flags.enableContextualTips() && Flags.enableContextualTipForPowerOff()) {
+            repository.setLatestInvocationType(type)
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 716209d..2c3ebe9 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -80,6 +80,7 @@
 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Application;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor;
 import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor;
@@ -90,6 +91,7 @@
 import com.android.systemui.log.SessionTracker;
 import com.android.systemui.plugins.FalsingManager;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.power.domain.interactor.PowerInteractor;
 import com.android.systemui.shade.domain.interactor.ShadeInteractor;
 import com.android.systemui.shared.system.SysUiStatsLog;
 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
@@ -116,6 +118,7 @@
 
 import javax.inject.Inject;
 
+import kotlinx.coroutines.CoroutineScope;
 import kotlinx.coroutines.ExperimentalCoroutinesApi;
 
 /**
@@ -173,6 +176,8 @@
             mDefaultUdfpsTouchOverlayViewModel;
     @NonNull private final AlternateBouncerInteractor mAlternateBouncerInteractor;
     @NonNull private final UdfpsOverlayInteractor mUdfpsOverlayInteractor;
+    @NonNull private final PowerInteractor mPowerInteractor;
+    @NonNull private final CoroutineScope mScope;
     @NonNull private final InputManager mInputManager;
     @NonNull private final UdfpsKeyguardAccessibilityDelegate mUdfpsKeyguardAccessibilityDelegate;
     @NonNull private final SelectedUserInteractor mSelectedUserInteractor;
@@ -296,7 +301,9 @@
                         mDeviceEntryUdfpsTouchOverlayViewModel,
                         mDefaultUdfpsTouchOverlayViewModel,
                         mShadeInteractor,
-                        mUdfpsOverlayInteractor
+                        mUdfpsOverlayInteractor,
+                        mPowerInteractor,
+                        mScope
                     )));
         }
 
@@ -678,7 +685,9 @@
             @NonNull KeyguardTransitionInteractor keyguardTransitionInteractor,
             Lazy<DeviceEntryUdfpsTouchOverlayViewModel> deviceEntryUdfpsTouchOverlayViewModel,
             Lazy<DefaultUdfpsTouchOverlayViewModel> defaultUdfpsTouchOverlayViewModel,
-            @NonNull UdfpsOverlayInteractor udfpsOverlayInteractor) {
+            @NonNull UdfpsOverlayInteractor udfpsOverlayInteractor,
+            @NonNull PowerInteractor powerInteractor,
+            @Application CoroutineScope scope) {
         mContext = context;
         mExecution = execution;
         mVibrator = vibrator;
@@ -720,6 +729,8 @@
         mShadeInteractor = shadeInteractor;
         mAlternateBouncerInteractor = alternateBouncerInteractor;
         mUdfpsOverlayInteractor = udfpsOverlayInteractor;
+        mPowerInteractor = powerInteractor;
+        mScope = scope;
         mInputManager = inputManager;
         mUdfpsKeyguardAccessibilityDelegate = udfpsKeyguardAccessibilityDelegate;
         mSelectedUserInteractor = selectedUserInteractor;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
index a209eae..921e395 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
@@ -44,6 +44,7 @@
 import androidx.annotation.LayoutRes
 import androidx.annotation.VisibleForTesting
 import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.Flags.udfpsViewPerformance
 import com.android.systemui.animation.ActivityTransitionAnimator
 import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor
 import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams
@@ -53,10 +54,13 @@
 import com.android.systemui.biometrics.ui.viewmodel.DeviceEntryUdfpsTouchOverlayViewModel
 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
+import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
 import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.power.shared.model.WakefulnessState
 import com.android.systemui.res.R
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.statusbar.LockscreenShadeTransitionController
@@ -67,7 +71,13 @@
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.user.domain.interactor.SelectedUserInteractor
 import dagger.Lazy
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.launch
 
 private const val TAG = "UdfpsControllerOverlay"
 
@@ -82,36 +92,45 @@
 @ExperimentalCoroutinesApi
 @UiThread
 class UdfpsControllerOverlay @JvmOverloads constructor(
-    private val context: Context,
-    private val inflater: LayoutInflater,
-    private val windowManager: WindowManager,
-    private val accessibilityManager: AccessibilityManager,
-    private val statusBarStateController: StatusBarStateController,
-    private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager,
-    private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
-    private val dialogManager: SystemUIDialogManager,
-    private val dumpManager: DumpManager,
-    private val transitionController: LockscreenShadeTransitionController,
-    private val configurationController: ConfigurationController,
-    private val keyguardStateController: KeyguardStateController,
-    private val unlockedScreenOffAnimationController: UnlockedScreenOffAnimationController,
-    private var udfpsDisplayModeProvider: UdfpsDisplayModeProvider,
-    val requestId: Long,
-    @RequestReason val requestReason: Int,
-    private val controllerCallback: IUdfpsOverlayControllerCallback,
-    private val onTouch: (View, MotionEvent, Boolean) -> Boolean,
-    private val activityTransitionAnimator: ActivityTransitionAnimator,
-    private val primaryBouncerInteractor: PrimaryBouncerInteractor,
-    private val alternateBouncerInteractor: AlternateBouncerInteractor,
-    private val isDebuggable: Boolean = Build.IS_DEBUGGABLE,
-    private val udfpsKeyguardAccessibilityDelegate: UdfpsKeyguardAccessibilityDelegate,
-    private val transitionInteractor: KeyguardTransitionInteractor,
-    private val selectedUserInteractor: SelectedUserInteractor,
-    private val deviceEntryUdfpsTouchOverlayViewModel: Lazy<DeviceEntryUdfpsTouchOverlayViewModel>,
-    private val defaultUdfpsTouchOverlayViewModel: Lazy<DefaultUdfpsTouchOverlayViewModel>,
-    private val shadeInteractor: ShadeInteractor,
-    private val udfpsOverlayInteractor: UdfpsOverlayInteractor,
+        private val context: Context,
+        private val inflater: LayoutInflater,
+        private val windowManager: WindowManager,
+        private val accessibilityManager: AccessibilityManager,
+        private val statusBarStateController: StatusBarStateController,
+        private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager,
+        private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+        private val dialogManager: SystemUIDialogManager,
+        private val dumpManager: DumpManager,
+        private val transitionController: LockscreenShadeTransitionController,
+        private val configurationController: ConfigurationController,
+        private val keyguardStateController: KeyguardStateController,
+        private val unlockedScreenOffAnimationController: UnlockedScreenOffAnimationController,
+        private var udfpsDisplayModeProvider: UdfpsDisplayModeProvider,
+        val requestId: Long,
+        @RequestReason val requestReason: Int,
+        private val controllerCallback: IUdfpsOverlayControllerCallback,
+        private val onTouch: (View, MotionEvent, Boolean) -> Boolean,
+        private val activityTransitionAnimator: ActivityTransitionAnimator,
+        private val primaryBouncerInteractor: PrimaryBouncerInteractor,
+        private val alternateBouncerInteractor: AlternateBouncerInteractor,
+        private val isDebuggable: Boolean = Build.IS_DEBUGGABLE,
+        private val udfpsKeyguardAccessibilityDelegate: UdfpsKeyguardAccessibilityDelegate,
+        private val transitionInteractor: KeyguardTransitionInteractor,
+        private val selectedUserInteractor: SelectedUserInteractor,
+        private val deviceEntryUdfpsTouchOverlayViewModel:
+            Lazy<DeviceEntryUdfpsTouchOverlayViewModel>,
+        private val defaultUdfpsTouchOverlayViewModel: Lazy<DefaultUdfpsTouchOverlayViewModel>,
+        private val shadeInteractor: ShadeInteractor,
+        private val udfpsOverlayInteractor: UdfpsOverlayInteractor,
+        private val powerInteractor: PowerInteractor,
+        @Application private val scope: CoroutineScope,
 ) {
+    private val isFinishedGoingToSleep: Flow<Unit> =
+        powerInteractor.detailedWakefulness
+            .filter { it.internalWakefulnessState == WakefulnessState.ASLEEP }
+            .map { } // map to Unit
+    private var listenForAsleepJob: Job? = null
+    private var addViewRunnable: Runnable? = null
     private var overlayViewLegacy: UdfpsView? = null
         private set
     private var overlayTouchView: UdfpsTouchOverlay? = null
@@ -192,7 +211,8 @@
                         if (requestReason.isImportantForAccessibility()) {
                             importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO
                         }
-                        windowManager.addView(this, coreLayoutParams.updateDimensions(null))
+
+                        addViewNowOrLater(this, null)
                         when (requestReason) {
                             REASON_AUTH_KEYGUARD ->
                                 UdfpsTouchOverlayBinder.bind(
@@ -225,7 +245,7 @@
                             importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_NO
                         }
 
-                        windowManager.addView(this, coreLayoutParams.updateDimensions(animation))
+                        addViewNowOrLater(this, animation)
                         sensorRect = sensorBounds
                     }
                 }
@@ -257,6 +277,41 @@
         return false
     }
 
+    private fun addViewNowOrLater(view: View, animation: UdfpsAnimationViewController<*>?) {
+        if (udfpsViewPerformance()) {
+            addViewRunnable = kotlinx.coroutines.Runnable {
+                windowManager.addView(
+                        view,
+                        coreLayoutParams.updateDimensions(animation)
+                )
+            }
+            if (powerInteractor.detailedWakefulness.value.internalWakefulnessState
+                    != WakefulnessState.STARTING_TO_SLEEP) {
+                addViewIfPending()
+            } else {
+                listenForAsleepJob?.cancel()
+                listenForAsleepJob = scope.launch {
+                    isFinishedGoingToSleep.collect {
+                        addViewIfPending()
+                    }
+                }
+            }
+        } else {
+            windowManager.addView(
+                    view,
+                    coreLayoutParams.updateDimensions(animation)
+            )
+        }
+    }
+
+    private fun addViewIfPending() {
+        addViewRunnable?.let {
+            listenForAsleepJob?.cancel()
+            it.run()
+        }
+        addViewRunnable = null
+    }
+
     fun inflateUdfpsAnimation(
         view: UdfpsView,
         controller: UdfpsController
@@ -368,6 +423,7 @@
         overlayViewLegacy = null
         overlayTouchView = null
         overlayTouchListener = null
+        listenForAsleepJob?.cancel()
 
         return wasShowing
     }
@@ -412,7 +468,8 @@
         if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
             if (!shouldRotate(animation)) {
                 Log.v(
-                    TAG, "Skip rotating UDFPS bounds " + Surface.rotationToString(rot) +
+                    TAG,
+                    "Skip rotating UDFPS bounds " + Surface.rotationToString(rot) +
                         " animation=$animation" +
                         " isGoingToSleep=${keyguardUpdateMonitor.isGoingToSleep}" +
                         " isOccluded=${keyguardStateController.isOccluded}"
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FacePropertyRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FacePropertyRepository.kt
index ae1539e..59b59bf 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FacePropertyRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/FacePropertyRepository.kt
@@ -50,6 +50,7 @@
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.flow.stateIn
 import kotlinx.coroutines.withContext
@@ -64,13 +65,16 @@
 
     /** The current face sensor location in current device rotation */
     val sensorLocation: StateFlow<Point?>
+
+    /** The info of current available camera. */
+    val cameraInfo: StateFlow<CameraInfo?>
 }
 
 /** Describes a biometric sensor */
 data class FaceSensorInfo(val id: Int, val strength: SensorStrength)
 
 /** Data class for camera info */
-private data class CameraInfo(
+data class CameraInfo(
     /** The logical id of the camera */
     val cameraId: String,
     /** The physical id of the camera */
@@ -124,7 +128,7 @@
     private val cameraInfoList: List<CameraInfo> = loadCameraInfoList()
     private var currentPhysicalCameraId: String? = null
 
-    private val defaultSensorLocation: StateFlow<Point?> =
+    override val cameraInfo: StateFlow<CameraInfo?> =
         ConflatedCallbackFlow.conflatedCallbackFlow {
                 val callback =
                     object : CameraManager.AvailabilityCallback() {
@@ -142,7 +146,7 @@
                                     physicalCameraId == it.cameraPhysicalId
                                 }
                             trySendWithFailureLogging(
-                                cameraInfo?.cameraLocation,
+                                cameraInfo,
                                 TAG,
                                 "Update face sensor location to $cameraInfo."
                             )
@@ -168,7 +172,7 @@
                                     }
                                 currentPhysicalCameraId = cameraInfo?.cameraPhysicalId
                                 trySendWithFailureLogging(
-                                    cameraInfo?.cameraLocation,
+                                    cameraInfo,
                                     TAG,
                                     "Update face sensor location to $cameraInfo."
                                 )
@@ -181,8 +185,16 @@
             .stateIn(
                 applicationScope,
                 started = SharingStarted.WhileSubscribed(),
-                initialValue =
-                    if (cameraInfoList.isNotEmpty()) cameraInfoList[0].cameraLocation else null
+                initialValue = if (cameraInfoList.isNotEmpty()) cameraInfoList[0] else null
+            )
+
+    private val defaultSensorLocation: StateFlow<Point?> =
+        cameraInfo
+            .map { it?.cameraLocation }
+            .stateIn(
+                applicationScope,
+                started = SharingStarted.WhileSubscribed(),
+                initialValue = null
             )
 
     override val sensorLocation: StateFlow<Point?> =
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
index b0cc3bd..cd5b124 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
@@ -438,9 +438,20 @@
 
                 // Play haptics
                 launch {
-                    viewModel.hapticsToPlay.collect { hapticFeedbackConstant ->
-                        if (hapticFeedbackConstant != HapticFeedbackConstants.NO_HAPTICS) {
-                            vibratorHelper.performHapticFeedback(view, hapticFeedbackConstant)
+                    viewModel.hapticsToPlay.collect { haptics ->
+                        if (haptics.hapticFeedbackConstant != HapticFeedbackConstants.NO_HAPTICS) {
+                            if (haptics.flag != null) {
+                                vibratorHelper.performHapticFeedback(
+                                    view,
+                                    haptics.hapticFeedbackConstant,
+                                    haptics.flag,
+                                )
+                            } else {
+                                vibratorHelper.performHapticFeedback(
+                                    view,
+                                    haptics.hapticFeedbackConstant,
+                                )
+                            }
                             viewModel.clearHaptics()
                         }
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
index 788991d..c933e0e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
@@ -53,6 +53,7 @@
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.first
 import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.update
 import kotlinx.coroutines.launch
 
 /** ViewModel for BiometricPrompt. */
@@ -144,9 +145,10 @@
     private val _forceLargeSize = MutableStateFlow(false)
     private val _forceMediumSize = MutableStateFlow(false)
 
-    private val _hapticsToPlay = MutableStateFlow(HapticFeedbackConstants.NO_HAPTICS)
+    private val _hapticsToPlay =
+        MutableStateFlow(HapticsToPlay(HapticFeedbackConstants.NO_HAPTICS, /* flag= */ null))
 
-    /** Event fired to the view indicating a [HapticFeedbackConstants] to be played */
+    /** Event fired to the view indicating a [HapticsToPlay] */
     val hapticsToPlay = _hapticsToPlay.asStateFlow()
 
     /** The current position of the prompt */
@@ -686,16 +688,26 @@
     }
 
     private fun vibrateOnSuccess() {
-        _hapticsToPlay.value = HapticFeedbackConstants.CONFIRM
+        _hapticsToPlay.value =
+            HapticsToPlay(
+                HapticFeedbackConstants.CONFIRM,
+                HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING,
+            )
     }
 
     private fun vibrateOnError() {
-        _hapticsToPlay.value = HapticFeedbackConstants.REJECT
+        _hapticsToPlay.value =
+            HapticsToPlay(
+                HapticFeedbackConstants.REJECT,
+                HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING,
+            )
     }
 
-    /** Clears the [hapticsToPlay] variable by setting it to the NO_HAPTICS default. */
+    /** Clears the [hapticsToPlay] variable by setting its constant to the NO_HAPTICS default. */
     fun clearHaptics() {
-        _hapticsToPlay.value = HapticFeedbackConstants.NO_HAPTICS
+        _hapticsToPlay.update { previous ->
+            HapticsToPlay(HapticFeedbackConstants.NO_HAPTICS, previous.flag)
+        }
     }
 
     companion object {
@@ -724,3 +736,9 @@
     val isStarted: Boolean
         get() = this == Normal || this == Delayed
 }
+
+/**
+ * The state of haptic feedback to play. It is composed by a [HapticFeedbackConstants] and a
+ * [HapticFeedbackConstants] flag.
+ */
+data class HapticsToPlay(val hapticFeedbackConstant: Int, val flag: Int?)
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogDelegate.java
index 00bbb20..6af0fa0 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/BroadcastDialogDelegate.java
@@ -40,6 +40,7 @@
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.media.MediaOutputConstants;
 import com.android.systemui.broadcast.BroadcastSender;
+import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.media.controls.util.MediaDataUtils;
 import com.android.systemui.media.dialog.MediaOutputDialogFactory;
 import com.android.systemui.res.R;
@@ -74,7 +75,7 @@
     private final SystemUIDialog.Factory mSystemUIDialogFactory;
     private final String mCurrentBroadcastApp;
     private final String mOutputPackageName;
-    private final Executor mExecutor;
+    private final Executor mBgExecutor;
     private boolean mShouldLaunchLeBroadcastDialog;
     private Button mSwitchBroadcast;
 
@@ -159,7 +160,7 @@
             MediaOutputDialogFactory mediaOutputDialogFactory,
             @Nullable LocalBluetoothManager localBluetoothManager,
             UiEventLogger uiEventLogger,
-            Executor executor,
+            @Background Executor bgExecutor,
             BroadcastSender broadcastSender,
             SystemUIDialog.Factory systemUIDialogFactory,
             @Assisted(CURRENT_BROADCAST_APP) String currentBroadcastApp,
@@ -171,7 +172,7 @@
         mCurrentBroadcastApp = currentBroadcastApp;
         mOutputPackageName = outputPkgName;
         mUiEventLogger = uiEventLogger;
-        mExecutor = executor;
+        mBgExecutor = bgExecutor;
         mBroadcastSender = broadcastSender;
 
         if (DEBUG) {
@@ -187,7 +188,7 @@
     @Override
     public void onStart(SystemUIDialog dialog) {
         mDialogs.add(dialog);
-        registerBroadcastCallBack(mExecutor, mBroadcastCallback);
+        registerBroadcastCallBack(mBgExecutor, mBroadcastCallback);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java
index 2af49cf..b269967 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java
@@ -143,7 +143,7 @@
         mTextPreview.getViewTreeObserver().addOnPreDrawListener(() -> {
             int availableHeight = mTextPreview.getHeight()
                     - (mTextPreview.getPaddingTop() + mTextPreview.getPaddingBottom());
-            mTextPreview.setMaxLines(availableHeight / mTextPreview.getLineHeight());
+            mTextPreview.setMaxLines(Math.max(availableHeight / mTextPreview.getLineHeight(), 1));
             return true;
         });
         super.onFinishInflate();
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
index f7ba5a4..8397372 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt
@@ -88,7 +88,6 @@
         val docked = dockManager.isDocked
 
         return when {
-            to == KeyguardState.DREAMING -> CommunalSceneKey.Blank
             docked && to == KeyguardState.LOCKSCREEN && from != KeyguardState.GLANCEABLE_HUB -> {
                 CommunalSceneKey.Communal
             }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
index d0044a4..5d52541 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalInteractor.kt
@@ -29,6 +29,7 @@
 import com.android.systemui.communal.shared.model.CommunalContentSize.HALF
 import com.android.systemui.communal.shared.model.CommunalContentSize.THIRD
 import com.android.systemui.communal.shared.model.CommunalSceneKey
+import com.android.systemui.communal.shared.model.CommunalWidgetContentModel
 import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState
 import com.android.systemui.communal.widgets.CommunalAppWidgetHost
 import com.android.systemui.communal.widgets.EditWidgetsActivityStarter
@@ -45,6 +46,7 @@
 import com.android.systemui.scene.domain.interactor.SceneInteractor
 import com.android.systemui.scene.shared.flag.SceneContainerFlags
 import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.settings.UserTracker
 import com.android.systemui.smartspace.data.repository.SmartspaceRepository
 import com.android.systemui.util.kotlin.BooleanFlowOperators.and
 import com.android.systemui.util.kotlin.BooleanFlowOperators.not
@@ -59,6 +61,7 @@
 import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.emptyFlow
 import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.flow.flowOf
@@ -82,6 +85,7 @@
     communalSettingsInteractor: CommunalSettingsInteractor,
     private val appWidgetHost: CommunalAppWidgetHost,
     private val editWidgetsActivityStarter: EditWidgetsActivityStarter,
+    private val userTracker: UserTracker,
     sceneInteractor: SceneInteractor,
     sceneContainerFlags: SceneContainerFlags,
     @CommunalLog logBuffer: LogBuffer,
@@ -125,8 +129,13 @@
     /**
      * Target scene as requested by the underlying [SceneTransitionLayout] or through
      * [onSceneChanged].
+     *
+     * If [isCommunalAvailable] is false, will return [CommunalSceneKey.Blank]
      */
-    val desiredScene: StateFlow<CommunalSceneKey> = communalRepository.desiredScene
+    val desiredScene: Flow<CommunalSceneKey> =
+        communalRepository.desiredScene.combine(isCommunalAvailable) { scene, available ->
+            if (available) scene else CommunalSceneKey.Blank
+        }
 
     /** Transition state of the hub mode. */
     val transitionState: StateFlow<ObservableCommunalTransitionState> =
@@ -262,10 +271,16 @@
     fun updateWidgetOrder(widgetIdToPriorityMap: Map<Int, Int>) =
         widgetRepository.updateWidgetOrder(widgetIdToPriorityMap)
 
+    /** All widgets present in db. */
+    val communalWidgets: Flow<List<CommunalWidgetContentModel>> =
+        isCommunalAvailable.flatMapLatest { available ->
+            if (!available) emptyFlow() else widgetRepository.communalWidgets
+        }
+
     /** A list of widget content to be displayed in the communal hub. */
     val widgetContent: Flow<List<CommunalContentModel.Widget>> =
         widgetRepository.communalWidgets.map { widgets ->
-            widgets.map Widget@{ widget ->
+            filterWidgetsByExistingUsers(widgets).map Widget@{ widget ->
                 return@Widget CommunalContentModel.Widget(
                     appWidgetId = widget.appWidgetId,
                     providerInfo = widget.providerInfo,
@@ -345,6 +360,19 @@
             return@combine ongoingContent
         }
 
+    /**
+     * Filter and retain widgets associated with an existing user, safeguarding against displaying
+     * stale data following user deletion.
+     */
+    private fun filterWidgetsByExistingUsers(
+        list: List<CommunalWidgetContentModel>,
+    ): List<CommunalWidgetContentModel> {
+        val currentUserIds = userTracker.userProfiles.map { it.id }.toSet()
+        return list.filter { widget ->
+            currentUserIds.contains(widget.providerInfo.profile?.identifier)
+        }
+    }
+
     companion object {
         /**
          * The user activity timeout which should be used when the communal hub is opened. A value
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
index 8a7b5eb..3ec9a26 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
@@ -34,7 +34,7 @@
     private val communalInteractor: CommunalInteractor,
     val mediaHost: MediaHost,
 ) {
-    val currentScene: StateFlow<CommunalSceneKey> = communalInteractor.desiredScene
+    val currentScene: Flow<CommunalSceneKey> = communalInteractor.desiredScene
 
     /** Whether widgets are currently being re-ordered. */
     open val reorderingWidgets: StateFlow<Boolean> = MutableStateFlow(false)
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartable.kt
index 4ddd768..8390d62 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalAppWidgetHostStartable.kt
@@ -18,11 +18,14 @@
 
 import com.android.systemui.CoreStartable
 import com.android.systemui.communal.domain.interactor.CommunalInteractor
+import com.android.systemui.communal.shared.model.CommunalWidgetContentModel
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.settings.UserTracker
 import com.android.systemui.util.kotlin.BooleanFlowOperators.or
 import com.android.systemui.util.kotlin.pairwise
+import com.android.systemui.util.kotlin.sample
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
@@ -37,6 +40,7 @@
 constructor(
     private val appWidgetHost: CommunalAppWidgetHost,
     private val communalInteractor: CommunalInteractor,
+    private val userTracker: UserTracker,
     @Background private val bgScope: CoroutineScope,
     @Main private val uiDispatcher: CoroutineDispatcher
 ) : CoreStartable {
@@ -47,6 +51,14 @@
             .pairwise(false)
             .filter { (previous, new) -> previous != new }
             .onEach { (_, shouldListen) -> updateAppWidgetHostActive(shouldListen) }
+            .sample(communalInteractor.communalWidgets, ::Pair)
+            .onEach { (withPrev, widgets) ->
+                val (_, isActive) = withPrev
+                // The validation is performed once the hub becomes active.
+                if (isActive) {
+                    validateWidgetsAndDeleteOrphaned(widgets)
+                }
+            }
             .launchIn(bgScope)
 
         appWidgetHost.appWidgetIdToRemove
@@ -63,4 +75,15 @@
                 appWidgetHost.stopListening()
             }
         }
+
+    /**
+     * Ensure the existence of all associated users for widgets, and remove widgets belonging to
+     * users who have been deleted.
+     */
+    private fun validateWidgetsAndDeleteOrphaned(widgets: List<CommunalWidgetContentModel>) {
+        val currentUserIds = userTracker.userProfiles.map { it.id }.toSet()
+        widgets
+            .filter { widget -> !currentUserIds.contains(widget.providerInfo.profile?.identifier) }
+            .onEach { widget -> communalInteractor.deleteWidget(id = widget.appWidgetId) }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetHost.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetHost.kt
index 080dbed..93e2b37 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetHost.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/CommunalWidgetHost.kt
@@ -21,6 +21,7 @@
 import android.appwidget.AppWidgetProviderInfo.WIDGET_FEATURE_CONFIGURATION_OPTIONAL
 import android.appwidget.AppWidgetProviderInfo.WIDGET_FEATURE_RECONFIGURABLE
 import android.content.ComponentName
+import android.os.Bundle
 import android.os.UserHandle
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.core.Logger
@@ -56,6 +57,7 @@
             return widgetInfo.configure != null && !configurationOptional
         }
     }
+
     private val logger = Logger(logBuffer, TAG)
 
     /**
@@ -84,9 +86,16 @@
 
     private fun bindWidget(widgetId: Int, user: UserHandle, provider: ComponentName): Boolean {
         if (appWidgetManager.isPresent) {
+            val options =
+                Bundle().apply {
+                    putInt(
+                        AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
+                        AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD,
+                    )
+                }
             return appWidgetManager
                 .get()
-                .bindAppWidgetIdIfAllowed(widgetId, user, provider, /* options */ null)
+                .bindAppWidgetIdIfAllowed(widgetId, user, provider, options)
         }
         return false
     }
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
index 0f038e1..bc07b95 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
@@ -36,6 +36,7 @@
 import com.android.systemui.controls.ControlsMetricsLogger
 import com.android.systemui.controls.settings.ControlsSettingsRepository
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.statusbar.VibratorHelper
@@ -47,16 +48,16 @@
 
 @SysUISingleton
 class ControlActionCoordinatorImpl @Inject constructor(
-        private val context: Context,
-        private val bgExecutor: DelayableExecutor,
-        @Main private val uiExecutor: DelayableExecutor,
-        private val activityStarter: ActivityStarter,
-        private val broadcastSender: BroadcastSender,
-        private val keyguardStateController: KeyguardStateController,
-        private val taskViewFactory: Optional<TaskViewFactory>,
-        private val controlsMetricsLogger: ControlsMetricsLogger,
-        private val vibrator: VibratorHelper,
-        private val controlsSettingsRepository: ControlsSettingsRepository,
+    private val context: Context,
+    @Background private val bgExecutor: DelayableExecutor,
+    @Main private val uiExecutor: DelayableExecutor,
+    private val activityStarter: ActivityStarter,
+    private val broadcastSender: BroadcastSender,
+    private val keyguardStateController: KeyguardStateController,
+    private val taskViewFactory: Optional<TaskViewFactory>,
+    private val controlsMetricsLogger: ControlsMetricsLogger,
+    private val vibrator: VibratorHelper,
+    private val controlsSettingsRepository: ControlsSettingsRepository,
 ) : ControlActionCoordinator {
     private var dialog: Dialog? = null
     private var pendingAction: Action? = null
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index 6d9994f..ce24259 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -71,6 +71,7 @@
 import android.media.projection.IMediaProjectionManager;
 import android.media.projection.MediaProjectionManager;
 import android.media.session.MediaSessionManager;
+import android.nearby.NearbyManager;
 import android.net.ConnectivityManager;
 import android.net.NetworkScoreManager;
 import android.net.wifi.WifiManager;
@@ -441,6 +442,12 @@
 
     @Provides
     @Singleton
+    static NearbyManager provideNearbyManager(Context context) {
+        return context.getSystemService(NearbyManager.class);
+    }
+
+    @Provides
+    @Singleton
     static NetworkScoreManager provideNetworkScoreManager(Context context) {
         return context.getSystemService(NetworkScoreManager.class);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java
index a90980f..a431a59 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSysUIComponent.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.dagger;
 
-import com.android.systemui.globalactions.ShutdownUiModule;
 import com.android.systemui.keyguard.CustomizationProvider;
 import com.android.systemui.statusbar.NotificationInsetsModule;
 import com.android.systemui.statusbar.QsFrameTranslateModule;
@@ -32,7 +31,6 @@
         DependencyProvider.class,
         NotificationInsetsModule.class,
         QsFrameTranslateModule.class,
-        ShutdownUiModule.class,
         SystemUIBinder.class,
         SystemUIModule.class,
         SystemUICoreStartableModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index e893177..1157d97 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -126,6 +126,7 @@
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.PolicyModule;
+import com.android.systemui.statusbar.policy.SensitiveNotificationProtectionController;
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.statusbar.policy.dagger.SmartRepliesInflationModule;
 import com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule;
@@ -358,6 +359,7 @@
             VisualInterruptionDecisionProvider visualInterruptionDecisionProvider,
             ZenModeController zenModeController,
             NotificationLockscreenUserManager notifUserManager,
+            SensitiveNotificationProtectionController sensitiveNotificationProtectionController,
             CommonNotifCollection notifCollection,
             NotifPipeline notifPipeline,
             SysUiState sysUiState,
@@ -376,6 +378,7 @@
                 visualInterruptionDecisionProvider,
                 zenModeController,
                 notifUserManager,
+                sensitiveNotificationProtectionController,
                 notifCollection,
                 notifPipeline,
                 sysUiState,
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt
index cf91e14..0c9fbc2 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/SystemUIDeviceEntryFaceAuthInteractor.kt
@@ -189,6 +189,18 @@
                 }
             }
             .launchIn(applicationScope)
+
+        facePropertyRepository.cameraInfo
+            .onEach {
+                if (it != null && isRunning()) {
+                    repository.cancel()
+                    runFaceAuth(
+                        FaceAuthUiEvent.FACE_AUTH_CAMERA_AVAILABLE_CHANGED,
+                        fallbackToDetect = true
+                    )
+                }
+            }
+            .launchIn(applicationScope)
     }
 
     private suspend fun resetLockedOutState(currentUserId: Int) {
diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/shared/FaceAuthReason.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/shared/FaceAuthReason.kt
index ee220d5..08a6166 100644
--- a/packages/SystemUI/src/com/android/systemui/deviceentry/shared/FaceAuthReason.kt
+++ b/packages/SystemUI/src/com/android/systemui/deviceentry/shared/FaceAuthReason.kt
@@ -31,6 +31,7 @@
 import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.ASSISTANT_VISIBILITY_CHANGED
 import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.AUTH_REQUEST_DURING_CANCELLATION
 import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.BIOMETRIC_ENABLED
+import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.CAMERA_AVAILABLE_CHANGED
 import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.CAMERA_LAUNCHED
 import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.DEVICE_WOKEN_UP_ON_REACH_GESTURE
 import com.android.systemui.deviceentry.shared.InternalFaceAuthReasons.DISPLAY_OFF
@@ -130,6 +131,7 @@
         "Face auth stopped because non strong biometric allowed changed"
     const val POSTURE_CHANGED = "Face auth started/stopped due to device posture changed."
     const val DISPLAY_OFF = "Face auth stopped due to display state OFF."
+    const val CAMERA_AVAILABLE_CHANGED = "Face auth started due to the available camera changed"
 }
 
 /**
@@ -221,7 +223,9 @@
     @UiEvent(doc = NON_STRONG_BIOMETRIC_ALLOWED_CHANGED)
     FACE_AUTH_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED(1256, NON_STRONG_BIOMETRIC_ALLOWED_CHANGED),
     @UiEvent(doc = ACCESSIBILITY_ACTION) FACE_AUTH_ACCESSIBILITY_ACTION(1454, ACCESSIBILITY_ACTION),
-    @UiEvent(doc = DISPLAY_OFF) FACE_AUTH_DISPLAY_OFF(1461, DISPLAY_OFF);
+    @UiEvent(doc = DISPLAY_OFF) FACE_AUTH_DISPLAY_OFF(1461, DISPLAY_OFF),
+    @UiEvent(doc = CAMERA_AVAILABLE_CHANGED)
+    FACE_AUTH_CAMERA_AVAILABLE_CHANGED(1623, CAMERA_AVAILABLE_CHANGED);
 
     override fun getId(): Int = this.id
 
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
index 9000da3..b97bace 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayAnimationsController.kt
@@ -40,7 +40,6 @@
 import com.android.systemui.log.dagger.DreamLog
 import com.android.systemui.statusbar.BlurUtils
 import com.android.systemui.statusbar.CrossFadeHelper
-import com.android.systemui.statusbar.policy.ConfigurationController
 import javax.inject.Inject
 import javax.inject.Named
 import kotlinx.coroutines.launch
@@ -55,7 +54,6 @@
     private val mOverlayStateController: DreamOverlayStateController,
     @Named(DreamOverlayModule.DREAM_BLUR_RADIUS) private val mDreamBlurRadius: Int,
     private val dreamOverlayViewModel: DreamOverlayViewModel,
-    private val configController: ConfigurationController,
     @Named(DreamOverlayModule.DREAM_IN_BLUR_ANIMATION_DURATION)
     private val mDreamInBlurAnimDurationMs: Long,
     @Named(DreamOverlayModule.DREAM_IN_COMPLICATIONS_ANIMATION_DURATION)
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamOverlayViewModel.kt b/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamOverlayViewModel.kt
index dd67a4c..bd99f4b 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamOverlayViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamOverlayViewModel.kt
@@ -20,6 +20,7 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.ui.viewmodel.DreamingToGlanceableHubTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToDreamingTransitionViewModel
 import com.android.systemui.res.R
 import javax.inject.Inject
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -33,16 +34,16 @@
 @Inject
 constructor(
     configurationInteractor: ConfigurationInteractor,
-    private val toGlanceableHubTransitionViewModel: DreamingToGlanceableHubTransitionViewModel,
+    toGlanceableHubTransitionViewModel: DreamingToGlanceableHubTransitionViewModel,
+    fromGlanceableHubTransitionInteractor: GlanceableHubToDreamingTransitionViewModel,
     private val toLockscreenTransitionViewModel: DreamingToLockscreenTransitionViewModel,
 ) {
 
     val dreamOverlayTranslationX: Flow<Float> =
-        configurationInteractor
-            .dimensionPixelSize(R.dimen.dream_overlay_exit_x_offset)
-            .flatMapLatest { px: Int ->
-                toGlanceableHubTransitionViewModel.dreamOverlayTranslationX(px)
-            }
+        merge(
+            toGlanceableHubTransitionViewModel.dreamOverlayTranslationX,
+            fromGlanceableHubTransitionInteractor.dreamOverlayTranslationX,
+        )
 
     val dreamOverlayTranslationY: Flow<Float> =
         configurationInteractor
@@ -55,6 +56,7 @@
         merge(
             toLockscreenTransitionViewModel.dreamOverlayAlpha,
             toGlanceableHubTransitionViewModel.dreamOverlayAlpha,
+            fromGlanceableHubTransitionInteractor.dreamOverlayAlpha,
         )
 
     val transitionEnded = toLockscreenTransitionViewModel.transitionEnded
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/ShutdownUi.java b/packages/SystemUI/src/com/android/systemui/globalactions/ShutdownUi.java
index 51978ec..ccd69ca 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/ShutdownUi.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/ShutdownUi.java
@@ -22,7 +22,10 @@
 import android.annotation.StringRes;
 import android.app.Dialog;
 import android.content.Context;
+import android.nearby.NearbyManager;
+import android.net.platform.flags.Flags;
 import android.os.PowerManager;
+import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
@@ -38,6 +41,8 @@
 import com.android.systemui.statusbar.BlurUtils;
 import com.android.systemui.statusbar.phone.ScrimController;
 
+import javax.inject.Inject;
+
 /**
  * Provides the UI shown during system shutdown.
  */
@@ -45,9 +50,13 @@
 
     private Context mContext;
     private BlurUtils mBlurUtils;
-    public ShutdownUi(Context context, BlurUtils blurUtils) {
+    private NearbyManager mNearbyManager;
+
+    @Inject
+    public ShutdownUi(Context context, BlurUtils blurUtils, NearbyManager nearbyManager) {
         mContext = context;
         mBlurUtils = blurUtils;
+        mNearbyManager = nearbyManager;
     }
 
     /**
@@ -132,12 +141,28 @@
     /**
      * Returns the layout resource to use for UI while shutting down.
      * @param isReboot Whether this is a reboot or a shutdown.
-     * @return
      */
-    public int getShutdownDialogContent(boolean isReboot) {
-        return R.layout.shutdown_dialog;
+    @VisibleForTesting int getShutdownDialogContent(boolean isReboot) {
+        if (!Flags.poweredOffFindingPlatform()) {
+            return R.layout.shutdown_dialog;
+        }
+        int finderActive = mNearbyManager.getPoweredOffFindingMode();
+        if (finderActive == NearbyManager.POWERED_OFF_FINDING_MODE_DISABLED
+                || finderActive == NearbyManager.POWERED_OFF_FINDING_MODE_UNSUPPORTED) {
+            // inactive or unsupported, use regular shutdown dialog
+            return R.layout.shutdown_dialog;
+        } else if (finderActive == NearbyManager.POWERED_OFF_FINDING_MODE_ENABLED) {
+            // active, use dialog with finder info if shutting down
+            return isReboot ? R.layout.shutdown_dialog :
+                    com.android.systemui.res.R.layout.shutdown_dialog_finder_active;
+        } else {
+            // that's weird? default to regular dialog
+            Log.w("ShutdownUi", "Unexpected value for finder active: " + finderActive);
+            return R.layout.shutdown_dialog;
+        }
     }
 
+
     @StringRes
     @VisibleForTesting int getRebootMessage(boolean isReboot, @Nullable String reason) {
         if (reason != null && reason.startsWith(PowerManager.REBOOT_RECOVERY_UPDATE)) {
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/ShutdownUiModule.kt b/packages/SystemUI/src/com/android/systemui/globalactions/ShutdownUiModule.kt
deleted file mode 100644
index b7285da..0000000
--- a/packages/SystemUI/src/com/android/systemui/globalactions/ShutdownUiModule.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.systemui.globalactions
-
-import android.content.Context
-import com.android.systemui.statusbar.BlurUtils
-import dagger.Module
-import dagger.Provides
-
-/** Provides the UI shown during system shutdown. */
-@Module
-class ShutdownUiModule {
-    /** Shutdown UI provider. */
-    @Provides
-    fun provideShutdownUi(context: Context?, blurUtils: BlurUtils?): ShutdownUi {
-        return ShutdownUi(context, blurUtils)
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index c6b9952..6d917bb 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -40,6 +40,7 @@
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE;
 import static com.android.systemui.DejankUtils.whitelistIpcs;
+import static com.android.systemui.Flags.notifyPowerManagerUserActivityBackground;
 import static com.android.systemui.Flags.refactorGetCurrentUser;
 import static com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel.DREAMING_ANIMATION_DURATION_MS;
 import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow;
@@ -1488,7 +1489,11 @@
     }
 
     public void userActivity() {
-        mPM.userActivity(mSystemClock.uptimeMillis(), false);
+        if (notifyPowerManagerUserActivityBackground()) {
+            mUiBgExecutor.execute(() -> mPM.userActivity(mSystemClock.uptimeMillis(), false));
+        } else {
+            mPM.userActivity(mSystemClock.uptimeMillis(), false);
+        }
     }
 
     private void setupLocked() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt
index b152eea..2bede977 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/DeviceEntryFingerprintAuthRepository.kt
@@ -40,6 +40,7 @@
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.buffer
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.flowOn
 import kotlinx.coroutines.flow.shareIn
@@ -177,92 +178,99 @@
 
     // TODO(b/322555228) Remove after consolidating device entry auth messages with BP auth messages
     //  in BiometricStatusRepository
+    /**
+     * FingerprintAuthenticationStatus Multiple statuses may arrive in immediate sequence (ie:
+     * acquired, failed, help, error), so we use a buffer to ensure consumers receive each distinct
+     * status.
+     */
     override val authenticationStatus: Flow<FingerprintAuthenticationStatus>
-        get() = conflatedCallbackFlow {
-            val callback =
-                object : KeyguardUpdateMonitorCallback() {
-                    override fun onBiometricAuthenticated(
-                        userId: Int,
-                        biometricSourceType: BiometricSourceType,
-                        isStrongBiometric: Boolean,
-                    ) {
-                        sendUpdateIfFingerprint(
-                            biometricSourceType,
-                            SuccessFingerprintAuthenticationStatus(
-                                userId,
-                                isStrongBiometric,
-                            ),
-                        )
-                    }
+        get() =
+            conflatedCallbackFlow {
+                    val callback =
+                        object : KeyguardUpdateMonitorCallback() {
+                            override fun onBiometricAuthenticated(
+                                userId: Int,
+                                biometricSourceType: BiometricSourceType,
+                                isStrongBiometric: Boolean,
+                            ) {
+                                sendUpdateIfFingerprint(
+                                    biometricSourceType,
+                                    SuccessFingerprintAuthenticationStatus(
+                                        userId,
+                                        isStrongBiometric,
+                                    ),
+                                )
+                            }
 
-                    override fun onBiometricError(
-                        msgId: Int,
-                        errString: String?,
-                        biometricSourceType: BiometricSourceType,
-                    ) {
-                        sendUpdateIfFingerprint(
-                            biometricSourceType,
-                            ErrorFingerprintAuthenticationStatus(
-                                msgId,
-                                errString,
-                            ),
-                        )
-                    }
+                            override fun onBiometricError(
+                                msgId: Int,
+                                errString: String?,
+                                biometricSourceType: BiometricSourceType,
+                            ) {
+                                sendUpdateIfFingerprint(
+                                    biometricSourceType,
+                                    ErrorFingerprintAuthenticationStatus(
+                                        msgId,
+                                        errString,
+                                    ),
+                                )
+                            }
 
-                    override fun onBiometricHelp(
-                        msgId: Int,
-                        helpString: String?,
-                        biometricSourceType: BiometricSourceType,
-                    ) {
-                        sendUpdateIfFingerprint(
-                            biometricSourceType,
-                            HelpFingerprintAuthenticationStatus(
-                                msgId,
-                                helpString,
-                            ),
-                        )
-                    }
+                            override fun onBiometricHelp(
+                                msgId: Int,
+                                helpString: String?,
+                                biometricSourceType: BiometricSourceType,
+                            ) {
+                                sendUpdateIfFingerprint(
+                                    biometricSourceType,
+                                    HelpFingerprintAuthenticationStatus(
+                                        msgId,
+                                        helpString,
+                                    ),
+                                )
+                            }
 
-                    override fun onBiometricAuthFailed(
-                        biometricSourceType: BiometricSourceType,
-                    ) {
-                        sendUpdateIfFingerprint(
-                            biometricSourceType,
-                            FailFingerprintAuthenticationStatus,
-                        )
-                    }
+                            override fun onBiometricAuthFailed(
+                                biometricSourceType: BiometricSourceType,
+                            ) {
+                                sendUpdateIfFingerprint(
+                                    biometricSourceType,
+                                    FailFingerprintAuthenticationStatus,
+                                )
+                            }
 
-                    override fun onBiometricAcquired(
-                        biometricSourceType: BiometricSourceType,
-                        acquireInfo: Int,
-                    ) {
-                        sendUpdateIfFingerprint(
-                            biometricSourceType,
-                            AcquiredFingerprintAuthenticationStatus(
-                                AuthenticationReason.DeviceEntryAuthentication,
-                                acquireInfo
-                            ),
-                        )
-                    }
+                            override fun onBiometricAcquired(
+                                biometricSourceType: BiometricSourceType,
+                                acquireInfo: Int,
+                            ) {
+                                sendUpdateIfFingerprint(
+                                    biometricSourceType,
+                                    AcquiredFingerprintAuthenticationStatus(
+                                        AuthenticationReason.DeviceEntryAuthentication,
+                                        acquireInfo
+                                    ),
+                                )
+                            }
 
-                    private fun sendUpdateIfFingerprint(
-                        biometricSourceType: BiometricSourceType,
-                        authenticationStatus: FingerprintAuthenticationStatus
-                    ) {
-                        if (biometricSourceType != BiometricSourceType.FINGERPRINT) {
-                            return
+                            private fun sendUpdateIfFingerprint(
+                                biometricSourceType: BiometricSourceType,
+                                authenticationStatus: FingerprintAuthenticationStatus
+                            ) {
+                                if (biometricSourceType != BiometricSourceType.FINGERPRINT) {
+                                    return
+                                }
+
+                                trySendWithFailureLogging(
+                                    authenticationStatus,
+                                    TAG,
+                                    "new fingerprint authentication status"
+                                )
+                            }
                         }
-
-                        trySendWithFailureLogging(
-                            authenticationStatus,
-                            TAG,
-                            "new fingerprint authentication status"
-                        )
-                    }
+                    keyguardUpdateMonitor.registerCallback(callback)
+                    awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
                 }
-            keyguardUpdateMonitor.registerCallback(callback)
-            awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
-        }
+                .buffer(capacity = 4)
 
     override val shouldUpdateIndicatorVisibility: Flow<Boolean> =
         conflatedCallbackFlow {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
index 59288a1..0ea5390 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt
@@ -41,7 +41,6 @@
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.flow.callbackFlow
-import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.mapNotNull
 import kotlinx.coroutines.flow.onStart
@@ -111,7 +110,6 @@
                 awaitClose { clockRegistry.unregisterClockChangeListener(listener) }
             }
             .mapNotNull { it }
-            .distinctUntilChanged()
 
     override val currentClock: StateFlow<ClockController?> =
         currentClockId
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
index 0cf74a1..9fc3692 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
@@ -156,5 +156,6 @@
         val TO_GONE_DURATION = 500.milliseconds
         val TO_AOD_DURATION = TRANSITION_DURATION_MS
         val TO_PRIMARY_BOUNCER_DURATION = TRANSITION_DURATION_MS
+        val TO_DOZING_DURATION = TRANSITION_DURATION_MS
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
index e2a8b6c..54d5908 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
@@ -115,5 +115,7 @@
         const val TAG = "FromDozingTransitionInteractor"
         private val DEFAULT_DURATION = 500.milliseconds
         val TO_LOCKSCREEN_DURATION = DEFAULT_DURATION
+        val TO_GONE_DURATION = DEFAULT_DURATION
+        val TO_PRIMARY_BOUNCER_DURATION = DEFAULT_DURATION
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
index c6594ef..acfa107 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
@@ -18,6 +18,7 @@
 
 import android.animation.ValueAnimator
 import com.android.app.animation.Interpolators
+import com.android.app.tracing.coroutines.launch
 import com.android.systemui.Flags.communalHub
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
@@ -64,12 +65,13 @@
 
     private fun listenForDreamingToGlanceableHub() {
         if (!communalHub()) return
-        glanceableHubTransitions.listenForGlanceableHubTransition(
-            transitionName = "listenForDreamingToGlanceableHub",
-            transitionOwnerName = TAG,
-            fromState = KeyguardState.DREAMING,
-            toState = KeyguardState.GLANCEABLE_HUB,
-        )
+        scope.launch("$TAG#listenForDreamingToGlanceableHub", mainDispatcher) {
+            glanceableHubTransitions.listenForGlanceableHubTransition(
+                transitionOwnerName = TAG,
+                fromState = KeyguardState.DREAMING,
+                toState = KeyguardState.GLANCEABLE_HUB,
+            )
+        }
     }
 
     fun startToLockscreenTransition() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
index fbf195e..786c3c6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
@@ -27,13 +27,16 @@
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
 import com.android.systemui.power.domain.interactor.PowerInteractor
-import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleMultiple
+import com.android.systemui.util.kotlin.BooleanFlowOperators.and
+import com.android.systemui.util.kotlin.BooleanFlowOperators.not
 import com.android.systemui.util.kotlin.sample
 import javax.inject.Inject
 import kotlin.time.Duration.Companion.seconds
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.collectLatest
 import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
 
 @SysUISingleton
 class FromGlanceableHubTransitionInteractor
@@ -58,13 +61,12 @@
         if (!Flags.communalHub()) {
             return
         }
-        listenForHubToLockscreen()
+        listenForHubToLockscreenOrDreaming()
         listenForHubToDozing()
         listenForHubToPrimaryBouncer()
         listenForHubToAlternateBouncer()
         listenForHubToOccluded()
         listenForHubToGone()
-        listenForHubToDreaming()
     }
 
     override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
@@ -82,13 +84,24 @@
      * Listens for the glanceable hub transition to lock screen and directly drives the keyguard
      * transition.
      */
-    private fun listenForHubToLockscreen() {
-        glanceableHubTransitions.listenForGlanceableHubTransition(
-            transitionName = "listenForHubToLockscreen",
-            transitionOwnerName = TAG,
-            fromState = KeyguardState.GLANCEABLE_HUB,
-            toState = KeyguardState.LOCKSCREEN,
-        )
+    private fun listenForHubToLockscreenOrDreaming() {
+        scope.launch("$TAG#listenForGlanceableHubToLockscreenOrDream") {
+            keyguardInteractor.isDreaming.collectLatest { dreaming ->
+                withContext(mainDispatcher) {
+                    val toState =
+                        if (dreaming) {
+                            KeyguardState.DREAMING
+                        } else {
+                            KeyguardState.LOCKSCREEN
+                        }
+                    glanceableHubTransitions.listenForGlanceableHubTransition(
+                        transitionOwnerName = TAG,
+                        fromState = KeyguardState.GLANCEABLE_HUB,
+                        toState = toState,
+                    )
+                }
+            }
+        }
     }
 
     private fun listenForHubToPrimaryBouncer() {
@@ -137,31 +150,15 @@
         }
     }
 
-    private fun listenForHubToDreaming() {
-        val invalidFromStates = setOf(KeyguardState.AOD, KeyguardState.DOZING)
-        scope.launch("$TAG#listenForHubToDreaming") {
-            keyguardInteractor.isAbleToDream
-                .sampleMultiple(startedKeyguardTransitionStep, finishedKeyguardState)
-                .collect { (isAbleToDream, lastStartedTransition, finishedKeyguardState) ->
-                    val isOnHub = finishedKeyguardState == KeyguardState.GLANCEABLE_HUB
-                    val isTransitionInterruptible =
-                        lastStartedTransition.to == KeyguardState.GLANCEABLE_HUB &&
-                            !invalidFromStates.contains(lastStartedTransition.from)
-                    if (isAbleToDream && (isOnHub || isTransitionInterruptible)) {
-                        startTransitionTo(KeyguardState.DREAMING)
-                    }
-                }
-        }
-    }
-
     private fun listenForHubToOccluded() {
         scope.launch {
-            keyguardInteractor.isKeyguardOccluded.sample(startedKeyguardState, ::Pair).collect {
-                (isOccluded, keyguardState) ->
-                if (isOccluded && keyguardState == fromState) {
-                    startTransitionTo(KeyguardState.OCCLUDED)
+            and(keyguardInteractor.isKeyguardOccluded, not(keyguardInteractor.isDreaming))
+                .sample(startedKeyguardState, ::Pair)
+                .collect { (isOccludedAndNotDreaming, keyguardState) ->
+                    if (isOccludedAndNotDreaming && keyguardState == fromState) {
+                        startTransitionTo(KeyguardState.OCCLUDED)
+                    }
                 }
-            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index 40b2c63..7263ae9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -360,13 +360,13 @@
         if (!com.android.systemui.Flags.communalHub()) {
             return
         }
-
-        glanceableHubTransitions.listenForGlanceableHubTransition(
-            transitionName = "listenForLockscreenToGlanceableHub",
-            transitionOwnerName = TAG,
-            fromState = KeyguardState.LOCKSCREEN,
-            toState = KeyguardState.GLANCEABLE_HUB,
-        )
+        scope.launch(mainDispatcher) {
+            glanceableHubTransitions.listenForGlanceableHubTransition(
+                transitionOwnerName = TAG,
+                fromState = KeyguardState.LOCKSCREEN,
+                toState = KeyguardState.GLANCEABLE_HUB,
+            )
+        }
     }
 
     override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
index f45a9ec..c5a2846 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
@@ -274,5 +274,6 @@
         val TO_GONE_SHORT_DURATION = 200.milliseconds
         val TO_AOD_DURATION = DEFAULT_DURATION
         val TO_LOCKSCREEN_DURATION = DEFAULT_DURATION
+        val TO_DOZING_DURATION = DEFAULT_DURATION
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt
index 809c0aee..6cb1eb4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt
@@ -18,11 +18,9 @@
 
 import android.animation.ValueAnimator
 import com.android.app.animation.Interpolators
-import com.android.app.tracing.coroutines.launch
 import com.android.systemui.communal.domain.interactor.CommunalInteractor
 import com.android.systemui.communal.domain.interactor.CommunalTransitionProgress
 import com.android.systemui.communal.shared.model.CommunalSceneKey
-import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -32,13 +30,11 @@
 import java.util.UUID
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.flowOn
 
 class GlanceableHubTransitions
 @Inject
 constructor(
-    @Application private val scope: CoroutineScope,
     @Background private val bgDispatcher: CoroutineDispatcher,
     private val transitionInteractor: KeyguardTransitionInteractor,
     private val transitionRepository: KeyguardTransitionRepository,
@@ -52,105 +48,101 @@
      * externally. The progress is used for both transitions caused by user touch input or by
      * programmatic changes.
      */
-    fun listenForGlanceableHubTransition(
-        transitionName: String,
+    suspend fun listenForGlanceableHubTransition(
         transitionOwnerName: String,
         fromState: KeyguardState,
         toState: KeyguardState,
     ) {
         val toScene =
-            if (toState == KeyguardState.GLANCEABLE_HUB) {
-                CommunalSceneKey.Communal
-            } else {
+            if (fromState == KeyguardState.GLANCEABLE_HUB) {
                 CommunalSceneKey.Blank
+            } else {
+                CommunalSceneKey.Communal
             }
         var transitionId: UUID? = null
-        scope.launch("$transitionOwnerName#$transitionName") {
-            communalInteractor
-                .transitionProgressToScene(toScene)
-                .sample(
-                    transitionInteractor.startedKeyguardTransitionStep.flowOn(bgDispatcher),
-                    ::Pair
-                )
-                .collect { pair ->
-                    val (transitionProgress, lastStartedStep) = pair
 
-                    val id = transitionId
-                    if (id == null) {
-                        // No transition started.
-                        if (
-                            transitionProgress is CommunalTransitionProgress.Transition &&
-                                lastStartedStep.to == fromState
-                        ) {
-                            transitionId =
-                                transitionRepository.startTransition(
-                                    TransitionInfo(
-                                        ownerName = transitionOwnerName,
-                                        from = fromState,
-                                        to = toState,
-                                        animator = null, // transition will be manually controlled
-                                    )
+        communalInteractor
+            .transitionProgressToScene(toScene)
+            .sample(
+                transitionInteractor.startedKeyguardTransitionStep.flowOn(bgDispatcher),
+                ::Pair,
+            )
+            .collect { (transitionProgress, lastStartedStep) ->
+                val id = transitionId
+                if (id == null) {
+                    // No transition started.
+                    if (
+                        transitionProgress is CommunalTransitionProgress.Transition &&
+                            lastStartedStep.to == fromState
+                    ) {
+                        transitionId =
+                            transitionRepository.startTransition(
+                                TransitionInfo(
+                                    ownerName = transitionOwnerName,
+                                    from = fromState,
+                                    to = toState,
+                                    animator = null, // transition will be manually controlled
                                 )
-                        }
-                    } else {
-                        if (lastStartedStep.to != toState) {
-                            return@collect
-                        }
-                        // An existing `id` means a transition is started, and calls to
-                        // `updateTransition` will control it until FINISHED or CANCELED
-                        val nextState: TransitionState
-                        val progressFraction: Float
-                        when (transitionProgress) {
-                            is CommunalTransitionProgress.Idle -> {
-                                if (transitionProgress.scene == toScene) {
-                                    nextState = TransitionState.FINISHED
-                                    progressFraction = 1f
-                                } else {
-                                    nextState = TransitionState.CANCELED
-                                    progressFraction = 0f
-                                }
-                            }
-                            is CommunalTransitionProgress.Transition -> {
-                                nextState = TransitionState.RUNNING
-                                progressFraction = transitionProgress.progress
-                            }
-                            is CommunalTransitionProgress.OtherTransition -> {
-                                // Shouldn't happen but if another transition starts during the
-                                // current one, mark the current one as canceled.
+                            )
+                    }
+                } else {
+                    if (lastStartedStep.to != toState) {
+                        return@collect
+                    }
+                    // An existing `id` means a transition is started, and calls to
+                    // `updateTransition` will control it until FINISHED or CANCELED
+                    val nextState: TransitionState
+                    val progressFraction: Float
+                    when (transitionProgress) {
+                        is CommunalTransitionProgress.Idle -> {
+                            if (transitionProgress.scene == toScene) {
+                                nextState = TransitionState.FINISHED
+                                progressFraction = 1f
+                            } else {
                                 nextState = TransitionState.CANCELED
                                 progressFraction = 0f
                             }
                         }
-                        transitionRepository.updateTransition(
-                            id,
-                            progressFraction,
-                            nextState,
-                        )
-
-                        if (
-                            nextState == TransitionState.CANCELED ||
-                                nextState == TransitionState.FINISHED
-                        ) {
-                            transitionId = null
+                        is CommunalTransitionProgress.Transition -> {
+                            nextState = TransitionState.RUNNING
+                            progressFraction = transitionProgress.progress
                         }
-
-                        // If canceled, just put the state back.
-                        if (nextState == TransitionState.CANCELED) {
-                            transitionRepository.startTransition(
-                                TransitionInfo(
-                                    ownerName = transitionOwnerName,
-                                    from = toState,
-                                    to = fromState,
-                                    animator =
-                                        ValueAnimator().apply {
-                                            interpolator = Interpolators.LINEAR
-                                            duration = 0
-                                        }
-                                )
-                            )
+                        is CommunalTransitionProgress.OtherTransition -> {
+                            // Shouldn't happen but if another transition starts during the
+                            // current one, mark the current one as canceled.
+                            nextState = TransitionState.CANCELED
+                            progressFraction = 0f
                         }
                     }
+                    transitionRepository.updateTransition(
+                        id,
+                        progressFraction,
+                        nextState,
+                    )
+
+                    if (
+                        nextState == TransitionState.CANCELED ||
+                            nextState == TransitionState.FINISHED
+                    ) {
+                        transitionId = null
+                    }
+
+                    // If canceled, just put the state back.
+                    if (nextState == TransitionState.CANCELED) {
+                        transitionRepository.startTransition(
+                            TransitionInfo(
+                                ownerName = transitionOwnerName,
+                                from = toState,
+                                to = fromState,
+                                animator =
+                                    ValueAnimator().apply {
+                                        interpolator = Interpolators.LINEAR
+                                        duration = 0
+                                    }
+                            )
+                        )
+                    }
                 }
-        }
+            }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt
index 56d64a2..bc3f0cc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractor.kt
@@ -15,12 +15,15 @@
  *
  */
 
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
 package com.android.systemui.keyguard.domain.interactor
 
 import android.content.Context
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.data.repository.KeyguardBlueprintRepository
+import com.android.systemui.keyguard.shared.ComposeLockscreen
 import com.android.systemui.keyguard.shared.model.KeyguardBlueprint
 import com.android.systemui.keyguard.ui.view.layout.blueprints.DefaultKeyguardBlueprint
 import com.android.systemui.keyguard.ui.view.layout.blueprints.SplitShadeKeyguardBlueprint
@@ -29,7 +32,9 @@
 import com.android.systemui.statusbar.policy.SplitShadeStateController
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.flow.onStart
 import kotlinx.coroutines.launch
 
@@ -41,6 +46,7 @@
     @Application private val applicationScope: CoroutineScope,
     private val context: Context,
     private val splitShadeStateController: SplitShadeStateController,
+    private val clockInteractor: KeyguardClockInteractor,
 ) {
 
     /** The current blueprint for the lockscreen. */
@@ -58,6 +64,7 @@
                 .onStart { emit(Unit) }
                 .collect { updateBlueprint() }
         }
+        applicationScope.launch { clockInteractor.currentClock.collect { updateBlueprint() } }
     }
 
     /**
@@ -67,12 +74,17 @@
     private fun updateBlueprint() {
         val useSplitShade =
             splitShadeStateController.shouldUseSplitNotificationShade(context.resources)
+        // TODO(b/326098079): Make ID a constant value.
+        val useWeatherClockLayout =
+            clockInteractor.currentClock.value?.config?.id == "DIGITAL_CLOCK_WEATHER" &&
+                ComposeLockscreen.isEnabled
 
         val blueprintId =
-            if (useSplitShade) {
-                SplitShadeKeyguardBlueprint.ID
-            } else {
-                DefaultKeyguardBlueprint.DEFAULT
+            when {
+                useWeatherClockLayout && useSplitShade -> SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID
+                useWeatherClockLayout -> WEATHER_CLOCK_BLUEPRINT_ID
+                useSplitShade -> SplitShadeKeyguardBlueprint.ID
+                else -> DefaultKeyguardBlueprint.DEFAULT
             }
 
         transitionToBlueprint(blueprintId)
@@ -107,4 +119,13 @@
     fun getCurrentBlueprint(): KeyguardBlueprint {
         return keyguardBlueprintRepository.blueprint.value
     }
+
+    companion object {
+        /**
+         * These values live here because classes in the composable package do not exist in some
+         * systems.
+         */
+        const val WEATHER_CLOCK_BLUEPRINT_ID = "weather-clock"
+        const val SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID = "split-shade-weather-clock"
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
index 873cc84..f46a207 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt
@@ -22,6 +22,7 @@
 import android.util.StateSet
 import android.view.HapticFeedbackConstants
 import android.view.View
+import androidx.core.view.isInvisible
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
 import com.android.systemui.common.ui.view.LongPressHandlingView
@@ -82,6 +83,11 @@
             // of the transition.
             repeatOnLifecycle(Lifecycle.State.CREATED) {
                 launch {
+                    viewModel.isVisible.collect { isVisible ->
+                        longPressHandlingView.isInvisible = !isVisible
+                    }
+                }
+                launch {
                     viewModel.isLongPressEnabled.collect { isEnabled ->
                         longPressHandlingView.setLongPressHandlingEnabled(isEnabled)
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt
index 951df5a..1abf4a6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt
@@ -16,15 +16,20 @@
 package com.android.systemui.keyguard.ui.transitions
 
 import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToAodTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToDozingTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToGoneTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToPrimaryBouncerTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.AodToGoneTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.AodToLockscreenTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.DozingToGoneTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.DozingToLockscreenTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.DozingToPrimaryBouncerTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.GoneToAodTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.GoneToDozingTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.GoneToLockscreenTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.LockscreenToAodTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.LockscreenToDozingTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.LockscreenToDreamingTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.LockscreenToGoneTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel
@@ -32,6 +37,7 @@
 import com.android.systemui.keyguard.ui.viewmodel.OccludedToAodTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToAodTransitionViewModel
+import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToDozingTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToLockscreenTransitionViewModel
 import dagger.Binds
 import dagger.Module
@@ -49,6 +55,12 @@
 
     @Binds
     @IntoSet
+    abstract fun alternateBouncerToDozing(
+        impl: AlternateBouncerToDozingTransitionViewModel
+    ): DeviceEntryIconTransition
+
+    @Binds
+    @IntoSet
     abstract fun alternateBouncerToGone(
         impl: AlternateBouncerToGoneTransitionViewModel
     ): DeviceEntryIconTransition
@@ -71,12 +83,22 @@
 
     @Binds
     @IntoSet
+    abstract fun dozingToGone(impl: DozingToGoneTransitionViewModel): DeviceEntryIconTransition
+
+    @Binds
+    @IntoSet
     abstract fun dozingToLockscreen(
         impl: DozingToLockscreenTransitionViewModel
     ): DeviceEntryIconTransition
 
     @Binds
     @IntoSet
+    abstract fun dozingToPrimaryBouncer(
+        impl: DozingToPrimaryBouncerTransitionViewModel
+    ): DeviceEntryIconTransition
+
+    @Binds
+    @IntoSet
     abstract fun dreamingToLockscreen(
         impl: DreamingToLockscreenTransitionViewModel
     ): DeviceEntryIconTransition
@@ -89,6 +111,12 @@
 
     @Binds
     @IntoSet
+    abstract fun lockscreenToDozing(
+        impl: LockscreenToDozingTransitionViewModel
+    ): DeviceEntryIconTransition
+
+    @Binds
+    @IntoSet
     abstract fun lockscreenToDreaming(
         impl: LockscreenToDreamingTransitionViewModel
     ): DeviceEntryIconTransition
@@ -123,6 +151,10 @@
 
     @Binds
     @IntoSet
+    abstract fun goneToDozing(impl: GoneToDozingTransitionViewModel): DeviceEntryIconTransition
+
+    @Binds
+    @IntoSet
     abstract fun occludedToAod(impl: OccludedToAodTransitionViewModel): DeviceEntryIconTransition
 
     @Binds
@@ -139,6 +171,12 @@
 
     @Binds
     @IntoSet
+    abstract fun primaryBouncerToDozing(
+        impl: PrimaryBouncerToDozingTransitionViewModel
+    ): DeviceEntryIconTransition
+
+    @Binds
+    @IntoSet
     abstract fun primaryBouncerToLockscreen(
         impl: PrimaryBouncerToLockscreenTransitionViewModel
     ): DeviceEntryIconTransition
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/KeyguardBlueprintModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/KeyguardBlueprintModule.kt
index 4f1a754..b4e57cc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/KeyguardBlueprintModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/KeyguardBlueprintModule.kt
@@ -17,10 +17,13 @@
 
 package com.android.systemui.keyguard.ui.view.layout.blueprints
 
-import com.android.systemui.communal.ui.view.layout.blueprints.DefaultCommunalBlueprint
+import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID
+import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.WEATHER_CLOCK_BLUEPRINT_ID
 import com.android.systemui.keyguard.shared.model.KeyguardBlueprint
+import com.android.systemui.keyguard.shared.model.KeyguardSection
 import dagger.Binds
 import dagger.Module
+import dagger.Provides
 import dagger.multibindings.IntoSet
 
 @Module
@@ -43,9 +46,25 @@
         shortcutsBesideUdfpsLockscreenBlueprint: ShortcutsBesideUdfpsKeyguardBlueprint
     ): KeyguardBlueprint
 
-    @Binds
-    @IntoSet
-    abstract fun bindDefaultCommunalBlueprint(
-        defaultCommunalBlueprint: DefaultCommunalBlueprint
-    ): KeyguardBlueprint
+    companion object {
+        /** This is a place holder for weather clock in compose. */
+        @Provides
+        @IntoSet
+        fun bindWeatherClockBlueprintPlaceHolder(): KeyguardBlueprint {
+            return object : KeyguardBlueprint {
+                override val id: String = WEATHER_CLOCK_BLUEPRINT_ID
+                override val sections: List<KeyguardSection> = listOf()
+            }
+        }
+
+        /** This is a place holder for weather clock in compose. */
+        @Provides
+        @IntoSet
+        fun bindSplitShadeWeatherClockBlueprintPlaceHolder(): KeyguardBlueprint {
+            return object : KeyguardBlueprint {
+                override val id: String = SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID
+                override val sections: List<KeyguardSection> = listOf()
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt
index 4bc2d86..a203c53 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultSettingsPopupMenuSection.kt
@@ -26,6 +26,7 @@
 import androidx.constraintlayout.widget.ConstraintSet.END
 import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
 import androidx.constraintlayout.widget.ConstraintSet.START
+import androidx.constraintlayout.widget.ConstraintSet.VISIBILITY_MODE_IGNORE
 import androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT
 import androidx.core.view.isVisible
 import com.android.systemui.Flags.keyguardBottomAreaRefactor
@@ -103,7 +104,8 @@
                 BOTTOM,
                 resources.getDimensionPixelSize(R.dimen.keyguard_affordance_vertical_offset)
             )
-            setVisibility(R.id.keyguard_settings_button, View.GONE)
+            // Ignore ConstrainSet's default visibility, and let the view choose
+            setVisibilityMode(R.id.keyguard_settings_button, VISIBILITY_MODE_IGNORE)
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModel.kt
index b4b48a8..4fd92d7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToAodTransitionViewModel.kt
@@ -25,7 +25,6 @@
 import javax.inject.Inject
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.emptyFlow
 import kotlinx.coroutines.flow.flatMapLatest
 
 /**
@@ -60,7 +59,7 @@
             if (udfpsEnrolledAndEnabled) {
                 transitionAnimation.immediatelyTransitionTo(1f)
             } else {
-                emptyFlow()
+                transitionAnimation.immediatelyTransitionTo(0f)
             }
         }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModel.kt
new file mode 100644
index 0000000..9649af73
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModel.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2024 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.keyguard.ui.viewmodel
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
+import com.android.systemui.keyguard.domain.interactor.FromAlternateBouncerTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flatMapLatest
+
+/**
+ * Breaks down ALTERNATE BOUNCER->DOZING transition into discrete steps for corresponding views to
+ * consume.
+ */
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class AlternateBouncerToDozingTransitionViewModel
+@Inject
+constructor(
+    deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
+    animationFlow: KeyguardTransitionAnimationFlow,
+) : DeviceEntryIconTransition {
+    private val transitionAnimation =
+        animationFlow.setup(
+            duration = FromAlternateBouncerTransitionInteractor.TO_DOZING_DURATION,
+            from = KeyguardState.ALTERNATE_BOUNCER,
+            to = KeyguardState.DOZING,
+        )
+
+    val deviceEntryBackgroundViewAlpha: Flow<Float> =
+        transitionAnimation.immediatelyTransitionTo(0f)
+
+    override val deviceEntryParentViewAlpha: Flow<Float> =
+        deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest { udfpsEnrolledAndEnabled
+            ->
+            if (udfpsEnrolledAndEnabled) {
+                transitionAnimation.immediatelyTransitionTo(1f)
+            } else {
+                transitionAnimation.immediatelyTransitionTo(0f)
+            }
+        }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
index 302ba72..662a77e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt
@@ -46,6 +46,11 @@
     dreamingToLockscreenTransitionViewModel: DreamingToLockscreenTransitionViewModel,
     alternateBouncerToAodTransitionViewModel: AlternateBouncerToAodTransitionViewModel,
     goneToLockscreenTransitionViewModel: GoneToLockscreenTransitionViewModel,
+    goneToDozingTransitionViewModel: GoneToDozingTransitionViewModel,
+    primaryBouncerToDozingTransitionViewModel: PrimaryBouncerToDozingTransitionViewModel,
+    lockscreenToDozingTransitionViewModel: LockscreenToDozingTransitionViewModel,
+    dozingToLockscreenTransitionViewModel: DozingToLockscreenTransitionViewModel,
+    alternateBouncerToDozingTransitionViewModel: AlternateBouncerToDozingTransitionViewModel,
 ) {
     val color: Flow<Int> =
         deviceEntryIconViewModel.useBackgroundProtection.flatMapLatest { useBackground ->
@@ -82,6 +87,11 @@
                         dreamingToLockscreenTransitionViewModel.deviceEntryBackgroundViewAlpha,
                         alternateBouncerToAodTransitionViewModel.deviceEntryBackgroundViewAlpha,
                         goneToLockscreenTransitionViewModel.deviceEntryBackgroundViewAlpha,
+                        goneToDozingTransitionViewModel.deviceEntryBackgroundViewAlpha,
+                        primaryBouncerToDozingTransitionViewModel.deviceEntryBackgroundViewAlpha,
+                        lockscreenToDozingTransitionViewModel.deviceEntryBackgroundViewAlpha,
+                        dozingToLockscreenTransitionViewModel.deviceEntryBackgroundViewAlpha,
+                        alternateBouncerToDozingTransitionViewModel.deviceEntryBackgroundViewAlpha,
                     )
                     .merge()
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
index ad6a36c..6281097 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
@@ -33,6 +33,7 @@
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onStart
 
@@ -48,9 +49,9 @@
     deviceEntryIconViewModel: DeviceEntryIconViewModel,
     udfpsOverlayInteractor: UdfpsOverlayInteractor,
 ) {
-    private val isShowingAod: Flow<Boolean> =
+    private val isShowingAodOrDozing: Flow<Boolean> =
         transitionInteractor.startedKeyguardState.map { keyguardState ->
-            keyguardState == KeyguardState.AOD
+            keyguardState == KeyguardState.AOD || keyguardState == KeyguardState.DOZING
         }
 
     private fun getColor(usingBackgroundProtection: Boolean): Int {
@@ -68,13 +69,15 @@
                 .onStart { emit(getColor(useBgProtection)) }
         }
 
+    // While dozing, the display can show the AOD UI; show the AOD udfps when dozing
     private val useAodIconVariant: Flow<Boolean> =
-        combine(isShowingAod, deviceEntryUdfpsInteractor.isUdfpsSupported) {
-                isTransitionToAod,
-                isUdfps ->
-                isTransitionToAod && isUdfps
+        deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest { udfspEnrolled ->
+            if (udfspEnrolled) {
+                isShowingAodOrDozing.distinctUntilChanged()
+            } else {
+                flowOf(false)
             }
-            .distinctUntilChanged()
+        }
 
     private val padding: Flow<Int> =
         deviceEntryUdfpsInteractor.isUdfpsSupported.flatMapLatest { udfpsSupported ->
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
index c9cf0c3..31e8093 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt
@@ -37,6 +37,7 @@
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.flow.flowOf
@@ -206,6 +207,7 @@
                 DeviceEntryIconView.IconType.LOCK
             }
         }
+    val isVisible: Flow<Boolean> = deviceEntryViewAlpha.map { it > 0f }.distinctUntilChanged()
     val isLongPressEnabled: Flow<Boolean> =
         combine(
             iconType,
@@ -217,6 +219,7 @@
                 DeviceEntryIconView.IconType.FINGERPRINT -> false
             }
         }
+
     val accessibilityDelegateHint: Flow<DeviceEntryIconView.AccessibilityHintType> =
         combine(iconType, isLongPressEnabled) { deviceEntryStatus, longPressEnabled ->
             if (longPressEnabled) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModel.kt
new file mode 100644
index 0000000..fca1604
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModel.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 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.keyguard.ui.viewmodel
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.FromDozingTransitionInteractor.Companion.TO_GONE_DURATION
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+
+/** Breaks down DOZING->GONE transition into discrete steps for corresponding views to consume. */
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class DozingToGoneTransitionViewModel
+@Inject
+constructor(
+    animationFlow: KeyguardTransitionAnimationFlow,
+) : DeviceEntryIconTransition {
+
+    private val transitionAnimation =
+        animationFlow.setup(
+            duration = TO_GONE_DURATION,
+            from = KeyguardState.DOZING,
+            to = KeyguardState.GONE,
+        )
+
+    override val deviceEntryParentViewAlpha: Flow<Float> =
+        transitionAnimation.immediatelyTransitionTo(0f)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt
index f81941b..168d6e1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModel.kt
@@ -52,6 +52,9 @@
 
     val lockscreenAlpha: Flow<Float> = shortcutsAlpha
 
+    val deviceEntryBackgroundViewAlpha: Flow<Float> =
+        transitionAnimation.immediatelyTransitionTo(1f)
+
     override val deviceEntryParentViewAlpha: Flow<Float> =
         transitionAnimation.immediatelyTransitionTo(1f)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModel.kt
new file mode 100644
index 0000000..4395c34
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModel.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2024 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.keyguard.ui.viewmodel
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.domain.interactor.FromDozingTransitionInteractor.Companion.TO_PRIMARY_BOUNCER_DURATION
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * Breaks down DOZING->PRIMARY BOUNCER transition into discrete steps for corresponding views to
+ * consume.
+ */
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class DozingToPrimaryBouncerTransitionViewModel
+@Inject
+constructor(
+    animationFlow: KeyguardTransitionAnimationFlow,
+) : DeviceEntryIconTransition {
+
+    private val transitionAnimation =
+        animationFlow.setup(
+            duration = TO_PRIMARY_BOUNCER_DURATION,
+            from = KeyguardState.DOZING,
+            to = KeyguardState.PRIMARY_BOUNCER,
+        )
+
+    override val deviceEntryParentViewAlpha: Flow<Float> =
+        transitionAnimation.immediatelyTransitionTo(0f)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
index 374a932..c64f277 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
@@ -17,18 +17,26 @@
 package com.android.systemui.keyguard.ui.viewmodel
 
 import com.android.app.animation.Interpolators.EMPHASIZED
+import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.res.R
 import javax.inject.Inject
 import kotlin.time.Duration.Companion.milliseconds
 import kotlin.time.Duration.Companion.seconds
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flatMapLatest
 
+@OptIn(ExperimentalCoroutinesApi::class)
 @SysUISingleton
 class DreamingToGlanceableHubTransitionViewModel
 @Inject
-constructor(animationFlow: KeyguardTransitionAnimationFlow) {
+constructor(
+    animationFlow: KeyguardTransitionAnimationFlow,
+    configurationInteractor: ConfigurationInteractor,
+) {
 
     private val transitionAnimation =
         animationFlow.setup(
@@ -37,14 +45,18 @@
             to = KeyguardState.GLANCEABLE_HUB,
         )
 
-    fun dreamOverlayTranslationX(translatePx: Int): Flow<Float> {
-        return transitionAnimation.sharedFlow(
-            duration = TO_GLANCEABLE_HUB_DURATION,
-            onStep = { it * -translatePx },
-            interpolator = EMPHASIZED,
-            name = "DREAMING->GLANCEABLE_HUB: overlayTranslationX",
-        )
-    }
+    val dreamOverlayTranslationX: Flow<Float> =
+        configurationInteractor
+            .dimensionPixelSize(R.dimen.dreaming_to_hub_transition_dream_overlay_translation_x)
+            .flatMapLatest { translatePx ->
+                transitionAnimation.sharedFlow(
+                    duration = TO_GLANCEABLE_HUB_DURATION,
+                    onStep = { value -> value * translatePx },
+                    interpolator = EMPHASIZED,
+                    onCancel = { 0f },
+                    name = "DREAMING->GLANCEABLE_HUB: overlayTranslationX",
+                )
+            }
 
     val dreamOverlayAlpha: Flow<Float> =
         transitionAnimation.sharedFlow(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
index 3802d5d..d3277cd 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModel.kt
@@ -18,7 +18,6 @@
 
 import com.android.app.animation.Interpolators.EMPHASIZED
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
 import com.android.systemui.keyguard.domain.interactor.FromDreamingTransitionInteractor
 import com.android.systemui.keyguard.domain.interactor.FromDreamingTransitionInteractor.Companion.TO_LOCKSCREEN_DURATION
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
@@ -43,7 +42,6 @@
 constructor(
     keyguardTransitionInteractor: KeyguardTransitionInteractor,
     private val fromDreamingTransitionInteractor: FromDreamingTransitionInteractor,
-    private val deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
     animationFlow: KeyguardTransitionAnimationFlow,
 ) : DeviceEntryIconTransition {
     fun startTransition() = fromDreamingTransitionInteractor.startToLockscreenTransition()
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModel.kt
new file mode 100644
index 0000000..478c4faa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModel.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2024 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.keyguard.ui.viewmodel
+
+import com.android.app.animation.Interpolators
+import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.res.R
+import javax.inject.Inject
+import kotlin.time.Duration.Companion.milliseconds
+import kotlin.time.Duration.Companion.seconds
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flatMapLatest
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SysUISingleton
+class GlanceableHubToDreamingTransitionViewModel
+@Inject
+constructor(
+    animationFlow: KeyguardTransitionAnimationFlow,
+    configurationInteractor: ConfigurationInteractor,
+) {
+
+    private val transitionAnimation =
+        animationFlow.setup(
+            duration = FROM_GLANCEABLE_HUB_DURATION,
+            from = KeyguardState.GLANCEABLE_HUB,
+            to = KeyguardState.DREAMING,
+        )
+
+    val dreamOverlayAlpha: Flow<Float> =
+        transitionAnimation.sharedFlow(
+            duration = 167.milliseconds,
+            startTime = 167.milliseconds,
+            onStep = { it },
+            name = "GLANCEABLE_HUB->DREAMING: dreamOverlayAlpha",
+        )
+
+    val dreamOverlayTranslationX: Flow<Float> =
+        configurationInteractor
+            .dimensionPixelSize(R.dimen.hub_to_dreaming_transition_dream_overlay_translation_x)
+            .flatMapLatest { translatePx: Int ->
+                transitionAnimation.sharedFlow(
+                    duration = FROM_GLANCEABLE_HUB_DURATION,
+                    onStep = { value -> -translatePx + value * translatePx },
+                    interpolator = Interpolators.EMPHASIZED,
+                    onCancel = { -translatePx.toFloat() },
+                    name = "GLANCEABLE_HUB->LOCKSCREEN: dreamOverlayTranslationX"
+                )
+            }
+
+    private companion object {
+        val FROM_GLANCEABLE_HUB_DURATION = 1.seconds
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModel.kt
index 55a289e..80a6bda 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModel.kt
@@ -17,13 +17,17 @@
 package com.android.systemui.keyguard.ui.viewmodel
 
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
 import com.android.systemui.keyguard.domain.interactor.FromGoneTransitionInteractor.Companion.TO_DOZING_DURATION
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
 import javax.inject.Inject
 import kotlin.time.Duration.Companion.milliseconds
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.flatMapLatest
 
 /** Breaks down GONE->DOZING transition into discrete steps for corresponding views to consume. */
 @ExperimentalCoroutinesApi
@@ -31,8 +35,9 @@
 class GoneToDozingTransitionViewModel
 @Inject
 constructor(
+    deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
     animationFlow: KeyguardTransitionAnimationFlow,
-) {
+) : DeviceEntryIconTransition {
 
     private val transitionAnimation =
         animationFlow.setup(
@@ -48,4 +53,17 @@
             onCancel = { 1f },
             onFinish = { 1f },
         )
+
+    val deviceEntryBackgroundViewAlpha: Flow<Float> =
+        transitionAnimation.immediatelyTransitionTo(0f)
+
+    override val deviceEntryParentViewAlpha: Flow<Float> =
+        deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest {
+            isUdfpsEnrolledAndEnabled ->
+            if (isUdfpsEnrolledAndEnabled) {
+                transitionAnimation.immediatelyTransitionTo(1f)
+            } else {
+                emptyFlow()
+            }
+        }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt
index 4c0cd2f..b60c52b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModel.kt
@@ -17,19 +17,25 @@
 package com.android.systemui.keyguard.ui.viewmodel
 
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
 import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor.Companion.TO_DOZING_DURATION
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
 import javax.inject.Inject
 import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flatMapLatest
 
+@OptIn(ExperimentalCoroutinesApi::class)
 @SysUISingleton
 class LockscreenToDozingTransitionViewModel
 @Inject
 constructor(
+    deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
     animationFlow: KeyguardTransitionAnimationFlow,
-) {
+) : DeviceEntryIconTransition {
 
     private val transitionAnimation =
         animationFlow.setup(
@@ -45,4 +51,19 @@
             onFinish = { 0f },
             onCancel = { 1f },
         )
+
+    val deviceEntryBackgroundViewAlpha: Flow<Float> =
+        transitionAnimation.immediatelyTransitionTo(0f)
+
+    override val deviceEntryParentViewAlpha: Flow<Float> =
+        deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest {
+            isUdfpsEnrolledAndEnabled ->
+            transitionAnimation.immediatelyTransitionTo(
+                if (isUdfpsEnrolledAndEnabled) {
+                    1f
+                } else {
+                    0f
+                }
+            )
+        }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModel.kt
new file mode 100644
index 0000000..13f651a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModel.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2024 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.keyguard.ui.viewmodel
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
+import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor.Companion.TO_DOZING_DURATION
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow
+import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.flatMapLatest
+
+/**
+ * Breaks down PRIMARY BOUNCER->DOZING transition into discrete steps for corresponding views to
+ * consume.
+ */
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class PrimaryBouncerToDozingTransitionViewModel
+@Inject
+constructor(
+    deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
+    animationFlow: KeyguardTransitionAnimationFlow,
+) : DeviceEntryIconTransition {
+
+    private val transitionAnimation =
+        animationFlow.setup(
+            duration = TO_DOZING_DURATION,
+            from = KeyguardState.PRIMARY_BOUNCER,
+            to = KeyguardState.DOZING,
+        )
+
+    val deviceEntryBackgroundViewAlpha: Flow<Float> =
+        transitionAnimation.immediatelyTransitionTo(0f)
+
+    override val deviceEntryParentViewAlpha: Flow<Float> =
+        deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest {
+            isUdfpsEnrolledAndEnabled ->
+            if (isUdfpsEnrolledAndEnabled) {
+                transitionAnimation.immediatelyTransitionTo(1f)
+            } else {
+                emptyFlow()
+            }
+        }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index cc3729b..8b7c85b 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -119,6 +119,16 @@
         return factory.create("LSShadeTransitionLog", 50);
     }
 
+    /** */
+    @Provides
+    @SysUISingleton
+    @SensitiveNotificationProtectionLog
+    public static LogBuffer provideSensitiveNotificationProtectionLogBuffer(
+            LogBufferFactory factory
+    ) {
+        return factory.create("SensitiveNotificationProtectionLog", 10);
+    }
+
     /** Provides a logging buffer for shade window messages. */
     @Provides
     @SysUISingleton
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/log/dagger/SensitiveNotificationProtectionLog.kt
similarity index 62%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
copy to packages/SystemUI/src/com/android/systemui/log/dagger/SensitiveNotificationProtectionLog.kt
index b370859..54e87cd 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/SensitiveNotificationProtectionLog.kt
@@ -14,14 +14,12 @@
  * limitations under the License.
  */
 
-package com.android.systemui.keyguard.ui.viewmodel
+package com.android.systemui.log.dagger
 
-import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
-import com.android.systemui.kosmos.Kosmos
+import javax.inject.Qualifier
 
-val Kosmos.dreamingToGlanceableHubTransitionViewModel by
-    Kosmos.Fixture {
-        DreamingToGlanceableHubTransitionViewModel(
-            animationFlow = keyguardTransitionAnimationFlow,
-        )
-    }
+/** A [com.android.systemui.log.LogBuffer] for SensitiveNotificationProtection. */
+@Qualifier
+@MustBeDocumented
+@Retention(AnnotationRetention.RUNTIME)
+annotation class SensitiveNotificationProtectionLog
diff --git a/packages/SystemUI/src/com/android/systemui/media/OWNERS b/packages/SystemUI/src/com/android/systemui/media/OWNERS
index 69ea57b..5eb14fc 100644
--- a/packages/SystemUI/src/com/android/systemui/media/OWNERS
+++ b/packages/SystemUI/src/com/android/systemui/media/OWNERS
@@ -1 +1,9 @@
-per-file MediaProjectionPermissionActivity.java = michaelwr@google.com
+# Bug component: 78010
+
+asc@google.com
+ethibodeau@google.com
+michaelmikhil@google.com
+
+# Audio team
+per-file RingtonePlayer.java = file:/services/core/java/com/android/server/audio/OWNERS
+per-file NotificationPlayer.java = file:/services/core/java/com/android/server/audio/OWNERS
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaController.kt
index 9206af2..ba7d410 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/KeyguardMediaController.kt
@@ -300,10 +300,17 @@
     private fun setVisibility(view: ViewGroup?, newVisibility: Int) {
         val currentMediaContainer = view ?: return
 
-        val previousVisibility = currentMediaContainer.visibility
-        currentMediaContainer.visibility = newVisibility
-        if (previousVisibility != newVisibility && currentMediaContainer is MediaContainerView) {
-            visibilityChangedListener?.invoke(newVisibility == View.VISIBLE)
+        val isVisible = newVisibility == View.VISIBLE
+
+        if (currentMediaContainer is MediaContainerView) {
+            val previousVisibility = currentMediaContainer.visibility
+
+            currentMediaContainer.setKeyguardVisibility(isVisible)
+            if (previousVisibility != newVisibility) {
+                visibilityChangedListener?.invoke(isVisible)
+            }
+        } else {
+            currentMediaContainer.visibility = newVisibility
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java
index e8ad4d3..840b309 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java
@@ -18,7 +18,7 @@
 
 import static android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS;
 
-import static com.android.systemui.Flags.legacyLeAudioSharing;
+import static com.android.settingslib.flags.Flags.legacyLeAudioSharing;
 import static com.android.systemui.media.controls.shared.model.SmartspaceMediaDataKt.NUM_REQUIRED_RECOMMENDATIONS;
 
 import android.animation.Animator;
@@ -260,7 +260,6 @@
     private TurbulenceNoiseController mTurbulenceNoiseController;
     private LoadingEffect mLoadingEffect;
     private final GlobalSettings mGlobalSettings;
-    private final Random mRandom = new Random();
     private TurbulenceNoiseAnimationConfig mTurbulenceNoiseAnimationConfig;
     private boolean mWasPlaying = false;
     private boolean mButtonClicked = false;
@@ -1294,13 +1293,14 @@
                 mMediaViewHolder.getTurbulenceNoiseView();
         int width = targetView.getWidth();
         int height = targetView.getHeight();
+        Random random = new Random();
 
         return new TurbulenceNoiseAnimationConfig(
                 /* gridCount= */ 2.14f,
                 TurbulenceNoiseAnimationConfig.DEFAULT_LUMINOSITY_MULTIPLIER,
-                /* noiseOffsetX= */ mRandom.nextFloat(),
-                /* noiseOffsetY= */ mRandom.nextFloat(),
-                /* noiseOffsetZ= */ mRandom.nextFloat(),
+                /* noiseOffsetX= */ random.nextFloat(),
+                /* noiseOffsetY= */ random.nextFloat(),
+                /* noiseOffsetZ= */ random.nextFloat(),
                 /* noiseMoveSpeedX= */ 0.42f,
                 /* noiseMoveSpeedY= */ 0f,
                 TurbulenceNoiseAnimationConfig.DEFAULT_NOISE_SPEED_Z,
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt
index 3b989d9..dbd71f3 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt
@@ -58,6 +58,7 @@
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.statusbar.policy.SplitShadeStateController
 import com.android.systemui.util.animation.UniqueObjectHostView
+import com.android.systemui.util.kotlin.BooleanFlowOperators.and
 import com.android.systemui.util.settings.SecureSettings
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
@@ -583,12 +584,14 @@
             UserHandle.USER_ALL
         )
 
-        // Listen to the communal UI state.
+        // Listen to the communal UI state. Make sure that communal UI is showing and hub itself is
+        // available, ie. not disabled and able to be shown.
         coroutineScope.launch {
-            communalInteractor.isCommunalShowing.collect { value ->
-                isCommunalShowing = value
-                updateDesiredLocation(forceNoAnimation = true)
-            }
+            and(communalInteractor.isCommunalShowing, communalInteractor.isCommunalAvailable)
+                .collect { value ->
+                    isCommunalShowing = value
+                    updateDesiredLocation()
+                }
         }
     }
 
@@ -1150,12 +1153,16 @@
             when {
                 mediaFlags.isSceneContainerEnabled() -> desiredLocation
                 dreamOverlayActive && dreamMediaComplicationActive -> LOCATION_DREAM_OVERLAY
+
+                // UMO should show in communal unless the shade is expanding or visible.
+                isCommunalShowing && qsExpansion == 0.0f -> LOCATION_COMMUNAL_HUB
                 (qsExpansion > 0.0f || inSplitShade) && !onLockscreen -> LOCATION_QS
                 qsExpansion > 0.4f && onLockscreen -> LOCATION_QS
                 onLockscreen && isSplitShadeExpanding() -> LOCATION_QS
                 onLockscreen && isTransformingToFullShadeAndInQQS() -> LOCATION_QQS
-                // TODO(b/311234666): revisit logic once interactions between the hub and
-                //  shade/keyguard state are finalized
+
+                // Communal does not have its own StatusBarState so it should always have higher
+                // priority for the UMO over the lockscreen.
                 isCommunalShowing -> LOCATION_COMMUNAL_HUB
                 onLockscreen && allowMediaPlayerOnLockScreen -> LOCATION_LOCKSCREEN
                 else -> LOCATION_QQS
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
index 8e0191e..1e31755 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.media.dialog;
 
+import static com.android.settingslib.flags.Flags.legacyLeAudioSharing;
+
 import android.app.AlertDialog;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothLeBroadcastAssistant;
@@ -492,6 +494,7 @@
 
     @Override
     public boolean isBroadcastSupported() {
+        if (!legacyLeAudioSharing()) return false;
         boolean isBluetoothLeDevice = false;
         if (mMediaOutputController.getCurrentConnectedMediaDevice() != null) {
             isBluetoothLeDevice = mMediaOutputController.isBluetoothLeDevice(
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
index c379d0e..eb6a320 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
@@ -16,7 +16,7 @@
 
 package com.android.systemui.media.dialog;
 
-import static com.android.systemui.Flags.legacyLeAudioSharing;
+import static com.android.settingslib.flags.Flags.legacyLeAudioSharing;
 
 import android.content.Context;
 import android.os.Bundle;
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt
index 1002cc3..38d31ed 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogReceiver.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.media.dialog
 
+import com.android.settingslib.flags.Flags.legacyLeAudioSharing
 import android.content.BroadcastReceiver
 import android.content.Context
 import android.content.Intent
@@ -44,6 +45,7 @@
                 mediaOutputDialogFactory.createDialogForSystemRouting()
             }
             MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG -> {
+                if (!legacyLeAudioSharing()) return
                 val packageName: String? =
                     intent.getStringExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME)
                 launchMediaOutputBroadcastDialogIfPossible(packageName)
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/OWNERS b/packages/SystemUI/src/com/android/systemui/media/dialog/OWNERS
new file mode 100644
index 0000000..95b8fa7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 1280508
+
+# Files in this directory should still be reviewed by a member of SystemUI team
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
index 416eae1..4f062af 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
@@ -72,7 +72,7 @@
         context: Context,
         logger: MediaTttReceiverLogger,
         windowManager: WindowManager,
-        mainExecutor: DelayableExecutor,
+        @Main mainExecutor: DelayableExecutor,
         accessibilityManager: AccessibilityManager,
         configurationController: ConfigurationController,
         dumpManager: DumpManager,
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionServiceHelper.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionServiceHelper.kt
index afe6285..f1cade7 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionServiceHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/MediaProjectionServiceHelper.kt
@@ -16,9 +16,6 @@
 
 package com.android.systemui.mediaprojection
 
-import android.compat.annotation.ChangeId
-import android.compat.annotation.Disabled
-import android.compat.annotation.Overridable
 import android.content.Context
 import android.media.projection.IMediaProjection
 import android.media.projection.IMediaProjectionManager
@@ -34,18 +31,6 @@
  */
 class MediaProjectionServiceHelper {
     companion object {
-        /**
-         * This change id ensures that users are presented with a choice of capturing a single app
-         * or the entire screen when initiating a MediaProjection session, overriding the usage of
-         * MediaProjectionConfig#createConfigForDefaultDisplay.
-         *
-         * @hide
-         */
-        @ChangeId
-        @Overridable
-        @Disabled
-        const val OVERRIDE_DISABLE_MEDIA_PROJECTION_SINGLE_APP_OPTION = 316897322L // buganizer id
-
         private const val TAG = "MediaProjectionServiceHelper"
         private val service =
             IMediaProjectionManager.Stub.asInterface(
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/OWNERS b/packages/SystemUI/src/com/android/systemui/mediaprojection/OWNERS
new file mode 100644
index 0000000..bd74077
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 1345447
+
+include /media/java/android/media/projection/OWNERS
+chrisgollner@google.com
+nickchameyev@google.com
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
index 0769731..8b034b2 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionActivity.java
@@ -16,26 +16,21 @@
 
 package com.android.systemui.mediaprojection.permission;
 
-import static android.Manifest.permission.LOG_COMPAT_CHANGE;
-import static android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG;
 import static android.media.projection.IMediaProjectionManager.EXTRA_PACKAGE_REUSING_GRANTED_CONSENT;
 import static android.media.projection.IMediaProjectionManager.EXTRA_USER_REVIEW_GRANTED_CONSENT;
 import static android.media.projection.ReviewGrantedConsentResult.RECORD_CANCEL;
 import static android.media.projection.ReviewGrantedConsentResult.RECORD_CONTENT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
 
-import static com.android.systemui.mediaprojection.MediaProjectionServiceHelper.OVERRIDE_DISABLE_MEDIA_PROJECTION_SINGLE_APP_OPTION;
 import static com.android.systemui.mediaprojection.permission.ScreenShareOptionKt.ENTIRE_SCREEN;
 import static com.android.systemui.mediaprojection.permission.ScreenShareOptionKt.SINGLE_APP;
 
 import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityOptions.LaunchCookie;
 import android.app.AlertDialog;
 import android.app.StatusBarManager;
-import android.app.compat.CompatChanges;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
@@ -109,7 +104,6 @@
     }
 
     @Override
-    @RequiresPermission(allOf = {READ_COMPAT_CHANGE_CONFIG, LOG_COMPAT_CHANGE})
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
@@ -237,9 +231,6 @@
         // the correct screen width when in split screen.
         Context dialogContext = getApplicationContext();
         if (isPartialScreenSharingEnabled()) {
-            final boolean overrideDisableSingleAppOption = CompatChanges.isChangeEnabled(
-                    OVERRIDE_DISABLE_MEDIA_PROJECTION_SINGLE_APP_OPTION,
-                    mPackageName, getHostUserHandle());
             MediaProjectionPermissionDialogDelegate delegate =
                     new MediaProjectionPermissionDialogDelegate(
                             dialogContext,
@@ -251,7 +242,6 @@
                             },
                             () -> finish(RECORD_CANCEL, /* projection= */ null),
                             appName,
-                            overrideDisableSingleAppOption,
                             mUid,
                             mMediaProjectionMetricsLogger);
             mDialog =
diff --git a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegate.kt
index 9ce8070..0f54e93 100644
--- a/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegate.kt
@@ -30,12 +30,11 @@
     private val onStartRecordingClicked: Consumer<MediaProjectionPermissionDialogDelegate>,
     private val onCancelClicked: Runnable,
     private val appName: String?,
-    forceShowPartialScreenshare: Boolean,
     hostUid: Int,
     mediaProjectionMetricsLogger: MediaProjectionMetricsLogger,
 ) :
     BaseMediaProjectionPermissionDialogDelegate<AlertDialog>(
-        createOptionList(context, appName, mediaProjectionConfig, forceShowPartialScreenshare),
+        createOptionList(context, appName, mediaProjectionConfig),
         appName,
         hostUid,
         mediaProjectionMetricsLogger
@@ -66,8 +65,7 @@
         private fun createOptionList(
             context: Context,
             appName: String?,
-            mediaProjectionConfig: MediaProjectionConfig?,
-            overrideDisableSingleAppOption: Boolean = false,
+            mediaProjectionConfig: MediaProjectionConfig?
         ): List<ScreenShareOption> {
             val singleAppWarningText =
                 if (appName == null) {
@@ -82,13 +80,8 @@
                     R.string.media_projection_entry_app_permission_dialog_warning_entire_screen
                 }
 
-            // The single app option should only be disabled if there is an app name provided,
-            // the client has setup a MediaProjection with
-            // MediaProjectionConfig#createConfigForDefaultDisplay, AND it hasn't been overridden by
-            // the OVERRIDE_DISABLE_SINGLE_APP_OPTION per-app override.
             val singleAppOptionDisabled =
                 appName != null &&
-                    !overrideDisableSingleAppOption &&
                     mediaProjectionConfig?.regionToCapture ==
                         MediaProjectionConfig.CAPTURE_REGION_FIXED_DISPLAY
 
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index aa03e6e..5dd1bd8 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -495,10 +495,6 @@
         return mBehavior != BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
     }
 
-    private boolean isImmersiveMode() {
-        return mBehavior == BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
-    }
-
     public void onConfigurationChanged(Configuration configuration) {
         mEdgeBackGestureHandler.onConfigurationChanged(configuration);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemFactory.kt
index 1c9be0f..f13ecf3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemFactory.kt
@@ -21,6 +21,7 @@
 import android.media.AudioManager
 import com.android.settingslib.bluetooth.BluetoothUtils
 import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.settingslib.flags.Flags
 import com.android.systemui.res.R
 
 private val backgroundOn = R.drawable.settingslib_switch_bar_bg_on
@@ -36,6 +37,7 @@
 /** Factories to create different types of Bluetooth device items from CachedBluetoothDevice. */
 internal abstract class DeviceItemFactory {
     abstract fun isFilterMatched(
+        context: Context,
         cachedDevice: CachedBluetoothDevice,
         audioManager: AudioManager?
     ): Boolean
@@ -45,6 +47,7 @@
 
 internal class ActiveMediaDeviceItemFactory : DeviceItemFactory() {
     override fun isFilterMatched(
+        context: Context,
         cachedDevice: CachedBluetoothDevice,
         audioManager: AudioManager?
     ): Boolean {
@@ -71,6 +74,7 @@
 
 internal class AvailableMediaDeviceItemFactory : DeviceItemFactory() {
     override fun isFilterMatched(
+        context: Context,
         cachedDevice: CachedBluetoothDevice,
         audioManager: AudioManager?
     ): Boolean {
@@ -99,10 +103,18 @@
 
 internal class ConnectedDeviceItemFactory : DeviceItemFactory() {
     override fun isFilterMatched(
+        context: Context,
         cachedDevice: CachedBluetoothDevice,
         audioManager: AudioManager?
     ): Boolean {
-        return BluetoothUtils.isConnectedBluetoothDevice(cachedDevice, audioManager)
+        return if (Flags.enableHideExclusivelyManagedBluetoothDevice()) {
+            !BluetoothUtils.isExclusivelyManagedBluetoothDevice(
+                context,
+                cachedDevice.getDevice()
+            ) && BluetoothUtils.isConnectedBluetoothDevice(cachedDevice, audioManager)
+        } else {
+            BluetoothUtils.isConnectedBluetoothDevice(cachedDevice, audioManager)
+        }
     }
 
     override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem {
@@ -125,10 +137,18 @@
 
 internal class SavedDeviceItemFactory : DeviceItemFactory() {
     override fun isFilterMatched(
+        context: Context,
         cachedDevice: CachedBluetoothDevice,
         audioManager: AudioManager?
     ): Boolean {
-        return cachedDevice.bondState == BluetoothDevice.BOND_BONDED && !cachedDevice.isConnected
+        return if (Flags.enableHideExclusivelyManagedBluetoothDevice()) {
+            !BluetoothUtils.isExclusivelyManagedBluetoothDevice(
+                context,
+                cachedDevice.getDevice()
+            ) && cachedDevice.bondState == BluetoothDevice.BOND_BONDED && !cachedDevice.isConnected
+        } else {
+            cachedDevice.bondState == BluetoothDevice.BOND_BONDED && !cachedDevice.isConnected
+        }
     }
 
     override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractor.kt
index fcd45a6..1df496b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractor.kt
@@ -133,7 +133,7 @@
                 bluetoothTileDialogRepository.cachedDevices
                     .mapNotNull { cachedDevice ->
                         deviceItemFactoryList
-                            .firstOrNull { it.isFilterMatched(cachedDevice, audioManager) }
+                            .firstOrNull { it.isFilterMatched(context, cachedDevice, audioManager) }
                             ?.create(context, cachedDevice)
                     }
                     .sort(displayPriority, bluetoothAdapter?.mostRecentlyConnectedDevices)
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/PanelExpansionInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/PanelExpansionInteractor.kt
new file mode 100644
index 0000000..36350f8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/PanelExpansionInteractor.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.scene.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
+import com.android.systemui.scene.shared.model.ObservableTransitionState
+import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.shade.data.repository.ShadeRepository
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
+
+@SysUISingleton
+class PanelExpansionInteractor
+@Inject
+constructor(
+    sceneInteractor: SceneInteractor,
+    shadeRepository: ShadeRepository,
+) {
+
+    /**
+     * The amount by which the "panel" has been expanded (`0` when fully collapsed, `1` when fully
+     * expanded).
+     *
+     * This is a legacy concept from the time when the "panel" included the notification/QS shades
+     * as well as the keyguard (lockscreen and bouncer). This value is meant only for
+     * backwards-compatibility and should not be consumed by newer code.
+     */
+    @Deprecated("Use SceneInteractor.currentScene instead.")
+    val legacyPanelExpansion: Flow<Float> =
+        if (SceneContainerFlag.isEnabled) {
+            sceneInteractor.transitionState.flatMapLatest { state ->
+                when (state) {
+                    is ObservableTransitionState.Idle ->
+                        flowOf(
+                            if (state.scene != SceneKey.Gone) {
+                                // When resting on a non-Gone scene, the panel is fully expanded.
+                                1f
+                            } else {
+                                // When resting on the Gone scene, the panel is considered fully
+                                // collapsed.
+                                0f
+                            }
+                        )
+                    is ObservableTransitionState.Transition ->
+                        when {
+                            state.fromScene == SceneKey.Gone ->
+                                if (state.toScene.isExpandable()) {
+                                    // Moving from Gone to a scene that can animate-expand has a
+                                    // panel
+                                    // expansion
+                                    // that tracks with the transition.
+                                    state.progress
+                                } else {
+                                    // Moving from Gone to a scene that doesn't animate-expand
+                                    // immediately makes
+                                    // the panel fully expanded.
+                                    flowOf(1f)
+                                }
+                            state.toScene == SceneKey.Gone ->
+                                if (state.fromScene.isExpandable()) {
+                                    // Moving to Gone from a scene that can animate-expand has a
+                                    // panel
+                                    // expansion
+                                    // that tracks with the transition.
+                                    state.progress.map { 1 - it }
+                                } else {
+                                    // Moving to Gone from a scene that doesn't animate-expand
+                                    // immediately makes
+                                    // the panel fully collapsed.
+                                    flowOf(0f)
+                                }
+                            else -> flowOf(1f)
+                        }
+                }
+            }
+        } else {
+            shadeRepository.legacyShadeExpansion
+        }
+
+    private fun SceneKey.isExpandable(): Boolean {
+        return this == SceneKey.Shade || this == SceneKey.QuickSettings
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
index b642d38..034f87f 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
@@ -26,6 +26,7 @@
 import com.android.systemui.bouncer.domain.interactor.SimBouncerInteractor
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.classifier.FalsingCollectorActual
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.DisplayId
@@ -34,6 +35,8 @@
 import com.android.systemui.model.SceneContainerPlugin
 import com.android.systemui.model.SysUiState
 import com.android.systemui.model.updateFlags
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.plugins.FalsingManager.FalsingBeliefListener
 import com.android.systemui.power.domain.interactor.PowerInteractor
 import com.android.systemui.scene.domain.interactor.SceneInteractor
 import com.android.systemui.scene.shared.flag.SceneContainerFlags
@@ -53,6 +56,7 @@
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.collectLatest
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
@@ -82,6 +86,7 @@
     @DisplayId private val displayId: Int,
     private val sceneLogger: SceneLogger,
     @FalsingCollectorActual private val falsingCollector: FalsingCollector,
+    private val falsingManager: FalsingManager,
     private val powerInteractor: PowerInteractor,
     private val simBouncerInteractor: Lazy<SimBouncerInteractor>,
     private val authenticationInteractor: Lazy<AuthenticationInteractor>,
@@ -98,6 +103,7 @@
             automaticallySwitchScenes()
             hydrateSystemUiState()
             collectFalsingSignals()
+            respondToFalsingDetections()
             hydrateWindowFocus()
             hydrateInteractionState()
         } else {
@@ -376,6 +382,18 @@
         }
     }
 
+    /** Switches to the lockscreen when falsing is detected. */
+    private fun respondToFalsingDetections() {
+        applicationScope.launch {
+            conflatedCallbackFlow {
+                    val listener = FalsingBeliefListener { trySend(Unit) }
+                    falsingManager.addFalsingBeliefListener(listener)
+                    awaitClose { falsingManager.removeFalsingBeliefListener(listener) }
+                }
+                .collect { switchToScene(SceneKey.Lockscreen, "Falsing detected.") }
+        }
+    }
+
     /** Keeps the focus state of the window view up-to-date. */
     private fun hydrateWindowFocus() {
         applicationScope.launch {
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/UserActionResult.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/UserActionResult.kt
index e1b96e4..c6ae215 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/UserActionResult.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/UserActionResult.kt
@@ -22,13 +22,6 @@
     val toScene: SceneKey,
 
     /**
-     * The distance the action takes to animate from 0% to 100%.
-     *
-     * If `null`, a default distance will be used depending on the [UserAction] performed.
-     */
-    val distance: UserActionDistance? = null,
-
-    /**
      * The key of the transition that should be used, if a specific one should be used.
      *
      * If `null`, the transition used will be the corresponding transition from the collection
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt
index 45b6f65..ee76c05 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt
@@ -16,11 +16,9 @@
 
 package com.android.systemui.scene.ui.view
 
-import android.view.Gravity
 import android.view.View
 import android.view.ViewGroup
 import android.view.WindowInsets
-import android.widget.FrameLayout
 import androidx.activity.OnBackPressedDispatcher
 import androidx.activity.OnBackPressedDispatcherOwner
 import androidx.activity.setViewTreeOnBackPressedDispatcherOwner
@@ -39,7 +37,6 @@
 import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
 import com.android.systemui.statusbar.notification.stack.shared.flexiNotifsEnabled
 import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
-import java.time.Instant
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.launch
 
@@ -98,7 +95,7 @@
                     )
 
                     val legacyView = view.requireViewById<View>(R.id.legacy_window_root)
-                    view.addView(createVisibilityToggleView(legacyView))
+                    legacyView.isVisible = false
 
                     // This moves the SharedNotificationContainer to the WindowRootView just after
                     //  the SceneContainerView. This SharedNotificationContainer should contain NSSL
@@ -123,29 +120,4 @@
             }
         }
     }
-
-    private var clickCount = 0
-    private var lastClick = Instant.now()
-
-    /**
-     * A temporary UI to toggle on/off the visibility of the given [otherView]. It is toggled by
-     * tapping 5 times in quick succession on the device camera (top center).
-     */
-    // TODO(b/291321285): Remove this when the Flexiglass UI is mature enough to turn off legacy
-    //  SysUI altogether.
-    private fun createVisibilityToggleView(otherView: View): View {
-        val toggleView = View(otherView.context)
-        otherView.isVisible = false
-        toggleView.layoutParams = FrameLayout.LayoutParams(200, 200, Gravity.CENTER_HORIZONTAL)
-        toggleView.setOnClickListener {
-            val now = Instant.now()
-            clickCount = if (now.minusSeconds(2) > lastClick) 1 else clickCount + 1
-            if (clickCount == 5) {
-                otherView.isVisible = !otherView.isVisible
-                clickCount = 0
-            }
-            lastClick = now
-        }
-        return toggleView
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
index bee3152..fb5339d 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt
@@ -31,10 +31,13 @@
 import android.view.WindowManagerGlobal
 import com.android.app.tracing.coroutines.launch
 import com.android.internal.infra.ServiceConnector
+import com.android.systemui.Flags.screenshotActionDismissSystemWindows
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.settings.DisplayTracker
+import com.android.systemui.shared.system.ActivityManagerWrapper
+import com.android.systemui.statusbar.phone.CentralSurfaces
 import javax.inject.Inject
 import kotlinx.coroutines.CompletableDeferred
 import kotlinx.coroutines.CoroutineDispatcher
@@ -46,9 +49,11 @@
 @Inject
 constructor(
     private val context: Context,
+    private val activityManagerWrapper: ActivityManagerWrapper,
     @Application private val applicationScope: CoroutineScope,
     @Main private val mainDispatcher: CoroutineDispatcher,
     private val displayTracker: DisplayTracker,
+    private val keyguardController: ScreenshotKeyguardController,
 ) {
     /**
      * Execute the given intent with startActivity while performing operations for screenshot action
@@ -74,7 +79,14 @@
         user: UserHandle,
         overrideTransition: Boolean,
     ) {
-        dismissKeyguard()
+        if (screenshotActionDismissSystemWindows()) {
+            keyguardController.dismiss()
+            activityManagerWrapper.closeSystemWindows(
+                CentralSurfaces.SYSTEM_DIALOG_REASON_SCREENSHOT
+            )
+        } else {
+            dismissKeyguard()
+        }
 
         if (user == myUserHandle()) {
             withContext(mainDispatcher) { context.startActivity(intent, options) }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotKeyguardController.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotKeyguardController.kt
new file mode 100644
index 0000000..7696bbe
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotKeyguardController.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot
+
+import android.content.Context
+import android.content.Intent
+import com.android.internal.infra.ServiceConnector
+import javax.inject.Inject
+import kotlinx.coroutines.CompletableDeferred
+
+open class ScreenshotKeyguardController @Inject constructor(context: Context) {
+    private val proxyConnector: ServiceConnector<IScreenshotProxy> =
+        ServiceConnector.Impl(
+            context,
+            Intent(context, ScreenshotProxyService::class.java),
+            Context.BIND_AUTO_CREATE or Context.BIND_WAIVE_PRIORITY or Context.BIND_NOT_VISIBLE,
+            context.userId,
+            IScreenshotProxy.Stub::asInterface
+        )
+
+    suspend fun dismiss() {
+        val completion = CompletableDeferred<Unit>()
+        val onDoneBinder =
+            object : IOnDoneCallback.Stub() {
+                override fun onDone(success: Boolean) {
+                    completion.complete(Unit)
+                }
+            }
+        proxyConnector.post { it.dismissKeyguard(onDoneBinder) }
+        completion.await()
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
index f2fa0ef..0a1f649 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
@@ -121,7 +121,6 @@
     @GuardedBy("callbacks")
     private val callbacks: MutableList<DataItem> = ArrayList()
 
-    private var beforeUserSwitchingJob: Job? = null
     private var userSwitchingJob: Job? = null
     private var afterUserSwitchingJob: Job? = null
 
@@ -194,14 +193,7 @@
     private fun registerUserSwitchObserver() {
         iActivityManager.registerUserSwitchObserver(object : UserSwitchObserver() {
             override fun onBeforeUserSwitching(newUserId: Int) {
-                if (isBackgroundUserSwitchEnabled) {
-                    beforeUserSwitchingJob?.cancel()
-                    beforeUserSwitchingJob = appScope.launch(backgroundContext) {
-                        handleBeforeUserSwitching(newUserId)
-                    }
-                } else {
-                    handleBeforeUserSwitching(newUserId)
-                }
+                handleBeforeUserSwitching(newUserId)
             }
 
             override fun onUserSwitching(newUserId: Int, reply: IRemoteCallback?) {
@@ -233,15 +225,12 @@
 
     @WorkerThread
     protected open fun handleBeforeUserSwitching(newUserId: Int) {
-        Assert.isNotMainThread()
         setUserIdInternal(newUserId)
 
-        val list = synchronized(callbacks) {
-            callbacks.toList()
-        }
-        list.forEach {
-            it.callback.get()?.onBeforeUserSwitching(newUserId)
-        }
+        notifySubscribers { callback, resultCallback ->
+            callback.onBeforeUserSwitching(newUserId)
+            resultCallback.run()
+        }.await()
     }
 
     @WorkerThread
@@ -249,21 +238,9 @@
         Assert.isNotMainThread()
         Log.i(TAG, "Switching to user $newUserId")
 
-        val list = synchronized(callbacks) {
-            callbacks.toList()
-        }
-        val latch = CountDownLatch(list.size)
-        list.forEach {
-            val callback = it.callback.get()
-            if (callback != null) {
-                it.executor.execute {
-                    callback.onUserChanging(userId, userContext) { latch.countDown() }
-                }
-            } else {
-                latch.countDown()
-            }
-        }
-        latch.await()
+        notifySubscribers { callback, resultCallback ->
+            callback.onUserChanging(newUserId, userContext, resultCallback)
+        }.await()
     }
 
     @WorkerThread
@@ -293,9 +270,9 @@
         Assert.isNotMainThread()
         Log.i(TAG, "Switched to user $newUserId")
 
-        notifySubscribers {
-            onUserChanged(newUserId, userContext)
-            onProfilesChanged(userProfiles)
+        notifySubscribers { callback, _ ->
+            callback.onUserChanged(newUserId, userContext)
+            callback.onProfilesChanged(userProfiles)
         }
     }
 
@@ -307,8 +284,8 @@
         synchronized(mutex) {
             userProfiles = profiles.map { UserInfo(it) } // save a "deep" copy
         }
-        notifySubscribers {
-            onProfilesChanged(profiles)
+        notifySubscribers { callback, _ ->
+            callback.onProfilesChanged(profiles)
         }
     }
 
@@ -324,18 +301,24 @@
         }
     }
 
-    private inline fun notifySubscribers(crossinline action: UserTracker.Callback.() -> Unit) {
+    private inline fun notifySubscribers(
+            crossinline action: (UserTracker.Callback, resultCallback: Runnable) -> Unit
+    ): CountDownLatch {
         val list = synchronized(callbacks) {
             callbacks.toList()
         }
-
+        val latch = CountDownLatch(list.size)
         list.forEach {
-            if (it.callback.get() != null) {
+            val callback = it.callback.get()
+            if (callback != null) {
                 it.executor.execute {
-                    it.callback.get()?.action()
+                    action(callback) { latch.countDown() }
                 }
+            } else {
+                latch.countDown()
             }
         }
+        return latch
     }
 
     override fun dump(pw: PrintWriter, args: Array<out String>) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 7068f5f..d5bbaa5 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -1539,6 +1539,7 @@
 
     @Override
     public void setOpenCloseListener(OpenCloseListener openCloseListener) {
+        SceneContainerFlag.assertInLegacyMode();
         mOpenCloseListener = openCloseListener;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
index ea41912..e6555f2e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
@@ -32,6 +32,7 @@
 import com.android.systemui.log.dagger.ShadeTouchLog;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.scene.domain.interactor.WindowRootViewVisibilityInteractor;
+import com.android.systemui.scene.shared.flag.SceneContainerFlag;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.StatusBarState;
@@ -98,6 +99,7 @@
                 statusBarKeyguardViewManager,
                 notificationShadeWindowController,
                 assistManagerLazy);
+        SceneContainerFlag.assertInLegacyMode();
         mCommandQueue = commandQueue;
         mMainExecutor = mainExecutor;
         mWindowRootViewVisibilityInteractor = windowRootViewVisibilityInteractor;
diff --git a/packages/SystemUI/src/com/android/systemui/shade/transition/ShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/shade/transition/ShadeTransitionController.kt
index 9715070..84afbed 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/transition/ShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/transition/ShadeTransitionController.kt
@@ -19,8 +19,11 @@
 import android.content.Context
 import android.content.res.Configuration
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.plugins.qs.QS
+import com.android.systemui.scene.domain.interactor.PanelExpansionInteractor
+import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.shade.PanelState
 import com.android.systemui.shade.ShadeExpansionChangeEvent
 import com.android.systemui.shade.ShadeExpansionStateManager
@@ -31,21 +34,26 @@
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.statusbar.policy.SplitShadeStateController
+import dagger.Lazy
 import java.io.PrintWriter
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
 
 /** Controls the shade expansion transition on non-lockscreen. */
 @SysUISingleton
 class ShadeTransitionController
 @Inject
 constructor(
+    @Application private val applicationScope: CoroutineScope,
     configurationController: ConfigurationController,
     shadeExpansionStateManager: ShadeExpansionStateManager,
     dumpManager: DumpManager,
     private val context: Context,
     private val scrimShadeTransitionController: ScrimShadeTransitionController,
     private val statusBarStateController: SysuiStatusBarStateController,
-    private val splitShadeStateController: SplitShadeStateController
+    private val splitShadeStateController: SplitShadeStateController,
+    private val panelExpansionInteractor: Lazy<PanelExpansionInteractor>,
 ) {
 
     lateinit var shadeViewController: ShadeViewController
@@ -63,11 +71,27 @@
                 override fun onConfigChanged(newConfig: Configuration?) {
                     updateResources()
                 }
-            })
-        val currentState =
-            shadeExpansionStateManager.addExpansionListener(this::onPanelExpansionChanged)
-        onPanelExpansionChanged(currentState)
-        shadeExpansionStateManager.addStateListener(this::onPanelStateChanged)
+            }
+        )
+        if (SceneContainerFlag.isEnabled) {
+            applicationScope.launch {
+                panelExpansionInteractor.get().legacyPanelExpansion.collect { panelExpansion ->
+                    onPanelExpansionChanged(
+                        ShadeExpansionChangeEvent(
+                            fraction = panelExpansion,
+                            expanded = panelExpansion > 0f,
+                            tracking = true,
+                            dragDownPxAmount = 0f,
+                        )
+                    )
+                }
+            }
+        } else {
+            val currentState =
+                shadeExpansionStateManager.addExpansionListener(this::onPanelExpansionChanged)
+            onPanelExpansionChanged(currentState)
+            shadeExpansionStateManager.addStateListener(this::onPanelStateChanged)
+        }
         dumpManager.registerCriticalDumpable("ShadeTransitionController") { printWriter, _ ->
             dump(printWriter)
         }
@@ -98,7 +122,9 @@
                 qs.isInitialized: ${this::qs.isInitialized}
                 npvc.isInitialized: ${this::shadeViewController.isInitialized}
                 nssl.isInitialized: ${this::notificationStackScrollLayoutController.isInitialized}
-            """.trimIndent())
+            """
+                .trimIndent()
+        )
     }
 
     private fun isScreenUnlocked() =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 3908ede..ca19f71 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -615,7 +615,14 @@
             args.argi2 = state1;
             args.argi3 = state2;
             args.argi4 = animate ? 1 : 0;
-            mHandler.obtainMessage(MSG_DISABLE, args).sendToTarget();
+            Message msg = mHandler.obtainMessage(MSG_DISABLE, args);
+            if (Looper.myLooper() == mHandler.getLooper()) {
+                // If its the right looper execute immediately so hides can be handled quickly.
+                mHandler.handleMessage(msg);
+                msg.recycle();
+            } else {
+                msg.sendToTarget();
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
index 599600d6..0fd0555 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -39,7 +39,6 @@
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.settingslib.Utils
 import com.android.systemui.Dumpable
-import com.android.systemui.res.R
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
@@ -54,6 +53,7 @@
 import com.android.systemui.plugins.FalsingManager
 import com.android.systemui.plugins.clocks.WeatherData
 import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.res.R
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.shared.regionsampling.RegionSampler
 import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.DATE_SMARTSPACE_DATA_PLUGIN
@@ -68,11 +68,14 @@
 import com.android.systemui.util.time.SystemClock
 import java.io.PrintWriter
 import java.time.Instant
+import java.util.Deque
+import java.util.LinkedList
 import java.util.Optional
 import java.util.concurrent.Executor
 import javax.inject.Inject
 import javax.inject.Named
 
+
 /** Controller for managing the smartspace view on the lockscreen */
 @SysUISingleton
 class LockscreenSmartspaceController
@@ -106,6 +109,8 @@
 ) : Dumpable {
     companion object {
         private const val TAG = "LockscreenSmartspaceController"
+
+        private const val MAX_RECENT_SMARTSPACE_DATA_FOR_DUMP = 5
     }
 
     private var session: SmartspaceSession? = null
@@ -114,6 +119,9 @@
     private val plugin: BcSmartspaceDataPlugin? = optionalPlugin.orElse(null)
     private val configPlugin: BcSmartspaceConfigPlugin? = optionalConfigPlugin.orElse(null)
 
+    // This stores recently received Smartspace pushes to be included in dumpsys.
+    private val recentSmartspaceData: Deque<List<SmartspaceTarget>> = LinkedList()
+
     // Smartspace can be used on multiple displays, such as when the user casts their screen
     private var smartspaceViews = mutableSetOf<SmartspaceView>()
     private var regionSamplers =
@@ -173,6 +181,7 @@
 
         // The weather data plugin takes unfiltered targets and performs the filtering internally.
         weatherPlugin?.onTargetsAvailable(targets)
+
         val now = Instant.ofEpochMilli(systemClock.currentTimeMillis())
         val weatherTarget = targets.find { t ->
             t.featureType == SmartspaceTarget.FEATURE_WEATHER &&
@@ -201,6 +210,14 @@
         }
 
         val filteredTargets = targets.filter(::filterSmartspaceTarget)
+
+        synchronized(recentSmartspaceData) {
+            recentSmartspaceData.offerLast(filteredTargets)
+            if (recentSmartspaceData.size > MAX_RECENT_SMARTSPACE_DATA_FOR_DUMP) {
+                recentSmartspaceData.pollFirst()
+            }
+        }
+
         plugin?.onTargetsAvailable(filteredTargets)
     }
 
@@ -588,9 +605,26 @@
         return null
     }
 
-    override fun dump(pw: PrintWriter, args: Array<out String>) = pw.asIndenting().run {
-        printCollection("Region Samplers", regionSamplers.values) {
-            it.dump(this)
+    override fun dump(pw: PrintWriter, args: Array<out String>) {
+        pw.asIndenting().run {
+            printCollection("Region Samplers", regionSamplers.values) {
+                it.dump(this)
+            }
+        }
+
+        pw.println("Recent BC Smartspace Targets (most recent first)")
+        synchronized(recentSmartspaceData) {
+            if (recentSmartspaceData.size === 0) {
+                pw.println("   No data\n")
+                return
+            }
+            recentSmartspaceData.descendingIterator().forEachRemaining { smartspaceTargets ->
+                pw.println("   Number of targets: ${smartspaceTargets.size}")
+                for (target in smartspaceTargets) {
+                    pw.println("      $target")
+                }
+                pw.println()
+            }
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ColorUpdateLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ColorUpdateLogger.kt
index c416d43..0f0ab2e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ColorUpdateLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ColorUpdateLogger.kt
@@ -108,7 +108,7 @@
 
         fun trim() {
             if (events.size > maxEventsPerFrame) {
-                events.removeFirst()
+                events.removeAt(0)
                 trimmedEvents++
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
index bd659d2..b9d1dde 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
@@ -53,6 +53,7 @@
         mediaCoordinator: MediaCoordinator,
         preparationCoordinator: PreparationCoordinator,
         remoteInputCoordinator: RemoteInputCoordinator,
+        rowAlertTimeCoordinator: RowAlertTimeCoordinator,
         rowAppearanceCoordinator: RowAppearanceCoordinator,
         stackCoordinator: StackCoordinator,
         shadeEventCoordinator: ShadeEventCoordinator,
@@ -69,9 +70,7 @@
     private val mCoordinators: MutableList<Coordinator> = ArrayList()
     private val mOrderedSections: MutableList<NotifSectioner> = ArrayList()
 
-    /**
-     * Creates all the coordinators.
-     */
+    /** Creates all the coordinators. */
     init {
         // Attach core coordinators.
         mCoreCoordinators.add(dataStoreCoordinator)
@@ -89,6 +88,7 @@
         mCoordinators.add(groupCountCoordinator)
         mCoordinators.add(groupWhenCoordinator)
         mCoordinators.add(mediaCoordinator)
+        mCoordinators.add(rowAlertTimeCoordinator)
         mCoordinators.add(rowAppearanceCoordinator)
         mCoordinators.add(stackCoordinator)
         mCoordinators.add(shadeEventCoordinator)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinator.kt
new file mode 100644
index 0000000..4a7b7ca
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinator.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2024 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.collection.coordinator
+
+import android.util.ArrayMap
+import com.android.systemui.statusbar.notification.collection.GroupEntry
+import com.android.systemui.statusbar.notification.collection.ListEntry
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
+import com.android.systemui.statusbar.notification.collection.render.NotifRowController
+import javax.inject.Inject
+import kotlin.math.max
+
+/**
+ * A small coordinator which ensures the "alerted" bell shows not just for recently alerted entries,
+ * but also on the summary for every such entry.
+ */
+@CoordinatorScope
+class RowAlertTimeCoordinator @Inject constructor() : Coordinator {
+
+    private val latestAlertTimeBySummary = ArrayMap<NotificationEntry, Long>()
+
+    override fun attach(pipeline: NotifPipeline) {
+        pipeline.addOnBeforeFinalizeFilterListener(::onBeforeFinalizeFilterListener)
+        pipeline.addOnAfterRenderEntryListener(::onAfterRenderEntry)
+    }
+
+    private fun onBeforeFinalizeFilterListener(entries: List<ListEntry>) {
+        latestAlertTimeBySummary.clear()
+        entries.asSequence().filterIsInstance<GroupEntry>().forEach { groupEntry ->
+            val summary = checkNotNull(groupEntry.summary)
+            latestAlertTimeBySummary[summary] = groupEntry.calculateLatestAlertTime()
+        }
+    }
+
+    private fun onAfterRenderEntry(entry: NotificationEntry, controller: NotifRowController) {
+        // Show the "alerted" bell icon based on the latest group member for summaries
+        val lastAudiblyAlerted = latestAlertTimeBySummary[entry] ?: entry.lastAudiblyAlertedMs
+        controller.setLastAudibleMs(lastAudiblyAlerted)
+    }
+
+    private fun GroupEntry.calculateLatestAlertTime(): Long {
+        val lastChildAlertedTime = children.maxOfOrNull { it.lastAudiblyAlertedMs } ?: 0
+        val summaryAlertedTime = checkNotNull(summary).lastAudiblyAlertedMs
+        return max(lastChildAlertedTime, summaryAlertedTime)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinator.kt
index f2b8482..df694bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinator.kt
@@ -75,7 +75,5 @@
                 (mAutoExpandFirstNotification && entry == entryToExpand))
         // Show/hide the feedback icon
         controller.setFeedbackIcon(mAssistantFeedbackController.getFeedbackIcon(entry))
-        // Show the "alerted" bell icon
-        controller.setLastAudibleMs(entry.lastAudiblyAlertedMs)
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
index 8189fe0..dfe6cd5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/VisualStabilityCoordinator.java
@@ -25,6 +25,7 @@
 
 import com.android.systemui.Dumpable;
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -92,7 +93,7 @@
 
     @Inject
     public VisualStabilityCoordinator(
-            DelayableExecutor delayableExecutor,
+            @Background DelayableExecutor delayableExecutor,
             DumpManager dumpManager,
             HeadsUpManager headsUpManager,
             ShadeAnimationInteractor shadeAnimationInteractor,
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 510086d..dc9eeb3 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
@@ -191,11 +191,11 @@
     public boolean shouldBubbleUp(NotificationEntry entry) {
         final StatusBarNotification sbn = entry.getSbn();
 
-        if (!canAlertCommon(entry, true)) {
+        if (!canAlertCommon(entry, false)) {
             return false;
         }
 
-        if (!canAlertAwakeCommon(entry, true)) {
+        if (!canAlertAwakeCommon(entry, false)) {
             return false;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index d828ad7..decb244 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -849,6 +849,7 @@
     public void setNotificationGroupWhen(long whenMillis) {
         if (mIsSummaryWithChildren) {
             mChildrenContainer.setNotificationGroupWhen(whenMillis);
+            mPublicLayout.setNotificationWhen(whenMillis);
         } else {
             Log.w(TAG, "setNotificationGroupWhen( whenMillis: " + whenMillis + ")"
                     + " mIsSummaryWithChildren: false"
@@ -2704,6 +2705,7 @@
     }
 
     private void onAttachedChildrenCountChanged() {
+        final boolean wasSummary = mIsSummaryWithChildren;
         mIsSummaryWithChildren = mChildrenContainer != null
                 && mChildrenContainer.getNotificationChildCount() > 0;
         if (mIsSummaryWithChildren) {
@@ -2714,6 +2716,10 @@
                         isConversation());
             }
         }
+        if (!mIsSummaryWithChildren && wasSummary) {
+            // Reset the 'when' once the row stops being a summary
+            mPublicLayout.setNotificationWhen(mEntry.getSbn().getNotification().when);
+        }
         getShowingLayout().updateBackgroundColor(false /* animate */);
         mPrivateLayout.updateExpandButtons(isExpandable());
         updateChildrenAppearance();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 402ea51..3742482 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -59,6 +59,7 @@
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
 import com.android.systemui.statusbar.notification.row.shared.AsyncHybridViewInflation;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationCustomViewWrapper;
+import com.android.systemui.statusbar.notification.row.wrapper.NotificationHeaderViewWrapper;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
 import com.android.systemui.statusbar.policy.InflatedSmartReplyState;
 import com.android.systemui.statusbar.policy.InflatedSmartReplyViewHolder;
@@ -2314,6 +2315,13 @@
         return false;
     }
 
+    public void setNotificationWhen(long whenMillis) {
+        NotificationViewWrapper wrapper = getNotificationViewWrapper();
+        if (wrapper instanceof NotificationHeaderViewWrapper headerViewWrapper) {
+            headerViewWrapper.setNotificationWhen(whenMillis);
+        }
+    }
+
     private static class RemoteInputViewData {
         @Nullable RemoteInputView mView;
         @Nullable RemoteInputViewController mController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaContainerView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaContainerView.kt
index bae5baa..5551ab4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaContainerView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/MediaContainerView.kt
@@ -22,6 +22,8 @@
 import android.graphics.Path
 import android.graphics.RectF
 import android.util.AttributeSet
+import android.util.Log
+import com.android.systemui.Flags
 import com.android.systemui.res.R
 import com.android.systemui.statusbar.notification.row.ExpandableView
 
@@ -87,4 +89,63 @@
     ) {
         // No animation, it doesn't need it, this would be local
     }
+
+    override fun setVisibility(visibility: Int) {
+        if (Flags.bindKeyguardMediaVisibility()) {
+            if (isVisibilityValid(visibility)) {
+                super.setVisibility(visibility)
+            }
+        } else {
+            super.setVisibility(visibility)
+        }
+
+        assertMediaContainerVisibility(visibility)
+    }
+
+    /**
+     * visibility should be aligned with MediaContainerView visibility on the keyguard.
+     */
+    private fun isVisibilityValid(visibility: Int): Boolean {
+        val currentViewState = viewState as? MediaContainerViewState ?: return true
+        val shouldBeGone = !currentViewState.shouldBeVisible
+        return if (shouldBeGone) visibility == GONE else visibility != GONE
+    }
+
+    /**
+     * b/298213983
+     * MediaContainerView's visibility is changed to VISIBLE when it should be GONE.
+     * This method check this state and logs.
+     */
+    private fun assertMediaContainerVisibility(visibility: Int) {
+        val currentViewState = viewState
+
+        if (currentViewState is MediaContainerViewState) {
+            if (!currentViewState.shouldBeVisible && visibility == VISIBLE) {
+                Log.wtf("MediaContainerView", "MediaContainerView should be GONE " +
+                        "but its visibility changed to VISIBLE")
+            }
+        }
+    }
+
+    fun setKeyguardVisibility(isVisible: Boolean) {
+        val currentViewState = viewState
+        if (currentViewState is MediaContainerViewState) {
+            currentViewState.shouldBeVisible = isVisible
+        }
+
+        visibility = if (isVisible) VISIBLE else GONE
+    }
+
+    override fun createExpandableViewState(): ExpandableViewState = MediaContainerViewState()
+
+    class MediaContainerViewState : ExpandableViewState() {
+        var shouldBeVisible: Boolean = false
+
+        override fun copyFrom(viewState: ViewState) {
+            super.copyFrom(viewState)
+            if (viewState is MediaContainerViewState) {
+                shouldBeVisible = viewState.shouldBeVisible
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/shared/SceneContainerFlagsExtension.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/shared/SceneContainerFlagsExtension.kt
index 5a71bd6..7dfd53e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/shared/SceneContainerFlagsExtension.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/shared/SceneContainerFlagsExtension.kt
@@ -18,7 +18,7 @@
 
 import com.android.systemui.scene.shared.flag.SceneContainerFlags
 
-private const val FLEXI_NOTIFS = false
+private const val FLEXI_NOTIFS = true
 
 /**
  * Returns whether flexiglass is displaying notifications, which is currently an optional piece of
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
index 5191053..566c030 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
@@ -75,6 +75,24 @@
                 }
             }
 
+        // Required to capture keyguard media changes and ensure the notification count is correct
+        val layoutChangeListener =
+            object : View.OnLayoutChangeListener {
+                override fun onLayoutChange(
+                    view: View,
+                    left: Int,
+                    top: Int,
+                    right: Int,
+                    bottom: Int,
+                    oldLeft: Int,
+                    oldTop: Int,
+                    oldRight: Int,
+                    oldBottom: Int
+                ) {
+                    viewModel.notificationStackChanged()
+                }
+            }
+
         val burnInParams = MutableStateFlow(BurnInParameters())
         val viewState =
             ViewStateAccessor(
@@ -170,6 +188,7 @@
             }
             insets
         }
+        view.addOnLayoutChangeListener(layoutChangeListener)
 
         return object : DisposableHandle {
             override fun dispose() {
@@ -177,6 +196,7 @@
                 disposableHandleMainImmediate.dispose()
                 controller.setOnHeightChangedRunnable(null)
                 view.setOnApplyWindowInsetsListener(null)
+                view.removeOnLayoutChangeListener(layoutChangeListener)
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
index 9052409..a1fae03 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -39,11 +39,11 @@
 import com.android.keyguard.AuthKeyguardMessageArea;
 import com.android.systemui.Dumpable;
 import com.android.systemui.animation.ActivityTransitionAnimator;
+import com.android.systemui.animation.RemoteAnimationRunnerCompat;
 import com.android.systemui.display.data.repository.DisplayMetricsRepository;
 import com.android.systemui.navigationbar.NavigationBarView;
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 import com.android.systemui.qs.QSPanelController;
-import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.util.Compile;
 
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 b07ba3c..a155e94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -67,7 +67,7 @@
     private static final String TAG = "HeadsUpManagerPhone";
 
     @VisibleForTesting
-    final int mExtensionTime;
+    public final int mExtensionTime;
     private final KeyguardBypassController mBypassController;
     private final GroupMembershipManager mGroupMembershipManager;
     private final List<OnHeadsUpPhoneListenerChange> mHeadsUpPhoneListeners = new ArrayList<>();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 5a8b636..d975009 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -22,6 +22,7 @@
 import android.app.ActivityTaskManager;
 import android.app.AlarmManager;
 import android.app.AlarmManager.AlarmClockInfo;
+import android.app.NotificationManager;
 import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -379,7 +380,7 @@
     }
 
     @Override
-    public void onConfigChanged(ZenModeConfig config) {
+    public void onConsolidatedPolicyChanged(NotificationManager.Policy policy) {
         updateVolumeZen();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 4fd33ba..5610ed9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -55,6 +55,7 @@
 import com.android.systemui.animation.ActivityTransitionAnimator;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.DisplayId;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.power.domain.interactor.PowerInteractor;
@@ -138,7 +139,7 @@
             Context context,
             @DisplayId int displayId,
             Handler mainThreadHandler,
-            Executor uiBgExecutor,
+            @Background Executor uiBgExecutor,
             NotificationVisibilityProvider visibilityProvider,
             HeadsUpManager headsUpManager,
             ActivityStarter activityStarter,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt
index f73d089..3e3ea85 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/data/prod/DeviceBasedSatelliteRepositoryImpl.kt
@@ -315,8 +315,8 @@
         // TTL for satellite polling is one hour
         const val POLLING_INTERVAL_MS: Long = 1000 * 60 * 60
 
-        // Let the system boot up (5s) and stabilize before we check for system support
-        const val MIN_UPTIME: Long = 1000 * 5
+        // Let the system boot up and stabilize before we check for system support
+        const val MIN_UPTIME: Long = 1000 * 60
 
         private const val TAG = "DeviceBasedSatelliteRepo"
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryStateNotifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryStateNotifier.kt
index a078dd5..2ad4d36 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryStateNotifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryStateNotifier.kt
@@ -23,6 +23,7 @@
 import android.content.Context
 import android.content.Intent
 import android.net.Uri
+import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.res.R
 import com.android.systemui.util.concurrency.DelayableExecutor
 import javax.inject.Inject
@@ -34,7 +35,7 @@
 class BatteryStateNotifier @Inject constructor(
     val controller: BatteryController,
     val noMan: NotificationManager,
-    val delayableExecutor: DelayableExecutor,
+    @Background val delayableExecutor: DelayableExecutor,
     val context: Context
 ) : BatteryController.BatteryStateChangeCallback {
     var stateUnknown = false
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java
index 6956a7d..18ec68b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java
@@ -51,6 +51,7 @@
 public class SensitiveNotificationProtectionControllerImpl
         implements SensitiveNotificationProtectionController {
     private static final String LOG_TAG = "SNPC";
+    private final SensitiveNotificationProtectionControllerLogger mLogger;
     private final ArraySet<String> mExemptPackages = new ArraySet<>();
     private final ListenerSet<Runnable> mListeners = new ListenerSet<>();
     private volatile MediaProjectionInfo mProjection;
@@ -66,6 +67,7 @@
                         if (mDisableScreenShareProtections) {
                             Log.w(LOG_TAG,
                                     "Screen share protections disabled, ignoring projectionstart");
+                            mLogger.logProjectionStart(false, info.getPackageName());
                             return;
                         }
 
@@ -73,6 +75,7 @@
                         // Launch cookie only set (non-null) if sharing single app/task
                         updateProjectionStateAndNotifyListeners(
                                 (info.getLaunchCookie() == null) ? info : null);
+                        mLogger.logProjectionStart(isSensitiveStateActive(), info.getPackageName());
                     } finally {
                         Trace.endSection();
                     }
@@ -82,6 +85,7 @@
                 public void onStop(MediaProjectionInfo info) {
                     Trace.beginSection("SNPC.onProjectionStop");
                     try {
+                        mLogger.logProjectionStop();
                         updateProjectionStateAndNotifyListeners(null);
                     } finally {
                         Trace.endSection();
@@ -96,7 +100,10 @@
             MediaProjectionManager mediaProjectionManager,
             IActivityManager activityManager,
             @Main Handler mainHandler,
-            @Background Executor bgExecutor) {
+            @Background Executor bgExecutor,
+            SensitiveNotificationProtectionControllerLogger logger) {
+        mLogger = logger;
+
         if (!screenshareNotificationHiding()) {
             return;
         }
@@ -202,8 +209,6 @@
             return false;
         }
 
-        // TODO(b/316955558): Add disabled by developer option
-
         return !mExemptPackages.contains(projection.getPackageName());
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerLogger.kt
new file mode 100644
index 0000000..70c5239
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerLogger.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2024 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.policy
+
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.core.LogLevel
+import com.android.systemui.log.dagger.SensitiveNotificationProtectionLog
+import javax.inject.Inject
+
+/** Logger for [SensitiveNotificationProtectionController]. */
+class SensitiveNotificationProtectionControllerLogger
+@Inject
+constructor(@SensitiveNotificationProtectionLog private val buffer: LogBuffer) {
+    fun logProjectionStart(protectionEnabled: Boolean, pkg: String) {
+        buffer.log(
+            TAG,
+            LogLevel.DEBUG,
+            {
+                bool1 = protectionEnabled
+                str1 = pkg
+            },
+            { "Projection started - protection enabled:$bool1, pkg=$str1" }
+        )
+    }
+
+    fun logProjectionStop() {
+        buffer.log(TAG, LogLevel.DEBUG, {}, { "Projection ended - protection disabled" })
+    }
+}
+
+private const val TAG = "SNPC"
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
index 6124f63..2cad844 100644
--- a/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
@@ -124,15 +124,6 @@
     }
 
     /**
-     * Provide a Background-Thread Executor by default.
-     */
-    @Provides
-    @SysUISingleton
-    public static Executor provideExecutor(@Background Looper looper) {
-        return new ExecutorImpl(looper);
-    }
-
-    /**
      * Provide a BroadcastRunning Executor (for sending and receiving broadcasts).
      */
     @Provides
@@ -174,15 +165,6 @@
     }
 
     /**
-     * Provide a Background-Thread Executor by default.
-     */
-    @Provides
-    @SysUISingleton
-    public static DelayableExecutor provideDelayableExecutor(@Background Looper looper) {
-        return new ExecutorImpl(looper);
-    }
-
-    /**
      * Provide a Background-Thread Executor.
      */
     @Provides
@@ -193,15 +175,6 @@
     }
 
     /**
-     * Provide a Background-Thread Executor by default.
-     */
-    @Provides
-    @SysUISingleton
-    public static RepeatableExecutor provideRepeatableExecutor(@Background DelayableExecutor exec) {
-        return new RepeatableExecutorImpl(exec);
-    }
-
-    /**
      * Provide a Background-Thread Executor.
      */
     @Provides
diff --git a/packages/SystemUI/src/com/android/systemui/util/service/ObservableServiceConnection.java b/packages/SystemUI/src/com/android/systemui/util/service/ObservableServiceConnection.java
index 3d724e1..0dcbe9b2 100644
--- a/packages/SystemUI/src/com/android/systemui/util/service/ObservableServiceConnection.java
+++ b/packages/SystemUI/src/com/android/systemui/util/service/ObservableServiceConnection.java
@@ -158,11 +158,11 @@
         try {
             bindResult = mContext.bindServiceAsUser(mServiceIntent, this, mFlags,
                     mUserTracker.getUserHandle());
+            mBoundCalled = true;
         } catch (SecurityException e) {
             Log.d(TAG, "Could not bind to service", e);
             mContext.unbindService(this);
         }
-        mBoundCalled = true;
         if (DEBUG) {
             Log.d(TAG, "bind. bound:" + bindResult);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/util/service/PersistentConnectionManager.java b/packages/SystemUI/src/com/android/systemui/util/service/PersistentConnectionManager.java
index 9b72eb7..5979f3e 100644
--- a/packages/SystemUI/src/com/android/systemui/util/service/PersistentConnectionManager.java
+++ b/packages/SystemUI/src/com/android/systemui/util/service/PersistentConnectionManager.java
@@ -28,6 +28,7 @@
 import androidx.annotation.NonNull;
 
 import com.android.systemui.Dumpable;
+import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 import com.android.systemui.util.time.SystemClock;
@@ -94,10 +95,12 @@
         }
     };
 
+    // TODO: b/326449074 - Ensure the DelayableExecutor is on the correct thread, and update the
+    //                     qualifier (to @Main) or name (to bgExecutor) to be consistent with that.
     @Inject
     public PersistentConnectionManager(
             SystemClock clock,
-            DelayableExecutor mainExecutor,
+            @Background DelayableExecutor mainExecutor,
             DumpManager dumpManager,
             @Named(DUMPSYS_NAME) String dumpsysName,
             @Named(SERVICE_CONNECTION) ObservableServiceConnection<T> serviceConnection,
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.kt b/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.kt
index 8431fbc..9dedf5c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/AudioModule.kt
@@ -18,9 +18,6 @@
 
 import android.content.Context
 import android.media.AudioManager
-import com.android.settingslib.media.data.repository.SpatializerRepository
-import com.android.settingslib.media.data.repository.SpatializerRepositoryImpl
-import com.android.settingslib.media.domain.interactor.SpatializerInteractor
 import com.android.settingslib.statusbar.notification.domain.interactor.NotificationsSoundPolicyInteractor
 import com.android.settingslib.volume.data.repository.AudioRepository
 import com.android.settingslib.volume.data.repository.AudioRepositoryImpl
@@ -66,16 +63,5 @@
             notificationsSoundPolicyInteractor: NotificationsSoundPolicyInteractor,
         ): AudioVolumeInteractor =
             AudioVolumeInteractor(audioRepository, notificationsSoundPolicyInteractor)
-
-        @Provides
-        fun provdieSpatializerRepository(
-            audioManager: AudioManager,
-            @Background backgroundContext: CoroutineContext,
-        ): SpatializerRepository =
-            SpatializerRepositoryImpl(audioManager.spatializer, backgroundContext)
-
-        @Provides
-        fun provideSpatializerInetractor(repository: SpatializerRepository): SpatializerInteractor =
-            SpatializerInteractor(repository)
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/SpatializerModule.kt b/packages/SystemUI/src/com/android/systemui/volume/dagger/SpatializerModule.kt
new file mode 100644
index 0000000..593b90a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/SpatializerModule.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2024 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.volume.dagger
+
+import android.media.AudioManager
+import android.media.Spatializer
+import com.android.settingslib.media.data.repository.SpatializerRepository
+import com.android.settingslib.media.data.repository.SpatializerRepositoryImpl
+import com.android.settingslib.media.domain.interactor.SpatializerInteractor
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import dagger.Module
+import dagger.Provides
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CoroutineScope
+
+/** Spatializer module. */
+@Module
+interface SpatializerModule {
+
+    companion object {
+
+        @Provides
+        fun provideSpatializer(
+            audioManager: AudioManager,
+        ): Spatializer = audioManager.spatializer
+
+        @Provides
+        fun provdieSpatializerRepository(
+            spatializer: Spatializer,
+            @Application scope: CoroutineScope,
+            @Background backgroundContext: CoroutineContext,
+        ): SpatializerRepository = SpatializerRepositoryImpl(spatializer, scope, backgroundContext)
+
+        @Provides
+        fun provideSpatializerInetractor(repository: SpatializerRepository): SpatializerInteractor =
+            SpatializerInteractor(repository)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
index c6aee42..64a5644 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/dagger/VolumeModule.java
@@ -59,7 +59,8 @@
                 AudioModule.class,
                 AncModule.class,
                 CaptioningModule.class,
-                MediaDevicesModule.class
+                MediaDevicesModule.class,
+                SpatializerModule.class,
         },
         subcomponents = {
                 VolumePanelComponent.class
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/shared/model/VolumePanelComponents.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/shared/model/VolumePanelComponents.kt
index f11ac5e..9d801fc 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/shared/model/VolumePanelComponents.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/shared/model/VolumePanelComponents.kt
@@ -22,6 +22,7 @@
 
     const val MEDIA_OUTPUT: VolumePanelComponentKey = "media_output"
     const val BOTTOM_BAR: VolumePanelComponentKey = "bottom_bar"
+    const val VOLUME_SLIDERS: VolumePanelComponentKey = "volume_sliders"
     const val CAPTIONING: VolumePanelComponentKey = "captioning"
     const val ANC: VolumePanelComponentKey = "anc"
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/SpatialAudioAvailabilityCriteria.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/SpatialAudioAvailabilityCriteria.kt
new file mode 100644
index 0000000..71bce5e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/SpatialAudioAvailabilityCriteria.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 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.volume.panel.component.spatial.domain
+
+import com.android.systemui.volume.panel.component.spatial.domain.interactor.SpatialAudioComponentInteractor
+import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioAvailabilityModel
+import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
+import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+
+@VolumePanelScope
+class SpatialAudioAvailabilityCriteria
+@Inject
+constructor(private val interactor: SpatialAudioComponentInteractor) :
+    ComponentAvailabilityCriteria {
+
+    override fun isAvailable(): Flow<Boolean> =
+        interactor.isAvailable.map { it is SpatialAudioAvailabilityModel.SpatialAudio }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractor.kt
new file mode 100644
index 0000000..4358611
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/interactor/SpatialAudioComponentInteractor.kt
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2024 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.volume.panel.component.spatial.domain.interactor
+
+import android.media.AudioDeviceAttributes
+import android.media.AudioDeviceInfo
+import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.settingslib.media.BluetoothMediaDevice
+import com.android.settingslib.media.domain.interactor.SpatializerInteractor
+import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor
+import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioAvailabilityModel
+import com.android.systemui.volume.panel.component.spatial.domain.model.SpatialAudioEnabledModel
+import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.stateIn
+
+/**
+ * Provides an ability to access and update spatial audio and head tracking state.
+ *
+ * Head tracking is a sub-feature of spatial audio. This means that it requires spatial audio to be
+ * available for it to be available. And spatial audio to be enabled for it to be enabled.
+ */
+@VolumePanelScope
+class SpatialAudioComponentInteractor
+@Inject
+constructor(
+    mediaOutputInteractor: MediaOutputInteractor,
+    private val spatializerInteractor: SpatializerInteractor,
+    @VolumePanelScope private val coroutineScope: CoroutineScope,
+) {
+
+    private val changes = MutableSharedFlow<Unit>()
+    private val currentAudioDeviceAttributes: StateFlow<AudioDeviceAttributes?> =
+        mediaOutputInteractor.currentConnectedDevice
+            .map { mediaDevice ->
+                mediaDevice ?: return@map null
+                val btDevice: CachedBluetoothDevice =
+                    (mediaDevice as? BluetoothMediaDevice)?.cachedDevice ?: return@map null
+                btDevice.getAudioDeviceAttributes()
+            }
+            .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), null)
+
+    /**
+     * Returns spatial audio availability model. It can be:
+     * - unavailable
+     * - only spatial audio is available
+     * - spatial audio and head tracking are available
+     */
+    val isAvailable: StateFlow<SpatialAudioAvailabilityModel> =
+        combine(
+                currentAudioDeviceAttributes,
+                changes.onStart { emit(Unit) },
+                spatializerInteractor.isHeadTrackingAvailable,
+            ) { attributes, _, isHeadTrackingAvailable ->
+                attributes ?: return@combine SpatialAudioAvailabilityModel.Unavailable
+                if (isHeadTrackingAvailable) {
+                    return@combine SpatialAudioAvailabilityModel.HeadTracking
+                }
+                if (spatializerInteractor.isSpatialAudioAvailable(attributes)) {
+                    return@combine SpatialAudioAvailabilityModel.SpatialAudio
+                }
+                SpatialAudioAvailabilityModel.Unavailable
+            }
+            .stateIn(
+                coroutineScope,
+                SharingStarted.Eagerly,
+                SpatialAudioAvailabilityModel.Unavailable,
+            )
+
+    /**
+     * Returns spatial audio enabled/disabled model. It can be
+     * - disabled
+     * - only spatial audio is enabled
+     * - spatial audio and head tracking are enabled
+     */
+    val isEnabled: StateFlow<SpatialAudioEnabledModel> =
+        combine(
+                changes.onStart { emit(Unit) },
+                currentAudioDeviceAttributes,
+                isAvailable,
+            ) { _, attributes, isAvailable ->
+                if (isAvailable is SpatialAudioAvailabilityModel.Unavailable) {
+                    return@combine SpatialAudioEnabledModel.Disabled
+                }
+                attributes ?: return@combine SpatialAudioEnabledModel.Disabled
+                if (spatializerInteractor.isHeadTrackingEnabled(attributes)) {
+                    return@combine SpatialAudioEnabledModel.HeadTrackingEnabled
+                }
+                if (spatializerInteractor.isSpatialAudioEnabled(attributes)) {
+                    return@combine SpatialAudioEnabledModel.SpatialAudioEnabled
+                }
+                SpatialAudioEnabledModel.Disabled
+            }
+            .stateIn(
+                coroutineScope,
+                SharingStarted.Eagerly,
+                SpatialAudioEnabledModel.Disabled,
+            )
+
+    /**
+     * Sets current [isEnabled] to a specific [SpatialAudioEnabledModel]. It
+     * - disables both spatial audio and head tracking
+     * - enables only spatial audio
+     * - enables both spatial audio and head tracking
+     */
+    suspend fun setEnabled(model: SpatialAudioEnabledModel) {
+        val attributes = currentAudioDeviceAttributes.value ?: return
+        spatializerInteractor.setSpatialAudioEnabled(
+            attributes,
+            model is SpatialAudioEnabledModel.SpatialAudioEnabled,
+        )
+        spatializerInteractor.setHeadTrackingEnabled(
+            attributes,
+            model is SpatialAudioEnabledModel.HeadTrackingEnabled,
+        )
+        changes.emit(Unit)
+    }
+
+    private suspend fun CachedBluetoothDevice.getAudioDeviceAttributes(): AudioDeviceAttributes? {
+        return listOf(
+                AudioDeviceAttributes(
+                    AudioDeviceAttributes.ROLE_OUTPUT,
+                    AudioDeviceInfo.TYPE_BLE_HEADSET,
+                    address
+                ),
+                AudioDeviceAttributes(
+                    AudioDeviceAttributes.ROLE_OUTPUT,
+                    AudioDeviceInfo.TYPE_BLE_SPEAKER,
+                    address
+                ),
+                AudioDeviceAttributes(
+                    AudioDeviceAttributes.ROLE_OUTPUT,
+                    AudioDeviceInfo.TYPE_BLE_BROADCAST,
+                    address
+                ),
+                AudioDeviceAttributes(
+                    AudioDeviceAttributes.ROLE_OUTPUT,
+                    AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
+                    address
+                ),
+                AudioDeviceAttributes(
+                    AudioDeviceAttributes.ROLE_OUTPUT,
+                    AudioDeviceInfo.TYPE_HEARING_AID,
+                    address
+                )
+            )
+            .firstOrNull { spatializerInteractor.isSpatialAudioAvailable(it) }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/model/SpatialAudioAvailabilityModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/model/SpatialAudioAvailabilityModel.kt
new file mode 100644
index 0000000..cf14546
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/model/SpatialAudioAvailabilityModel.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 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.volume.panel.component.spatial.domain.model
+
+/** Models spatial audio and head tracking availability. */
+interface SpatialAudioAvailabilityModel {
+
+    /** Spatial audio is unavailable. */
+    data object Unavailable : SpatialAudioAvailabilityModel
+
+    /** Spatial audio is available. */
+    interface SpatialAudio : SpatialAudioAvailabilityModel {
+        companion object : SpatialAudio
+    }
+
+    /** Head tracking is available. This also means that [SpatialAudio] is available. */
+    data object HeadTracking : SpatialAudio
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/model/SpatialAudioEnabledModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/model/SpatialAudioEnabledModel.kt
new file mode 100644
index 0000000..4e65f60
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/spatial/domain/model/SpatialAudioEnabledModel.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2024 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.volume.panel.component.spatial.domain.model
+
+/** Models spatial audio and head tracking enabled/disabled state. */
+interface SpatialAudioEnabledModel {
+
+    /** Spatial audio is disabled. */
+    data object Disabled : SpatialAudioEnabledModel
+
+    /** Spatial audio is enabled. */
+    interface SpatialAudioEnabled : SpatialAudioEnabledModel {
+        companion object : SpatialAudioEnabled
+    }
+
+    /** Head tracking is enabled. This also means that [SpatialAudioEnabled]. */
+    data object HeadTrackingEnabled : SpatialAudioEnabled
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/interactor/VolumeSliderInteractor.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/interactor/VolumeSliderInteractor.kt
index 52736c6..0c91bbf 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/interactor/VolumeSliderInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/domain/interactor/VolumeSliderInteractor.kt
@@ -24,7 +24,7 @@
 class VolumeSliderInteractor @Inject constructor() {
 
     /** mimic percentage volume setting */
-    private val displayValueRange: ClosedFloatingPointRange<Float> = 0f..100f
+    val displayValueRange: ClosedFloatingPointRange<Float> = 0f..100f
 
     /**
      * Translates [volume], that belongs to [volumeRange] to the value that belongs to
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt
new file mode 100644
index 0000000..faf7434
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModel.kt
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2024 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.volume.panel.component.volume.slider.ui.viewmodel
+
+import android.content.Context
+import android.media.AudioManager
+import com.android.settingslib.volume.domain.interactor.AudioVolumeInteractor
+import com.android.settingslib.volume.shared.model.AudioStream
+import com.android.settingslib.volume.shared.model.AudioStreamModel
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.res.R
+import com.android.systemui.volume.panel.component.volume.domain.interactor.VolumeSliderInteractor
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
+
+/** Models a particular slider state. */
+class AudioStreamSliderViewModel
+@AssistedInject
+constructor(
+    @Assisted private val audioStreamWrapper: FactoryAudioStreamWrapper,
+    @Assisted private val coroutineScope: CoroutineScope,
+    private val context: Context,
+    private val audioVolumeInteractor: AudioVolumeInteractor,
+    private val volumeSliderInteractor: VolumeSliderInteractor,
+) : SliderViewModel {
+
+    private val audioStream = audioStreamWrapper.audioStream
+    private val iconsByStream =
+        mapOf(
+            AudioStream(AudioManager.STREAM_MUSIC) to R.drawable.ic_music_note,
+            AudioStream(AudioManager.STREAM_VOICE_CALL) to R.drawable.ic_call,
+            AudioStream(AudioManager.STREAM_RING) to R.drawable.ic_ring_volume,
+            AudioStream(AudioManager.STREAM_NOTIFICATION) to R.drawable.ic_volume_ringer,
+            AudioStream(AudioManager.STREAM_ALARM) to R.drawable.ic_volume_alarm,
+        )
+    private val mutedIconsByStream =
+        mapOf(
+            AudioStream(AudioManager.STREAM_MUSIC) to R.drawable.ic_volume_off,
+            AudioStream(AudioManager.STREAM_VOICE_CALL) to R.drawable.ic_volume_off,
+            AudioStream(AudioManager.STREAM_RING) to R.drawable.ic_volume_off,
+            AudioStream(AudioManager.STREAM_NOTIFICATION) to R.drawable.ic_volume_off,
+            AudioStream(AudioManager.STREAM_ALARM) to R.drawable.ic_volume_off,
+        )
+    private val labelsByStream =
+        mapOf(
+            AudioStream(AudioManager.STREAM_MUSIC) to R.string.stream_music,
+            AudioStream(AudioManager.STREAM_VOICE_CALL) to R.string.stream_voice_call,
+            AudioStream(AudioManager.STREAM_RING) to R.string.stream_ring,
+            AudioStream(AudioManager.STREAM_NOTIFICATION) to R.string.stream_notification,
+            AudioStream(AudioManager.STREAM_ALARM) to R.string.stream_alarm,
+        )
+    private val disabledTextByStream =
+        mapOf(
+            AudioStream(AudioManager.STREAM_NOTIFICATION) to
+                R.string.stream_notification_unavailable,
+        )
+
+    private var value = 0f
+    override val slider: StateFlow<SliderState> =
+        combine(
+                audioVolumeInteractor.getAudioStream(audioStream),
+                audioVolumeInteractor.canChangeVolume(audioStream),
+            ) { model, isEnabled ->
+                model.toState(value, isEnabled)
+            }
+            .stateIn(coroutineScope, SharingStarted.Eagerly, EmptyState)
+
+    override fun onValueChangeFinished(state: SliderState, newValue: Float) {
+        val audioViewModel = state as? State
+        audioViewModel ?: return
+        coroutineScope.launch {
+            value = newValue
+            val volume =
+                volumeSliderInteractor.translateValueToVolume(
+                    newValue,
+                    audioViewModel.audioStreamModel.volumeRange
+                )
+            audioVolumeInteractor.setVolume(audioStream, volume)
+        }
+    }
+
+    private fun AudioStreamModel.toState(value: Float, isEnabled: Boolean): State {
+        return State(
+            value =
+                volumeSliderInteractor.processVolumeToValue(
+                    volume,
+                    volumeRange,
+                    value,
+                    isMuted,
+                ),
+            valueRange = volumeSliderInteractor.displayValueRange,
+            icon = getIcon(this),
+            label = labelsByStream[audioStream]?.let(context::getString)
+                    ?: error("No label for the stream: $audioStream"),
+            disabledMessage = disabledTextByStream[audioStream]?.let(context::getString),
+            isEnabled = isEnabled,
+            audioStreamModel = this,
+        )
+    }
+
+    private fun getIcon(model: AudioStreamModel): Icon {
+        val isMutedOrNoVolume = model.isMuted || model.volume == model.minVolume
+        val iconRes =
+            if (isMutedOrNoVolume) {
+                mutedIconsByStream
+            } else {
+                iconsByStream
+            }[audioStream]
+                ?: error("No icon for the stream: $audioStream")
+        return Icon.Resource(iconRes, null)
+    }
+
+    private val AudioStreamModel.volumeRange: IntRange
+        get() = minVolume..maxVolume
+
+    private data class State(
+        override val value: Float,
+        override val valueRange: ClosedFloatingPointRange<Float>,
+        override val icon: Icon,
+        override val label: String,
+        override val disabledMessage: String?,
+        override val isEnabled: Boolean,
+        val audioStreamModel: AudioStreamModel,
+    ) : SliderState
+
+    private data object EmptyState : SliderState {
+        override val value: Float = 0f
+        override val valueRange: ClosedFloatingPointRange<Float> = 0f..1f
+        override val icon: Icon? = null
+        override val label: String = ""
+        override val disabledMessage: String? = null
+        override val isEnabled: Boolean = true
+    }
+
+    @AssistedFactory
+    interface Factory {
+
+        fun create(
+            audioStream: FactoryAudioStreamWrapper,
+            coroutineScope: CoroutineScope,
+        ): AudioStreamSliderViewModel
+    }
+
+    /**
+     * AudioStream is a value class that compiles into a primitive. This fail AssistedFactory build
+     * when using [AudioStream] directly because it expects another type.
+     */
+    class FactoryAudioStreamWrapper(val audioStream: AudioStream)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModel.kt
new file mode 100644
index 0000000..ae93826
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModel.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2024 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.volume.panel.component.volume.slider.ui.viewmodel
+
+import android.content.Context
+import com.android.settingslib.volume.domain.model.RoutingSession
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.res.R
+import com.android.systemui.volume.panel.component.mediaoutput.domain.interactor.MediaOutputInteractor
+import com.android.systemui.volume.panel.component.volume.domain.interactor.CastVolumeInteractor
+import com.android.systemui.volume.panel.component.volume.domain.interactor.VolumeSliderInteractor
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
+
+class CastVolumeSliderViewModel
+@AssistedInject
+constructor(
+    @Assisted private val routingSession: RoutingSession,
+    @Assisted private val coroutineScope: CoroutineScope,
+    private val context: Context,
+    mediaOutputInteractor: MediaOutputInteractor,
+    private val volumeSliderInteractor: VolumeSliderInteractor,
+    private val castVolumeInteractor: CastVolumeInteractor,
+) : SliderViewModel {
+
+    private val volumeRange = 0..routingSession.routingSessionInfo.volumeMax
+    private val value = MutableStateFlow(0f)
+
+    override val slider: StateFlow<SliderState> =
+        combine(value, mediaOutputInteractor.currentConnectedDevice) { value, _ ->
+                getCurrentState(value)
+            }
+            .stateIn(coroutineScope, SharingStarted.Eagerly, getCurrentState(value.value))
+
+    override fun onValueChangeFinished(state: SliderState, newValue: Float) {
+        coroutineScope.launch {
+            value.value = newValue
+            castVolumeInteractor.setVolume(
+                routingSession,
+                volumeSliderInteractor.translateValueToVolume(newValue, volumeRange),
+            )
+        }
+    }
+
+    private fun getCurrentState(value: Float): State {
+        return State(
+            value =
+                volumeSliderInteractor.processVolumeToValue(
+                    volume = routingSession.routingSessionInfo.volume,
+                    volumeRange = volumeRange,
+                    currentValue = value,
+                    isMuted = false,
+                ),
+            valueRange = volumeSliderInteractor.displayValueRange,
+            icon = Icon.Resource(R.drawable.ic_cast, null),
+            label = context.getString(R.string.media_device_cast),
+            isEnabled = true,
+        )
+    }
+
+    private data class State(
+        override val value: Float,
+        override val valueRange: ClosedFloatingPointRange<Float>,
+        override val icon: Icon,
+        override val label: String,
+        override val isEnabled: Boolean,
+    ) : SliderState {
+        override val disabledMessage: String?
+            get() = null
+    }
+
+    @AssistedFactory
+    interface Factory {
+
+        fun create(
+            routingSession: RoutingSession,
+            coroutineScope: CoroutineScope,
+        ): CastVolumeSliderViewModel
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/SliderState.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/SliderState.kt
new file mode 100644
index 0000000..6e9794b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/SliderState.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 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.volume.panel.component.volume.slider.ui.viewmodel
+
+import com.android.systemui.common.shared.model.Icon
+
+/**
+ * Models a state of a volume slider.
+ *
+ * @property disabledMessage is shown when [isEnabled] is false
+ */
+sealed interface SliderState {
+    val value: Float
+    val valueRange: ClosedFloatingPointRange<Float>
+    val icon: Icon?
+    val label: String
+    val disabledMessage: String?
+    val isEnabled: Boolean
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/SliderViewModel.kt
similarity index 62%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
copy to packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/SliderViewModel.kt
index b370859..0c4b322 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/SliderViewModel.kt
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.systemui.keyguard.ui.viewmodel
+package com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel
 
-import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
-import com.android.systemui.kosmos.Kosmos
+import kotlinx.coroutines.flow.StateFlow
 
-val Kosmos.dreamingToGlanceableHubTransitionViewModel by
-    Kosmos.Fixture {
-        DreamingToGlanceableHubTransitionViewModel(
-            animationFlow = keyguardTransitionAnimationFlow,
-        )
-    }
+/** Controls the behaviour of a volume slider. */
+interface SliderViewModel {
+
+    val slider: StateFlow<SliderState>
+
+    fun onValueChangeFinished(state: SliderState, newValue: Float)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt
new file mode 100644
index 0000000..2824323
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2024 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.volume.panel.component.volume.ui.viewmodel
+
+import android.media.AudioManager
+import com.android.settingslib.volume.shared.model.AudioStream
+import com.android.systemui.volume.panel.component.volume.domain.interactor.CastVolumeInteractor
+import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.AudioStreamSliderViewModel
+import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.CastVolumeSliderViewModel
+import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderViewModel
+import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.flow.transformLatest
+
+/**
+ * Controls the behaviour of the whole audio
+ * [com.android.systemui.volume.panel.shared.model.VolumePanelUiComponent].
+ */
+@OptIn(ExperimentalCoroutinesApi::class)
+@VolumePanelScope
+class AudioVolumeComponentViewModel
+@Inject
+constructor(
+    @VolumePanelScope private val scope: CoroutineScope,
+    castVolumeInteractor: CastVolumeInteractor,
+    private val streamSliderViewModelFactory: AudioStreamSliderViewModel.Factory,
+    private val castVolumeSliderViewModelFactory: CastVolumeSliderViewModel.Factory,
+) {
+
+    private val remoteSessionsViewModels: Flow<List<SliderViewModel>> =
+        castVolumeInteractor.remoteRoutingSessions.transformLatest { routingSessions ->
+            coroutineScope {
+                emit(
+                    routingSessions.map { routingSession ->
+                        castVolumeSliderViewModelFactory.create(routingSession, this)
+                    }
+                )
+            }
+        }
+    private val streamViewModels: Flow<List<SliderViewModel>> =
+        flowOf(
+                listOf(
+                    AudioStream(AudioManager.STREAM_MUSIC),
+                    AudioStream(AudioManager.STREAM_VOICE_CALL),
+                    AudioStream(AudioManager.STREAM_RING),
+                    AudioStream(AudioManager.STREAM_NOTIFICATION),
+                    AudioStream(AudioManager.STREAM_ALARM),
+                )
+            )
+            .transformLatest { streams ->
+                coroutineScope {
+                    emit(
+                        streams.map { stream ->
+                            streamSliderViewModelFactory.create(
+                                AudioStreamSliderViewModel.FactoryAudioStreamWrapper(stream),
+                                this,
+                            )
+                        }
+                    )
+                }
+            }
+
+    val sliderViewModels: StateFlow<List<SliderViewModel>> =
+        combine(remoteSessionsViewModels, streamViewModels) {
+                remoteSessionsViewModels,
+                streamViewModels ->
+                remoteSessionsViewModels + streamViewModels
+            }
+            .stateIn(scope, SharingStarted.Eagerly, emptyList())
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/dagger/VolumePanelComponent.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/dagger/VolumePanelComponent.kt
index df4972a..f31ee86 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/dagger/VolumePanelComponent.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/dagger/VolumePanelComponent.kt
@@ -20,6 +20,7 @@
 import com.android.systemui.volume.panel.component.bottombar.BottomBarModule
 import com.android.systemui.volume.panel.component.captioning.CaptioningModule
 import com.android.systemui.volume.panel.component.mediaoutput.MediaOutputModule
+import com.android.systemui.volume.panel.component.volume.VolumeSlidersModule
 import com.android.systemui.volume.panel.dagger.factory.VolumePanelComponentFactory
 import com.android.systemui.volume.panel.dagger.scope.VolumePanelScope
 import com.android.systemui.volume.panel.domain.DomainModule
@@ -48,6 +49,7 @@
             // Components modules
             BottomBarModule::class,
             AncModule::class,
+            VolumeSlidersModule::class,
             CaptioningModule::class,
             MediaOutputModule::class,
         ]
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/domain/DomainModule.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/domain/DomainModule.kt
index 0d65c42..57ea997 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/domain/DomainModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/domain/DomainModule.kt
@@ -52,6 +52,7 @@
             return setOf(
                 VolumePanelComponents.ANC,
                 VolumePanelComponents.CAPTIONING,
+                VolumePanelComponents.VOLUME_SLIDERS,
                 VolumePanelComponents.MEDIA_OUTPUT,
                 VolumePanelComponents.BOTTOM_BAR,
             )
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelState.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelState.kt
index 7f33a6b..f57e293 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelState.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelState.kt
@@ -23,12 +23,12 @@
  * State of the Volume Panel itself.
  *
  * @property orientation is current Volume Panel orientation
- * @property isWideScreen is true when Volume Panel should use wide-screen layout and false the
+ * @property isLargeScreen is true when Volume Panel should use wide-screen layout and false the
  *   otherwise
  */
 data class VolumePanelState(
     @Orientation val orientation: Int,
-    val isWideScreen: Boolean,
+    val isLargeScreen: Boolean,
     val isVisible: Boolean,
 ) {
     init {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModel.kt
index 3c5b75c..5ae827f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModel.kt
@@ -76,7 +76,7 @@
                 VolumePanelState(
                     orientation = configuration.orientation,
                     isVisible = isVisible,
-                    isWideScreen = !resources.getBoolean(R.bool.config_edgeToEdgeBottomSheetDialog),
+                    isLargeScreen = resources.getBoolean(R.bool.volume_panel_is_large_screen),
                 )
             }
             .stateIn(
@@ -85,7 +85,7 @@
                 VolumePanelState(
                     orientation = resources.configuration.orientation,
                     isVisible = mutablePanelVisibility.value,
-                    isWideScreen = !resources.getBoolean(R.bool.config_edgeToEdgeBottomSheetDialog)
+                    isLargeScreen = resources.getBoolean(R.bool.volume_panel_is_large_screen)
                 ),
             )
     val componentsLayout: Flow<ComponentsLayout> =
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index 139d190..65dede8 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -25,6 +25,7 @@
 import static android.service.notification.NotificationStats.DISMISSAL_BUBBLE;
 import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
 
+import static com.android.server.notification.Flags.screenshareNotificationHiding;
 import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
 import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
 
@@ -69,6 +70,7 @@
 import com.android.systemui.statusbar.notification.interruption.VisualInterruptionDecisionProvider;
 import com.android.systemui.statusbar.phone.StatusBarWindowCallback;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.policy.SensitiveNotificationProtectionController;
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.wm.shell.bubbles.Bubble;
 import com.android.wm.shell.bubbles.BubbleEntry;
@@ -102,6 +104,7 @@
     private final NotificationVisibilityProvider mVisibilityProvider;
     private final VisualInterruptionDecisionProvider mVisualInterruptionDecisionProvider;
     private final NotificationLockscreenUserManager mNotifUserManager;
+    private final SensitiveNotificationProtectionController mSensitiveNotifProtectionController;
     private final CommonNotifCollection mCommonNotifCollection;
     private final NotifPipeline mNotifPipeline;
     private final NotifPipelineFlags mNotifPipelineFlags;
@@ -111,6 +114,7 @@
     // TODO (b/145659174): allow for multiple callbacks to support the "shadow" new notif pipeline
     private final List<NotifCallback> mCallbacks = new ArrayList<>();
     private final StatusBarWindowCallback mStatusBarWindowCallback;
+    private final Runnable mSensitiveStateChangedListener;
     private boolean mPanelExpanded;
 
     /**
@@ -130,6 +134,7 @@
             VisualInterruptionDecisionProvider visualInterruptionDecisionProvider,
             ZenModeController zenModeController,
             NotificationLockscreenUserManager notifUserManager,
+            SensitiveNotificationProtectionController sensitiveNotificationProtectionController,
             CommonNotifCollection notifCollection,
             NotifPipeline notifPipeline,
             SysUiState sysUiState,
@@ -149,6 +154,7 @@
                     visualInterruptionDecisionProvider,
                     zenModeController,
                     notifUserManager,
+                    sensitiveNotificationProtectionController,
                     notifCollection,
                     notifPipeline,
                     sysUiState,
@@ -173,6 +179,7 @@
             VisualInterruptionDecisionProvider visualInterruptionDecisionProvider,
             ZenModeController zenModeController,
             NotificationLockscreenUserManager notifUserManager,
+            SensitiveNotificationProtectionController sensitiveNotificationProtectionController,
             CommonNotifCollection notifCollection,
             NotifPipeline notifPipeline,
             SysUiState sysUiState,
@@ -188,6 +195,7 @@
         mVisibilityProvider = visibilityProvider;
         mVisualInterruptionDecisionProvider = visualInterruptionDecisionProvider;
         mNotifUserManager = notifUserManager;
+        mSensitiveNotifProtectionController = sensitiveNotificationProtectionController;
         mCommonNotifCollection = notifCollection;
         mNotifPipeline = notifPipeline;
         mNotifPipelineFlags = notifPipelineFlags;
@@ -251,6 +259,22 @@
                 };
         notificationShadeWindowController.registerCallback(mStatusBarWindowCallback);
 
+        mSensitiveStateChangedListener = new Runnable() {
+            @Override
+            public void run() {
+                if (!screenshareNotificationHiding()) {
+                    return;
+                }
+                bubbles.onSensitiveNotificationProtectionStateChanged(
+                        mSensitiveNotifProtectionController.isSensitiveStateActive());
+            }
+        };
+
+        if (screenshareNotificationHiding()) {
+            mSensitiveNotifProtectionController
+                    .registerSensitiveStateListener(mSensitiveStateChangedListener);
+        }
+
         mSysuiProxy = new Bubbles.SysuiProxy() {
             @Override
             public void isNotificationPanelExpand(Consumer<Boolean> callback) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java
index c2ed7d4..976cd5bd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuItemAccessibilityDelegateTest.java
@@ -21,6 +21,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
@@ -89,6 +90,7 @@
         mMenuView = spy(new MenuView(mContext, stubMenuViewModel, stubMenuViewAppearance,
                 mSecureSettings));
         mMenuView.setTranslationY(halfScreenHeight);
+        doNothing().when(mMenuView).gotoEditScreen();
 
         mMenuViewLayer = spy(new MenuViewLayer(
                 mContext, stubWindowManager, mAccessibilityManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
index ce4db8f..3862b0f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewLayerTest.java
@@ -160,6 +160,7 @@
                 new MenuView(mSpyContext, mMenuViewModel, menuViewAppearance, mSecureSettings));
         // Ensure tests don't actually update metrics.
         doNothing().when(mMenuView).incrementTexMetric(any(), anyInt());
+        doNothing().when(mMenuView).gotoEditScreen();
 
         mMenuViewLayer = spy(new MenuViewLayer(mSpyContext, mStubWindowManager,
                 mStubAccessibilityManager, mMenuViewModel, menuViewAppearance, mMenuView,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
index 7c97f53..1ce6525 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
@@ -21,6 +21,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 
@@ -80,6 +81,7 @@
         mUiModeManager.setNightMode(MODE_NIGHT_YES);
 
         mSpyContext = spy(mContext);
+        doNothing().when(mSpyContext).startActivity(any());
         final SecureSettings secureSettings = TestUtils.mockSecureSettings();
         final MenuViewModel stubMenuViewModel = new MenuViewModel(mContext, mAccessibilityManager,
                 secureSettings);
@@ -179,8 +181,6 @@
     @Test
     @EnableFlags(Flags.FLAG_FLOATING_MENU_DRAG_TO_EDIT)
     public void gotoEditScreen_sendsIntent() {
-        // Notably, this shouldn't crash the settings app,
-        // because the button target args are configured.
         mMenuView.gotoEditScreen();
         verify(mSpyContext).startActivity(any());
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FacePropertyRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FacePropertyRepositoryImplTest.kt
index 9f24d5d..f5e96c9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FacePropertyRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/FacePropertyRepositoryImplTest.kt
@@ -237,6 +237,35 @@
         }
     }
 
+    @Test
+    fun providesTheCameraInfoOnCameraAvailableChange() {
+        testScope.runTest {
+            runCurrent()
+            collectLastValue(underTest.cameraInfo)
+
+            verify(faceManager).addAuthenticatorsRegisteredCallback(callback.capture())
+            callback.value.onAllAuthenticatorsRegistered(
+                listOf(createSensorProperties(1, SensorProperties.STRENGTH_STRONG))
+            )
+            runCurrent()
+            verify(cameraManager)
+                .registerAvailabilityCallback(any(Executor::class.java), cameraCallback.capture())
+
+            cameraCallback.value.onPhysicalCameraAvailable("0", PHYSICAL_CAMERA_ID_OUTER_FRONT)
+            runCurrent()
+
+            val cameraInfo by collectLastValue(underTest.cameraInfo)
+            assertThat(cameraInfo)
+                .isEqualTo(
+                    CameraInfo(
+                        "0",
+                        PHYSICAL_CAMERA_ID_OUTER_FRONT,
+                        Point(OUTER_FRONT_SENSOR_LOCATION[0], OUTER_FRONT_SENSOR_LOCATION[1])
+                    )
+                )
+        }
+    }
+
     private fun createSensorProperties(id: Int, strength: Int) =
         FaceSensorPropertiesInternal(id, strength, 0, emptyList(), 1, false, false, false)
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
index ff68fe3..140849b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
@@ -241,19 +241,27 @@
 
             viewModel.showAuthenticated(testCase.authenticatedModality, 1_000L)
 
-            val confirmConstant by collectLastValue(viewModel.hapticsToPlay)
-            assertThat(confirmConstant)
+            val confirmHaptics by collectLastValue(viewModel.hapticsToPlay)
+            assertThat(confirmHaptics?.hapticFeedbackConstant)
                 .isEqualTo(
                     if (expectConfirmation) HapticFeedbackConstants.NO_HAPTICS
                     else HapticFeedbackConstants.CONFIRM
                 )
+            assertThat(confirmHaptics?.flag)
+                .isEqualTo(
+                    if (expectConfirmation) null
+                    else HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING
+                )
 
             if (expectConfirmation) {
                 viewModel.confirmAuthenticated()
             }
 
-            val confirmedConstant by collectLastValue(viewModel.hapticsToPlay)
-            assertThat(confirmedConstant).isEqualTo(HapticFeedbackConstants.CONFIRM)
+            val confirmedHaptics by collectLastValue(viewModel.hapticsToPlay)
+            assertThat(confirmedHaptics?.hapticFeedbackConstant)
+                .isEqualTo(HapticFeedbackConstants.CONFIRM)
+            assertThat(confirmedHaptics?.flag)
+                .isEqualTo(HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING)
         }
 
     @Test
@@ -265,16 +273,21 @@
             viewModel.confirmAuthenticated()
         }
 
-        val currentConstant by collectLastValue(viewModel.hapticsToPlay)
-        assertThat(currentConstant).isEqualTo(HapticFeedbackConstants.CONFIRM)
+        val currentHaptics by collectLastValue(viewModel.hapticsToPlay)
+        assertThat(currentHaptics?.hapticFeedbackConstant)
+            .isEqualTo(HapticFeedbackConstants.CONFIRM)
+        assertThat(currentHaptics?.flag)
+            .isEqualTo(HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING)
     }
 
     @Test
     fun playErrorHaptic_SetsRejectConstant() = runGenericTest {
         viewModel.showTemporaryError("test", "messageAfterError", false)
 
-        val currentConstant by collectLastValue(viewModel.hapticsToPlay)
-        assertThat(currentConstant).isEqualTo(HapticFeedbackConstants.REJECT)
+        val currentHaptics by collectLastValue(viewModel.hapticsToPlay)
+        assertThat(currentHaptics?.hapticFeedbackConstant).isEqualTo(HapticFeedbackConstants.REJECT)
+        assertThat(currentHaptics?.flag)
+            .isEqualTo(HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING)
     }
 
     @Test
@@ -800,8 +813,9 @@
             hapticFeedback = true,
         )
 
-        val constant by collectLastValue(viewModel.hapticsToPlay)
-        assertThat(constant).isEqualTo(HapticFeedbackConstants.REJECT)
+        val haptics by collectLastValue(viewModel.hapticsToPlay)
+        assertThat(haptics?.hapticFeedbackConstant).isEqualTo(HapticFeedbackConstants.REJECT)
+        assertThat(haptics?.flag).isEqualTo(HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING)
     }
 
     @Test
@@ -813,8 +827,8 @@
             hapticFeedback = false,
         )
 
-        val constant by collectLastValue(viewModel.hapticsToPlay)
-        assertThat(constant).isEqualTo(HapticFeedbackConstants.NO_HAPTICS)
+        val haptics by collectLastValue(viewModel.hapticsToPlay)
+        assertThat(haptics?.hapticFeedbackConstant).isEqualTo(HapticFeedbackConstants.NO_HAPTICS)
     }
 
     private suspend fun TestScope.showTemporaryErrors(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt
index e30dd35d..e1e9fcb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/interactor/DeviceEntryFaceAuthInteractorTest.kt
@@ -25,6 +25,7 @@
 import com.android.keyguard.keyguardUpdateMonitor
 import com.android.keyguard.trustManager
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.CameraInfo
 import com.android.systemui.biometrics.data.repository.FaceSensorInfo
 import com.android.systemui.biometrics.data.repository.facePropertyRepository
 import com.android.systemui.biometrics.shared.model.LockoutMode
@@ -490,6 +491,47 @@
             verify(trustManager).clearAllBiometricRecognized(eq(BiometricSourceType.FACE), anyInt())
         }
 
+    @Test
+    fun faceAuthIsRequestedWhenAuthIsRunningWhileCameraInfoChanged() =
+        testScope.runTest {
+            facePropertyRepository.setCameraIno(null)
+            underTest.start()
+
+            faceAuthRepository.requestAuthenticate(
+                FaceAuthUiEvent.FACE_AUTH_UPDATED_KEYGUARD_VISIBILITY_CHANGED,
+                true
+            )
+            facePropertyRepository.setCameraIno(CameraInfo("0", "1", null))
+
+            runCurrent()
+            assertThat(faceAuthRepository.runningAuthRequest.value)
+                .isEqualTo(Pair(FaceAuthUiEvent.FACE_AUTH_CAMERA_AVAILABLE_CHANGED, true))
+        }
+
+    @Test
+    fun faceAuthIsNotRequestedWhenNoAuthRunningWhileCameraInfoChanged() =
+        testScope.runTest {
+            facePropertyRepository.setCameraIno(null)
+            underTest.start()
+
+            facePropertyRepository.setCameraIno(CameraInfo("0", "1", null))
+
+            runCurrent()
+            assertThat(faceAuthRepository.runningAuthRequest.value).isNull()
+        }
+
+    @Test
+    fun faceAuthIsNotRequestedWhenAuthIsRunningWhileCameraInfoIsNull() =
+        testScope.runTest {
+            facePropertyRepository.setCameraIno(null)
+            underTest.start()
+
+            facePropertyRepository.setCameraIno(null)
+
+            runCurrent()
+            assertThat(faceAuthRepository.runningAuthRequest.value).isNull()
+        }
+
     companion object {
         private const val primaryUserId = 1
         private val primaryUser = UserInfo(primaryUserId, "test user", UserInfo.FLAG_PRIMARY)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt
index e97edcb..9b8cf59 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/deviceentry/domain/ui/viewmodel/UdfpsAccessibilityOverlayViewModelTest.kt
@@ -27,7 +27,7 @@
 import com.android.systemui.flags.Flags.FULL_SCREEN_USER_SWITCHER
 import com.android.systemui.flags.fakeFeatureFlagsClassic
 import com.android.systemui.keyguard.data.repository.deviceEntryFingerprintAuthRepository
-import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.fakeBiometricSettingsRepository
 import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.TransitionState
@@ -39,6 +39,7 @@
 import com.google.common.truth.Truth.assertThat
 import kotlin.test.Test
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.runner.RunWith
 
@@ -52,7 +53,7 @@
         }
     private val deviceEntryIconTransition = kosmos.fakeDeviceEntryIconViewModelTransition
     private val testScope = kosmos.testScope
-    private val keyguardRepository = kosmos.fakeKeyguardRepository
+    private val biometricSettingsRepository = kosmos.fakeBiometricSettingsRepository
     private val accessibilityRepository = kosmos.fakeAccessibilityRepository
     private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
     private val fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository
@@ -85,22 +86,12 @@
             setupVisibleStateOnLockscreen()
 
             // AOD
-            keyguardTransitionRepository.sendTransitionStep(
-                TransitionStep(
-                    from = KeyguardState.LOCKSCREEN,
-                    to = KeyguardState.AOD,
-                    value = 0f,
-                    transitionState = TransitionState.STARTED,
-                )
+            keyguardTransitionRepository.sendTransitionSteps(
+                from = KeyguardState.LOCKSCREEN,
+                to = KeyguardState.AOD,
+                this,
             )
-            keyguardTransitionRepository.sendTransitionStep(
-                TransitionStep(
-                    from = KeyguardState.LOCKSCREEN,
-                    to = KeyguardState.AOD,
-                    value = 1f,
-                    transitionState = TransitionState.FINISHED,
-                )
-            )
+            runCurrent()
             assertThat(visible).isFalse()
         }
     fun fpNotRunning_overlayNotVisible() =
@@ -129,6 +120,7 @@
 
         // Listening for UDFPS
         fingerprintPropertyRepository.supportsUdfps()
+        biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
         deviceEntryFingerprintAuthRepository.setIsRunning(true)
         deviceEntryRepository.setUnlocked(false)
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/ShutdownUiTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/ShutdownUiTest.java
index 9d9b263..2d3ca60 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/ShutdownUiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/ShutdownUiTest.java
@@ -19,7 +19,13 @@
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertNull;
 
+import static org.mockito.Mockito.when;
+
+import android.nearby.NearbyManager;
+import android.net.platform.flags.Flags;
 import android.os.PowerManager;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
 import android.testing.AndroidTestingRunner;
 
 import androidx.test.filters.SmallTest;
@@ -32,6 +38,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 
 @SmallTest
@@ -41,10 +48,13 @@
     ShutdownUi mShutdownUi;
     @Mock
     BlurUtils mBlurUtils;
+    @Mock
+    NearbyManager mNearbyManager;
 
     @Before
     public void setUp() throws Exception {
-        mShutdownUi = new ShutdownUi(getContext(), mBlurUtils);
+        MockitoAnnotations.initMocks(this);
+        mShutdownUi = new ShutdownUi(getContext(), mBlurUtils, mNearbyManager);
     }
 
     @Test
@@ -82,4 +92,53 @@
         String message = mShutdownUi.getReasonMessage("anything-else");
         assertNull(message);
     }
+
+    @EnableFlags(Flags.FLAG_POWERED_OFF_FINDING_PLATFORM)
+    @Test
+    public void getDialog_whenPowerOffFindingModeEnabled_returnsFinderDialog() {
+        when(mNearbyManager.getPoweredOffFindingMode()).thenReturn(
+                NearbyManager.POWERED_OFF_FINDING_MODE_ENABLED);
+
+        int actualLayout = mShutdownUi.getShutdownDialogContent(false);
+
+        int expectedLayout = com.android.systemui.res.R.layout.shutdown_dialog_finder_active;
+        assertEquals(actualLayout, expectedLayout);
+    }
+
+    @DisableFlags(Flags.FLAG_POWERED_OFF_FINDING_PLATFORM)
+    @Test
+    public void getDialog_whenPowerOffFindingModeEnabledFlagDisabled_returnsFinderDialog() {
+        when(mNearbyManager.getPoweredOffFindingMode()).thenReturn(
+                NearbyManager.POWERED_OFF_FINDING_MODE_ENABLED);
+
+        int actualLayout = mShutdownUi.getShutdownDialogContent(false);
+
+        int expectedLayout = R.layout.shutdown_dialog;
+        assertEquals(actualLayout, expectedLayout);
+    }
+
+    @EnableFlags(Flags.FLAG_POWERED_OFF_FINDING_PLATFORM)
+    @Test
+    public void getDialog_whenPowerOffFindingModeDisabled_returnsDefaultDialog() {
+        when(mNearbyManager.getPoweredOffFindingMode()).thenReturn(
+                NearbyManager.POWERED_OFF_FINDING_MODE_DISABLED);
+
+        int actualLayout = mShutdownUi.getShutdownDialogContent(false);
+
+        int expectedLayout = R.layout.shutdown_dialog;
+        assertEquals(actualLayout, expectedLayout);
+    }
+
+    @EnableFlags(Flags.FLAG_POWERED_OFF_FINDING_PLATFORM)
+    @Test
+    public void getDialog_whenPowerOffFindingModeEnabledAndIsReboot_returnsDefaultDialog() {
+        when(mNearbyManager.getPoweredOffFindingMode()).thenReturn(
+                NearbyManager.POWERED_OFF_FINDING_MODE_ENABLED);
+
+        int actualLayout = mShutdownUi.getShutdownDialogContent(true);
+
+        int expectedLayout = R.layout.shutdown_dialog;
+        assertEquals(actualLayout, expectedLayout);
+    }
+
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt
index 9df00d3..b0d8de3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorTest.kt
@@ -19,17 +19,23 @@
 
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.systemui.Flags
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.keyguard.data.repository.KeyguardBlueprintRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID
+import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor.Companion.WEATHER_CLOCK_BLUEPRINT_ID
 import com.android.systemui.keyguard.ui.view.layout.blueprints.DefaultKeyguardBlueprint
 import com.android.systemui.keyguard.ui.view.layout.blueprints.SplitShadeKeyguardBlueprint
 import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition
 import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Config
 import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Type
+import com.android.systemui.plugins.clocks.ClockConfig
+import com.android.systemui.plugins.clocks.ClockController
 import com.android.systemui.statusbar.policy.SplitShadeStateController
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.whenever
 import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.test.StandardTestDispatcher
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
@@ -38,6 +44,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mock
+import org.mockito.Mockito.never
 import org.mockito.Mockito.reset
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
@@ -54,6 +61,8 @@
 
     @Mock private lateinit var splitShadeStateController: SplitShadeStateController
     @Mock private lateinit var keyguardBlueprintRepository: KeyguardBlueprintRepository
+    @Mock private lateinit var clockInteractor: KeyguardClockInteractor
+    @Mock private lateinit var clockController: ClockController
 
     @Before
     fun setup() {
@@ -61,6 +70,8 @@
         testScope = TestScope(StandardTestDispatcher())
         whenever(keyguardBlueprintRepository.configurationChange).thenReturn(configurationFlow)
         whenever(keyguardBlueprintRepository.refreshTransition).thenReturn(refreshTransition)
+        whenever(clockInteractor.currentClock).thenReturn(MutableStateFlow(clockController))
+        clockInteractor.currentClock
 
         underTest =
             KeyguardBlueprintInteractor(
@@ -68,6 +79,7 @@
                 testScope.backgroundScope,
                 mContext,
                 splitShadeStateController,
+                clockInteractor,
             )
     }
 
@@ -102,6 +114,77 @@
     }
 
     @Test
+    fun composeLockscreenOff_DoesAppliesSplitShadeWeatherClockBlueprint() {
+        testScope.runTest {
+            mSetFlagsRule.disableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN)
+            whenever(clockController.config)
+                .thenReturn(
+                    ClockConfig(
+                        id = "DIGITAL_CLOCK_WEATHER",
+                        name = "clock",
+                        description = "clock",
+                    )
+                )
+            whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
+                .thenReturn(true)
+
+            reset(keyguardBlueprintRepository)
+            configurationFlow.tryEmit(Unit)
+            runCurrent()
+
+            verify(keyguardBlueprintRepository, never())
+                .applyBlueprint(SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID)
+        }
+    }
+
+    @Test
+    fun testDoesAppliesSplitShadeWeatherClockBlueprint() {
+        testScope.runTest {
+            mSetFlagsRule.enableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN)
+            whenever(clockController.config)
+                .thenReturn(
+                    ClockConfig(
+                        id = "DIGITAL_CLOCK_WEATHER",
+                        name = "clock",
+                        description = "clock",
+                    )
+                )
+            whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
+                .thenReturn(true)
+
+            reset(keyguardBlueprintRepository)
+            configurationFlow.tryEmit(Unit)
+            runCurrent()
+
+            verify(keyguardBlueprintRepository)
+                .applyBlueprint(SPLIT_SHADE_WEATHER_CLOCK_BLUEPRINT_ID)
+        }
+    }
+
+    @Test
+    fun testAppliesWeatherClockBlueprint() {
+        testScope.runTest {
+            mSetFlagsRule.enableFlags(Flags.FLAG_COMPOSE_LOCKSCREEN)
+            whenever(clockController.config)
+                .thenReturn(
+                    ClockConfig(
+                        id = "DIGITAL_CLOCK_WEATHER",
+                        name = "clock",
+                        description = "clock",
+                    )
+                )
+            whenever(splitShadeStateController.shouldUseSplitNotificationShade(any()))
+                .thenReturn(false)
+
+            reset(keyguardBlueprintRepository)
+            configurationFlow.tryEmit(Unit)
+            runCurrent()
+
+            verify(keyguardBlueprintRepository).applyBlueprint(WEATHER_CLOCK_BLUEPRINT_ID)
+        }
+    }
+
+    @Test
     fun testRefreshBlueprint() {
         underTest.refreshBlueprint()
         verify(keyguardBlueprintRepository).refreshBlueprint()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index abd4238..69cd173 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -129,7 +129,6 @@
 
         val glanceableHubTransitions =
             GlanceableHubTransitions(
-                scope = testScope,
                 bgDispatcher = kosmos.testDispatcher,
                 transitionInteractor = transitionInteractor,
                 transitionRepository = transitionRepository,
@@ -1812,26 +1811,40 @@
     @Test
     fun glanceableHubToDreaming() =
         testScope.runTest {
-            // GIVEN a device that is not dreaming or dozing
-            keyguardRepository.setDreamingWithOverlay(false)
+            // GIVEN that we are dreaming and not dozing
+            keyguardRepository.setDreaming(true)
             keyguardRepository.setDozeTransitionModel(
                 DozeTransitionModel(from = DozeStateModel.DOZE, to = DozeStateModel.FINISH)
             )
             runCurrent()
 
             // GIVEN a prior transition has run to GLANCEABLE_HUB
-            runTransitionAndSetWakefulness(KeyguardState.LOCKSCREEN, KeyguardState.GLANCEABLE_HUB)
+            runTransitionAndSetWakefulness(KeyguardState.DREAMING, KeyguardState.GLANCEABLE_HUB)
+            runCurrent()
 
-            // WHEN the device begins to dream
-            keyguardRepository.setDreamingWithOverlay(true)
-            advanceTimeBy(100L)
+            // WHEN a transition away from glanceable hub starts
+            val currentScene = CommunalSceneKey.Communal
+            val targetScene = CommunalSceneKey.Blank
+
+            val transitionState =
+                MutableStateFlow<ObservableCommunalTransitionState>(
+                    ObservableCommunalTransitionState.Transition(
+                        fromScene = currentScene,
+                        toScene = targetScene,
+                        progress = flowOf(0f, 0.1f),
+                        isInitiatedByUserInput = false,
+                        isUserInputOngoing = flowOf(false),
+                    )
+                )
+            communalInteractor.setTransitionState(transitionState)
+            runCurrent()
 
             assertThat(transitionRepository)
                 .startedTransition(
                     ownerName = FromGlanceableHubTransitionInteractor::class.simpleName,
                     from = KeyguardState.GLANCEABLE_HUB,
                     to = KeyguardState.DREAMING,
-                    animatorAssertion = { it.isNotNull() },
+                    animatorAssertion = { it.isNull() }, // transition should be manually animated
                 )
 
             coroutineContext.cancelChildren()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelTest.kt
new file mode 100644
index 0000000..02bd810
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModelTest.kt
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2024 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.keyguard.ui.viewmodel
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
+import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
+import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
+import com.android.systemui.keyguard.data.repository.keyguardRepository
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.runner.RunWith
+
+@ExperimentalCoroutinesApi
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DeviceEntryIconViewModelTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private val testScope = kosmos.testScope
+    private lateinit var keyguardRepository: FakeKeyguardRepository
+    private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository
+    private lateinit var fingerprintAuthRepository: FakeDeviceEntryFingerprintAuthRepository
+    private lateinit var deviceEntryIconTransition: FakeDeviceEntryIconTransition
+    private lateinit var underTest: DeviceEntryIconViewModel
+
+    @Before
+    fun setUp() {
+        keyguardRepository = kosmos.fakeKeyguardRepository
+        fingerprintPropertyRepository = kosmos.fingerprintPropertyRepository
+        fingerprintAuthRepository = kosmos.fakeDeviceEntryFingerprintAuthRepository
+        deviceEntryIconTransition = kosmos.fakeDeviceEntryIconViewModelTransition
+        underTest = kosmos.deviceEntryIconViewModel
+    }
+
+    @Test
+    fun isLongPressEnabled_udfpsRunning() =
+        testScope.runTest {
+            val isLongPressEnabled by collectLastValue(underTest.isLongPressEnabled)
+            fingerprintPropertyRepository.supportsUdfps()
+            fingerprintAuthRepository.setIsRunning(true)
+            keyguardRepository.setKeyguardDismissible(false)
+            assertThat(isLongPressEnabled).isFalse()
+        }
+
+    @Test
+    fun isLongPressEnabled_unlocked() =
+        testScope.runTest {
+            val isLongPressEnabled by collectLastValue(underTest.isLongPressEnabled)
+            keyguardRepository.setKeyguardDismissible(true)
+            assertThat(isLongPressEnabled).isTrue()
+        }
+
+    @Test
+    fun isLongPressEnabled_lock() =
+        testScope.runTest {
+            val isLongPressEnabled by collectLastValue(underTest.isLongPressEnabled)
+            keyguardRepository.setKeyguardDismissible(false)
+
+            // udfps supported
+            fingerprintPropertyRepository.supportsUdfps()
+            assertThat(isLongPressEnabled).isTrue()
+
+            // udfps isn't supported
+            fingerprintPropertyRepository.supportsRearFps()
+            assertThat(isLongPressEnabled).isFalse()
+        }
+
+    @Test
+    fun isVisible() =
+        testScope.runTest {
+            val isVisible by collectLastValue(underTest.isVisible)
+            deviceEntryIconTransitionAlpha(1f)
+            assertThat(isVisible).isTrue()
+
+            deviceEntryIconTransitionAlpha(0f)
+            assertThat(isVisible).isFalse()
+
+            deviceEntryIconTransitionAlpha(.5f)
+            assertThat(isVisible).isTrue()
+        }
+
+    private fun deviceEntryIconTransitionAlpha(alpha: Float) {
+        deviceEntryIconTransition.setDeviceEntryParentViewAlpha(alpha)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelTest.kt
index 471029b..4a10d80 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelTest.kt
@@ -54,6 +54,19 @@
             deviceEntryParentViewAlpha.forEach { assertThat(it).isEqualTo(1f) }
         }
 
+    @Test
+    fun deviceEntryBackgroundViewShows() =
+        testScope.runTest {
+            val backgroundViewAlpha by collectValues(underTest.deviceEntryBackgroundViewAlpha)
+            repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+            repository.sendTransitionStep(step(0.1f))
+            repository.sendTransitionStep(step(0.3f))
+            repository.sendTransitionStep(step(0.5f))
+            repository.sendTransitionStep(step(0.6f))
+            repository.sendTransitionStep(step(1f))
+            backgroundViewAlpha.forEach { assertThat(it).isEqualTo(1f) }
+        }
+
     private fun step(
         value: Float,
         state: TransitionState = TransitionState.RUNNING
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/OWNERS b/packages/SystemUI/tests/src/com/android/systemui/media/OWNERS
new file mode 100644
index 0000000..e6f218f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/OWNERS
@@ -0,0 +1 @@
+include /packages/SystemUI/src/com/android/systemui/media/OWNERS
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt
index 2e7829d..2f92afa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt
@@ -1247,7 +1247,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
+    @RequiresFlagsEnabled(com.android.settingslib.flags.Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
     fun bindBroadcastButton() {
         initMediaViewHolderMocks()
         initDeviceMediaData(true, APP_NAME)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManagerTest.kt
index 85291b8..45f49f0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManagerTest.kt
@@ -24,8 +24,10 @@
 import android.widget.FrameLayout
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardViewController
+import com.android.systemui.Flags
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.communal.domain.interactor.communalInteractor
+import com.android.systemui.communal.domain.interactor.setCommunalAvailable
 import com.android.systemui.communal.shared.model.CommunalSceneKey
 import com.android.systemui.controls.controller.ControlsControllerImplTest.Companion.eq
 import com.android.systemui.dreams.DreamOverlayStateController
@@ -508,6 +510,10 @@
     @Test
     fun testCommunalLocation() =
         testScope.runTest {
+            mSetFlagsRule.enableFlags(Flags.FLAG_COMMUNAL_HUB)
+            kosmos.setCommunalAvailable(true)
+            runCurrent()
+
             communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
             runCurrent()
             verify(mediaCarouselController)
@@ -533,6 +539,66 @@
         }
 
     @Test
+    fun testCommunalLocation_showsOverLockscreen() =
+        testScope.runTest {
+            mSetFlagsRule.enableFlags(Flags.FLAG_COMMUNAL_HUB)
+            kosmos.setCommunalAvailable(true)
+            runCurrent()
+
+            // Device is on lock screen.
+            whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
+
+            // UMO goes to communal even over the lock screen.
+            communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
+            runCurrent()
+            verify(mediaCarouselController)
+                .onDesiredLocationChanged(
+                    eq(MediaHierarchyManager.LOCATION_COMMUNAL_HUB),
+                    nullable(),
+                    eq(false),
+                    anyLong(),
+                    anyLong()
+                )
+        }
+
+    @Test
+    fun testCommunalLocation_showsUntilQsExpands() =
+        testScope.runTest {
+            mSetFlagsRule.enableFlags(Flags.FLAG_COMMUNAL_HUB)
+            kosmos.setCommunalAvailable(true)
+            runCurrent()
+
+            // Device is on lock screen.
+            whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
+
+            communalInteractor.onSceneChanged(CommunalSceneKey.Communal)
+            runCurrent()
+            verify(mediaCarouselController)
+                .onDesiredLocationChanged(
+                    eq(MediaHierarchyManager.LOCATION_COMMUNAL_HUB),
+                    nullable(),
+                    eq(false),
+                    anyLong(),
+                    anyLong()
+                )
+            clearInvocations(mediaCarouselController)
+
+            // Start opening the shade.
+            mediaHierarchyManager.qsExpansion = 0.1f
+            runCurrent()
+
+            // UMO goes to the shade instead.
+            verify(mediaCarouselController)
+                .onDesiredLocationChanged(
+                    eq(MediaHierarchyManager.LOCATION_QS),
+                    any(MediaHostState::class.java),
+                    eq(false),
+                    anyLong(),
+                    anyLong()
+                )
+        }
+
+    @Test
     fun testQsExpandedChanged_noQqsMedia() {
         // When we are looking at QQS with active media
         whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogReceiverTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogReceiverTest.java
index e2cf87a..0879884 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogReceiverTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogReceiverTest.java
@@ -28,6 +28,7 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.settingslib.flags.Flags;
 import com.android.settingslib.media.MediaOutputConstants;
 import com.android.systemui.SysuiTestCase;
 
@@ -84,7 +85,20 @@
     }
 
     @Test
+    public void launchMediaOutputBroadcastDialog_flagOff_broadcastDialogFactoryNotCalled() {
+        mSetFlagsRule.disableFlags(Flags.FLAG_LEGACY_LE_AUDIO_SHARING);
+        Intent intent = new Intent(
+                MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG);
+        intent.putExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME, getContext().getPackageName());
+        mMediaOutputDialogReceiver.onReceive(getContext(), intent);
+
+        verify(mMockMediaOutputDialogFactory, never()).create(any(), anyBoolean(), any());
+        verify(mMockMediaOutputBroadcastDialogFactory, never()).create(any(), anyBoolean(), any());
+    }
+
+    @Test
     public void launchMediaOutputBroadcastDialog_ExtraPackageName_BroadcastDialogFactoryCalled() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_LEGACY_LE_AUDIO_SHARING);
         Intent intent = new Intent(
                 MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG);
         intent.putExtra(MediaOutputConstants.EXTRA_PACKAGE_NAME, getContext().getPackageName());
@@ -97,6 +111,7 @@
 
     @Test
     public void launchMediaOutputBroadcastDialog_WrongExtraKey_DialogBroadcastFactoryNotCalled() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_LEGACY_LE_AUDIO_SHARING);
         Intent intent = new Intent(
                 MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG);
         intent.putExtra("Wrong Package Name Key", getContext().getPackageName());
@@ -108,6 +123,7 @@
 
     @Test
     public void launchMediaOutputBroadcastDialog_NoExtra_BroadcastDialogFactoryNotCalled() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_LEGACY_LE_AUDIO_SHARING);
         Intent intent = new Intent(
                 MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG);
         mMediaOutputDialogReceiver.onReceive(getContext(), intent);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
index d9ddc8e..84300da 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
@@ -50,6 +50,7 @@
 import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+import com.android.settingslib.flags.Flags;
 import com.android.settingslib.media.LocalMediaManager;
 import com.android.settingslib.media.MediaDevice;
 import com.android.systemui.SysuiTestCase;
@@ -177,7 +178,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
+    @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
     public void getStopButtonVisibility_remoteBLEDevice_returnVisible() {
         when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
                 mLocalBluetoothLeBroadcast);
@@ -189,7 +190,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
+    @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
     public void getStopButtonVisibility_remoteNonBLEDevice_returnGone() {
         when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
                 mLocalBluetoothLeBroadcast);
@@ -210,7 +211,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
+    @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
     public void isBroadcastSupported_flagOnAndConnectBleDevice_returnsTrue() {
         when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
                 mLocalBluetoothLeBroadcast);
@@ -223,7 +224,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
+    @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
     public void isBroadcastSupported_flagOnAndNoBleDevice_returnsFalse() {
         when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
                 mLocalBluetoothLeBroadcast);
@@ -236,7 +237,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
+    @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
     public void isBroadcastSupported_notSupportBroadcastAndflagOn_returnsFalse() {
         FeatureFlagUtils.setEnabled(mContext,
                 FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, true);
@@ -245,7 +246,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
+    @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
     public void isBroadcastSupported_flagOffAndConnectToBleDevice_returnsTrue() {
         when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
                 mLocalBluetoothLeBroadcast);
@@ -258,7 +259,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
+    @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
     public void isBroadcastSupported_flagOffAndNoBleDevice_returnsTrue() {
         when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
                 mLocalBluetoothLeBroadcast);
@@ -271,7 +272,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
+    @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
     public void isBroadcastSupported_noBleDeviceAndEnabledBroadcast_returnsTrue() {
         when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
                 mLocalBluetoothLeBroadcast);
@@ -284,7 +285,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
+    @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
     public void isBroadcastSupported_noBleDeviceAndDisabledBroadcast_returnsFalse() {
         when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
                 mLocalBluetoothLeBroadcast);
@@ -297,7 +298,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
+    @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
     public void getBroadcastIconVisibility_isBroadcasting_returnVisible() {
         when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
                 mLocalBluetoothLeBroadcast);
@@ -309,7 +310,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
+    @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
     public void getBroadcastIconVisibility_noBroadcasting_returnGone() {
         when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
                 mLocalBluetoothLeBroadcast);
@@ -321,7 +322,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
+    @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
     public void getBroadcastIconVisibility_remoteNonLeDevice_returnGone() {
         when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
                 mLocalBluetoothLeBroadcast);
@@ -374,7 +375,7 @@
     }
 
     @Test
-    @RequiresFlagsEnabled(com.android.systemui.Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
+    @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING)
     public void getStopButtonText_supportsBroadcast_returnsBroadcastText() {
         String stopText = mContext.getText(R.string.media_output_broadcast).toString();
         MediaDevice mMediaDevice = mock(MediaDevice.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/OWNERS b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/OWNERS
new file mode 100644
index 0000000..100dd2e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/OWNERS
@@ -0,0 +1 @@
+include /packages/SystemUI/src/com/android/systemui/media/dialog/OWNERS
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/OWNERS b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/OWNERS
new file mode 100644
index 0000000..f87d93a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/OWNERS
@@ -0,0 +1 @@
+include /packages/SystemUI/src/com/android/systemui/mediaprojection/OWNERS
diff --git a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegateTest.kt
deleted file mode 100644
index e044eec..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/mediaprojection/permission/MediaProjectionPermissionDialogDelegateTest.kt
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2022 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.mediaprojection.permission
-
-import android.app.AlertDialog
-import android.media.projection.MediaProjectionConfig
-import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
-import android.view.WindowManager
-import android.widget.Spinner
-import android.widget.TextView
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.flags.FeatureFlagsClassic
-import com.android.systemui.flags.Flags
-import com.android.systemui.mediaprojection.MediaProjectionMetricsLogger
-import com.android.systemui.res.R
-import com.android.systemui.statusbar.phone.AlertDialogWithDelegate
-import com.android.systemui.statusbar.phone.SystemUIDialog
-import com.android.systemui.util.mockito.mock
-import junit.framework.Assert.assertEquals
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mockito.`when` as whenever
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
-class MediaProjectionPermissionDialogDelegateTest : SysuiTestCase() {
-
-    private lateinit var dialog: AlertDialog
-
-    private val flags = mock<FeatureFlagsClassic>()
-    private val onStartRecordingClicked = mock<Runnable>()
-    private val mediaProjectionMetricsLogger = mock<MediaProjectionMetricsLogger>()
-
-    private val mediaProjectionConfig: MediaProjectionConfig =
-        MediaProjectionConfig.createConfigForDefaultDisplay()
-    private val appName: String = "testApp"
-    private val hostUid: Int = 12345
-
-    private val resIdSingleApp = R.string.screen_share_permission_dialog_option_single_app
-    private val resIdFullScreen = R.string.screen_share_permission_dialog_option_entire_screen
-    private val resIdSingleAppDisabled =
-        R.string.media_projection_entry_app_permission_dialog_single_app_disabled
-
-    @Before
-    fun setUp() {
-        whenever(flags.isEnabled(Flags.WM_ENABLE_PARTIAL_SCREEN_SHARING)).thenReturn(true)
-    }
-
-    @After
-    fun teardown() {
-        if (::dialog.isInitialized) {
-            dialog.dismiss()
-        }
-    }
-
-    @Test
-    fun showDialog_forceShowPartialScreenShareFalse() {
-        // Set up dialog with MediaProjectionConfig.createConfigForDefaultDisplay() and
-        // overrideDisableSingleAppOption = false
-        val overrideDisableSingleAppOption = false
-        setUpAndShowDialog(overrideDisableSingleAppOption)
-
-        val spinner = dialog.requireViewById<Spinner>(R.id.screen_share_mode_spinner)
-        val secondOptionText =
-            spinner.adapter
-                .getDropDownView(1, null, spinner)
-                .findViewById<TextView>(android.R.id.text2)
-                ?.text
-
-        // check that the first option is full screen and enabled
-        assertEquals(context.getString(resIdFullScreen), spinner.selectedItem)
-
-        // check that the second option is single app and disabled
-        assertEquals(context.getString(resIdSingleAppDisabled, appName), secondOptionText)
-    }
-
-    @Test
-    fun showDialog_forceShowPartialScreenShareTrue() {
-        // Set up dialog with MediaProjectionConfig.createConfigForDefaultDisplay() and
-        // overrideDisableSingleAppOption = true
-        val overrideDisableSingleAppOption = true
-        setUpAndShowDialog(overrideDisableSingleAppOption)
-
-        val spinner = dialog.requireViewById<Spinner>(R.id.screen_share_mode_spinner)
-        val secondOptionText =
-            spinner.adapter
-                .getDropDownView(1, null, spinner)
-                .findViewById<TextView>(android.R.id.text1)
-                ?.text
-
-        // check that the first option is single app and enabled
-        assertEquals(context.getString(resIdSingleApp), spinner.selectedItem)
-
-        // check that the second option is full screen and enabled
-        assertEquals(context.getString(resIdFullScreen), secondOptionText)
-    }
-
-    private fun setUpAndShowDialog(overrideDisableSingleAppOption: Boolean) {
-        val delegate =
-            MediaProjectionPermissionDialogDelegate(
-                context,
-                mediaProjectionConfig,
-                {},
-                onStartRecordingClicked,
-                appName,
-                overrideDisableSingleAppOption,
-                hostUid,
-                mediaProjectionMetricsLogger
-            )
-
-        dialog = AlertDialogWithDelegate(context, R.style.Theme_SystemUI_Dialog, delegate)
-        SystemUIDialog.applyFlags(dialog)
-        SystemUIDialog.setDialogSize(dialog)
-
-        dialog.window?.addSystemFlags(
-            WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS
-        )
-
-        delegate.onCreate(dialog, savedInstanceState = null)
-        dialog.show()
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemFactoryTest.kt
index 92c7326..a8cd8c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemFactoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemFactoryTest.kt
@@ -16,10 +16,18 @@
 
 package com.android.systemui.qs.tiles.dialog.bluetooth
 
+import android.bluetooth.BluetoothDevice
+import android.content.pm.PackageInfo
+import android.content.pm.PackageManager
+import android.media.AudioManager
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import androidx.test.filters.SmallTest
+import com.android.settingslib.bluetooth.BluetoothUtils
 import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.settingslib.flags.Flags
 import com.android.systemui.SysuiTestCase
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
@@ -35,19 +43,26 @@
 @RunWith(AndroidTestingRunner::class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 class DeviceItemFactoryTest : SysuiTestCase() {
-
     @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
 
     @Mock private lateinit var cachedDevice: CachedBluetoothDevice
+    @Mock private lateinit var bluetoothDevice: BluetoothDevice
+    @Mock private lateinit var packageManager: PackageManager
 
     private val availableMediaDeviceItemFactory = AvailableMediaDeviceItemFactory()
     private val connectedDeviceItemFactory = ConnectedDeviceItemFactory()
     private val savedDeviceItemFactory = SavedDeviceItemFactory()
 
+    private val audioManager = context.getSystemService(AudioManager::class.java)!!
+
     @Before
     fun setup() {
         `when`(cachedDevice.name).thenReturn(DEVICE_NAME)
+        `when`(cachedDevice.address).thenReturn(DEVICE_ADDRESS)
+        `when`(cachedDevice.device).thenReturn(bluetoothDevice)
         `when`(cachedDevice.connectionSummary).thenReturn(CONNECTION_SUMMARY)
+
+        context.setMockPackageManager(packageManager)
     }
 
     @Test
@@ -72,6 +87,225 @@
         assertThat(deviceItem.background).isNotNull()
     }
 
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testSavedFactory_isFilterMatched_bondedAndNotConnected_returnsTrue() {
+        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
+        `when`(cachedDevice.isConnected).thenReturn(false)
+
+        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isTrue()
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testSavedFactory_isFilterMatched_connected_returnsFalse() {
+        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
+        `when`(cachedDevice.isConnected).thenReturn(true)
+
+        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isFalse()
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testSavedFactory_isFilterMatched_notBonded_returnsFalse() {
+        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_NONE)
+        `when`(cachedDevice.isConnected).thenReturn(false)
+
+        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isFalse()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testSavedFactory_isFilterMatched_exclusivelyManaged_returnsFalse() {
+        val exclusiveManagerName =
+            BluetoothUtils.getExclusiveManagers().firstOrNull() ?: FAKE_EXCLUSIVE_MANAGER_NAME
+        `when`(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER))
+            .thenReturn(exclusiveManagerName.toByteArray())
+        `when`(packageManager.getPackageInfo(exclusiveManagerName, 0)).thenReturn(PackageInfo())
+        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
+        `when`(cachedDevice.isConnected).thenReturn(false)
+
+        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isFalse()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testSavedFactory_isFilterMatched_noExclusiveManager_returnsTrue() {
+        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
+        `when`(cachedDevice.isConnected).thenReturn(false)
+
+        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isTrue()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testSavedFactory_isFilterMatched_notAllowedExclusiveManager_returnsTrue() {
+        `when`(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER))
+            .thenReturn(FAKE_EXCLUSIVE_MANAGER_NAME.toByteArray())
+        `when`(packageManager.getPackageInfo(FAKE_EXCLUSIVE_MANAGER_NAME, 0))
+            .thenReturn(PackageInfo())
+        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
+        `when`(cachedDevice.isConnected).thenReturn(false)
+
+        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isTrue()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testSavedFactory_isFilterMatched_uninstalledExclusiveManager_returnsTrue() {
+        val exclusiveManagerName =
+            BluetoothUtils.getExclusiveManagers().firstOrNull() ?: FAKE_EXCLUSIVE_MANAGER_NAME
+        `when`(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER))
+            .thenReturn(exclusiveManagerName.toByteArray())
+        `when`(packageManager.getPackageInfo(exclusiveManagerName, 0))
+            .thenThrow(PackageManager.NameNotFoundException("Test!"))
+        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
+        `when`(cachedDevice.isConnected).thenReturn(false)
+
+        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isTrue()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testSavedFactory_isFilterMatched_notExclusivelyManaged_notBonded_returnsFalse() {
+        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_NONE)
+        `when`(cachedDevice.isConnected).thenReturn(false)
+
+        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isFalse()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testSavedFactory_isFilterMatched_notExclusivelyManaged_connected_returnsFalse() {
+        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
+        `when`(cachedDevice.isConnected).thenReturn(true)
+
+        assertThat(savedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isFalse()
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testConnectedFactory_isFilterMatched_bondedAndConnected_returnsTrue() {
+        `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
+        `when`(bluetoothDevice.isConnected).thenReturn(true)
+        audioManager.setMode(AudioManager.MODE_NORMAL)
+
+        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isTrue()
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testConnectedFactory_isFilterMatched_notConnected_returnsFalse() {
+        `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
+        `when`(bluetoothDevice.isConnected).thenReturn(false)
+        audioManager.setMode(AudioManager.MODE_NORMAL)
+
+        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isFalse()
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testConnectedFactory_isFilterMatched_notBonded_returnsFalse() {
+        `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_NONE)
+        `when`(bluetoothDevice.isConnected).thenReturn(true)
+        audioManager.setMode(AudioManager.MODE_NORMAL)
+
+        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isFalse()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testConnectedFactory_isFilterMatched_exclusivelyManaged_returnsFalse() {
+        val exclusiveManagerName =
+            BluetoothUtils.getExclusiveManagers().firstOrNull() ?: FAKE_EXCLUSIVE_MANAGER_NAME
+        `when`(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER))
+            .thenReturn(exclusiveManagerName.toByteArray())
+        `when`(packageManager.getPackageInfo(exclusiveManagerName, 0)).thenReturn(PackageInfo())
+        `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
+        `when`(bluetoothDevice.isConnected).thenReturn(true)
+        audioManager.setMode(AudioManager.MODE_NORMAL)
+
+        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isFalse()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testConnectedFactory_isFilterMatched_noExclusiveManager_returnsTrue() {
+        `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
+        `when`(bluetoothDevice.isConnected).thenReturn(true)
+        audioManager.setMode(AudioManager.MODE_NORMAL)
+
+        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isTrue()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testConnectedFactory_isFilterMatched_notAllowedExclusiveManager_returnsTrue() {
+        `when`(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER))
+            .thenReturn(FAKE_EXCLUSIVE_MANAGER_NAME.toByteArray())
+        `when`(packageManager.getPackageInfo(FAKE_EXCLUSIVE_MANAGER_NAME, 0))
+            .thenReturn(PackageInfo())
+        `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
+        `when`(bluetoothDevice.isConnected).thenReturn(true)
+        audioManager.setMode(AudioManager.MODE_NORMAL)
+
+        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isTrue()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testConnectedFactory_isFilterMatched_uninstalledExclusiveManager_returnsTrue() {
+        val exclusiveManagerName =
+            BluetoothUtils.getExclusiveManagers().firstOrNull() ?: FAKE_EXCLUSIVE_MANAGER_NAME
+        `when`(bluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER))
+            .thenReturn(exclusiveManagerName.toByteArray())
+        `when`(packageManager.getPackageInfo(exclusiveManagerName, 0))
+            .thenThrow(PackageManager.NameNotFoundException("Test!"))
+        `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
+        `when`(bluetoothDevice.isConnected).thenReturn(true)
+        audioManager.setMode(AudioManager.MODE_NORMAL)
+
+        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isTrue()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testConnectedFactory_isFilterMatched_notExclusivelyManaged_notBonded_returnsFalse() {
+        `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_NONE)
+        `when`(bluetoothDevice.isConnected).thenReturn(true)
+        audioManager.setMode(AudioManager.MODE_NORMAL)
+
+        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isFalse()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+    fun testConnectedFactory_isFilterMatched_notExclusivelyManaged_notConnected_returnsFalse() {
+        `when`(bluetoothDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
+        `when`(bluetoothDevice.isConnected).thenReturn(false)
+        audioManager.setMode(AudioManager.MODE_NORMAL)
+
+        assertThat(connectedDeviceItemFactory.isFilterMatched(context, cachedDevice, audioManager))
+            .isFalse()
+    }
+
     private fun assertDeviceItem(deviceItem: DeviceItem?, deviceItemType: DeviceItemType) {
         assertThat(deviceItem).isNotNull()
         assertThat(deviceItem!!.type).isEqualTo(deviceItemType)
@@ -83,5 +317,7 @@
     companion object {
         const val DEVICE_NAME = "DeviceName"
         const val CONNECTION_SUMMARY = "ConnectionSummary"
+        private const val FAKE_EXCLUSIVE_MANAGER_NAME = "com.fake.name"
+        private const val DEVICE_ADDRESS = "04:52:C7:0B:D8:3C"
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractorTest.kt
index e236f4a..ddf0b9a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/DeviceItemInteractorTest.kt
@@ -279,6 +279,7 @@
     ): DeviceItemFactory {
         return object : DeviceItemFactory() {
             override fun isFilterMatched(
+                context: Context,
                 cachedDevice: CachedBluetoothDevice,
                 audioManager: AudioManager?
             ) = isFilterMatchFunc(cachedDevice)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt
new file mode 100644
index 0000000..0c32470
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot
+
+import android.content.Intent
+import android.os.Process.myUserHandle
+import android.platform.test.annotations.EnableFlags
+import android.testing.AndroidTestingRunner
+import android.testing.TestableContext
+import com.android.systemui.Flags
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.settings.DisplayTracker
+import com.android.systemui.shared.system.ActivityManagerWrapper
+import com.android.systemui.statusbar.phone.CentralSurfaces
+import com.android.systemui.util.mockito.mock
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestCoroutineScheduler
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.verify
+
+@RunWith(AndroidTestingRunner::class)
+class ActionIntentExecutorTest : SysuiTestCase() {
+
+    private val scheduler = TestCoroutineScheduler()
+    private val mainDispatcher = StandardTestDispatcher(scheduler)
+    private val testScope = TestScope(mainDispatcher)
+    private val testableContext = TestableContext(mContext)
+
+    private val activityManagerWrapper = mock<ActivityManagerWrapper>()
+    private val displayTracker = mock<DisplayTracker>()
+    private val keyguardController = mock<ScreenshotKeyguardController>()
+
+    private val actionIntentExecutor =
+        ActionIntentExecutor(
+            testableContext,
+            activityManagerWrapper,
+            testScope,
+            mainDispatcher,
+            displayTracker,
+            keyguardController,
+        )
+
+    @Test
+    @EnableFlags(Flags.FLAG_SCREENSHOT_ACTION_DISMISS_SYSTEM_WINDOWS)
+    fun launchIntent_callsCloseSystemWindows() =
+        testScope.runTest {
+            val intent = Intent(Intent.ACTION_EDIT).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK }
+            val userHandle = myUserHandle()
+
+            actionIntentExecutor.launchIntent(intent, null, userHandle, false)
+            scheduler.advanceUntilIdle()
+
+            verify(activityManagerWrapper)
+                .closeSystemWindows(CentralSurfaces.SYSTEM_DIALOG_REASON_SCREENSHOT)
+        }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
index 032ec74..774aa51 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserTrackerImplTest.kt
@@ -371,7 +371,6 @@
 
         val captor = ArgumentCaptor.forClass(IUserSwitchObserver::class.java)
         verify(iActivityManager).registerUserSwitchObserver(capture(captor), anyString())
-        captor.value.onBeforeUserSwitching(newID)
         captor.value.onUserSwitching(newID, userSwitchingReply)
 
         assertThat(callback.calledOnUserChanging).isEqualTo(0)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt
index b94e483..31acd86 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/brightness/BrightnessDialogTest.kt
@@ -23,6 +23,7 @@
 import android.view.View
 import android.view.ViewGroup
 import android.view.WindowManagerPolicyConstants.EXTRA_FROM_BRIGHTNESS_KEY
+import androidx.test.filters.FlakyTest
 import androidx.test.filters.SmallTest
 import androidx.test.rule.ActivityTestRule
 import com.android.systemui.SysuiTestCase
@@ -183,6 +184,7 @@
     }
 
     @OptIn(FlowPreview::class)
+    @FlakyTest(bugId = 326186573)
     @Test
     fun testFinishOnQSExpanded() = runTest {
         val isQSExpanded = MutableStateFlow(false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
index 1dc5f7d..665fc75 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
@@ -26,17 +26,20 @@
 import android.view.WindowManager
 import android.widget.FrameLayout
 import androidx.test.filters.SmallTest
+import com.android.systemui.Flags
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.communal.data.repository.FakeCommunalRepository
 import com.android.systemui.communal.data.repository.fakeCommunalRepository
 import com.android.systemui.communal.domain.interactor.CommunalInteractor
 import com.android.systemui.communal.domain.interactor.communalInteractor
+import com.android.systemui.communal.domain.interactor.setCommunalAvailable
 import com.android.systemui.communal.shared.model.CommunalSceneKey
 import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
 import com.android.systemui.compose.ComposeFacade
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
 import com.android.systemui.res.R
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.testKosmos
@@ -45,6 +48,7 @@
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.launch
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import org.junit.After
 import org.junit.Assert.assertThrows
@@ -114,6 +118,14 @@
             BOTTOM_SWIPE_REGION_WIDTH
         )
 
+        // Make communal available so that communalInteractor.desiredScene accurately reflects
+        // scene changes instead of just returning Blank.
+        mSetFlagsRule.enableFlags(Flags.FLAG_COMMUNAL_HUB)
+        with(kosmos.testScope) {
+            launch { kosmos.setCommunalAvailable(true) }
+            testScheduler.runCurrent()
+        }
+
         initAndAttachContainerView()
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ShadeTransitionControllerTest.kt
index 7737b43..651006d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/transition/ShadeTransitionControllerTest.kt
@@ -1,15 +1,46 @@
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
 package com.android.systemui.shade.transition
 
+import android.platform.test.annotations.DisableFlags
 import android.testing.AndroidTestingRunner
 import androidx.test.filters.SmallTest
+import com.android.systemui.Flags.FLAG_SCENE_CONTAINER
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.deviceentry.data.repository.FakeDeviceEntryRepository
+import com.android.systemui.deviceentry.data.repository.fakeDeviceEntryRepository
+import com.android.systemui.deviceentry.domain.interactor.DeviceUnlockedInteractor
+import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.flags.EnableSceneContainer
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.scene.domain.interactor.PanelExpansionInteractor
+import com.android.systemui.scene.domain.interactor.SceneInteractor
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.scene.shared.model.FakeSceneDataSource
+import com.android.systemui.scene.shared.model.ObservableTransitionState
+import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.scene.shared.model.fakeSceneDataSource
 import com.android.systemui.shade.STATE_OPENING
 import com.android.systemui.shade.ShadeExpansionChangeEvent
 import com.android.systemui.shade.ShadeExpansionStateManager
 import com.android.systemui.statusbar.SysuiStatusBarStateController
+import com.android.systemui.statusbar.notification.stack.ui.viewmodel.panelExpansionInteractor
 import com.android.systemui.statusbar.policy.FakeConfigurationController
 import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
+import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.flowOf
+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
@@ -29,32 +60,95 @@
 
     private val configurationController = FakeConfigurationController()
     private val shadeExpansionStateManager = ShadeExpansionStateManager()
+    private val kosmos = testKosmos()
+    private lateinit var testScope: TestScope
+    private lateinit var applicationScope: CoroutineScope
+    private lateinit var panelExpansionInteractor: PanelExpansionInteractor
+    private lateinit var deviceEntryRepository: FakeDeviceEntryRepository
+    private lateinit var deviceUnlockedInteractor: DeviceUnlockedInteractor
+    private lateinit var sceneInteractor: SceneInteractor
+    private lateinit var fakeSceneDataSource: FakeSceneDataSource
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
 
+        testScope = kosmos.testScope
+        applicationScope = kosmos.applicationCoroutineScope
+        panelExpansionInteractor = kosmos.panelExpansionInteractor
+        deviceEntryRepository = kosmos.fakeDeviceEntryRepository
+        deviceUnlockedInteractor = kosmos.deviceUnlockedInteractor
+        sceneInteractor = kosmos.sceneInteractor
+        fakeSceneDataSource = kosmos.fakeSceneDataSource
+
         controller =
             ShadeTransitionController(
+                applicationScope,
                 configurationController,
                 shadeExpansionStateManager,
                 dumpManager,
                 context,
                 scrimShadeTransitionController,
                 statusBarStateController,
-                    ResourcesSplitShadeStateController()
-            )
+                ResourcesSplitShadeStateController(),
+            ) {
+                panelExpansionInteractor
+            }
     }
 
     @Test
+    @DisableFlags(FLAG_SCENE_CONTAINER)
     fun onPanelStateChanged_forwardsToScrimTransitionController() {
-        startPanelExpansion()
+        startLegacyPanelExpansion()
 
         verify(scrimShadeTransitionController).onPanelStateChanged(STATE_OPENING)
         verify(scrimShadeTransitionController).onPanelExpansionChanged(DEFAULT_EXPANSION_EVENT)
     }
 
-    private fun startPanelExpansion() {
+    @Test
+    @EnableSceneContainer
+    fun sceneChanges_forwardsToScrimTransitionController() =
+        testScope.runTest {
+            var latestChangeEvent: ShadeExpansionChangeEvent? = null
+            whenever(scrimShadeTransitionController.onPanelExpansionChanged(any())).thenAnswer {
+                latestChangeEvent = it.arguments[0] as ShadeExpansionChangeEvent
+                Unit
+            }
+            setUnlocked(true)
+            val transitionState =
+                MutableStateFlow<ObservableTransitionState>(
+                    ObservableTransitionState.Idle(SceneKey.Gone)
+                )
+            sceneInteractor.setTransitionState(transitionState)
+
+            changeScene(SceneKey.Gone, transitionState)
+            val currentScene by collectLastValue(sceneInteractor.currentScene)
+            assertThat(currentScene).isEqualTo(SceneKey.Gone)
+
+            assertThat(latestChangeEvent)
+                .isEqualTo(
+                    ShadeExpansionChangeEvent(
+                        fraction = 0f,
+                        expanded = false,
+                        tracking = true,
+                        dragDownPxAmount = 0f,
+                    )
+                )
+
+            changeScene(SceneKey.Shade, transitionState) { progress ->
+                assertThat(latestChangeEvent)
+                    .isEqualTo(
+                        ShadeExpansionChangeEvent(
+                            fraction = progress,
+                            expanded = progress > 0,
+                            tracking = true,
+                            dragDownPxAmount = 0f,
+                        )
+                    )
+            }
+        }
+
+    private fun startLegacyPanelExpansion() {
         shadeExpansionStateManager.onPanelExpansionChanged(
             DEFAULT_EXPANSION_EVENT.fraction,
             DEFAULT_EXPANSION_EVENT.expanded,
@@ -63,6 +157,52 @@
         )
     }
 
+    private fun TestScope.setUnlocked(isUnlocked: Boolean) {
+        val isDeviceUnlocked by collectLastValue(deviceUnlockedInteractor.isDeviceUnlocked)
+        deviceEntryRepository.setUnlocked(isUnlocked)
+        runCurrent()
+
+        assertThat(isDeviceUnlocked).isEqualTo(isUnlocked)
+    }
+
+    private fun TestScope.changeScene(
+        toScene: SceneKey,
+        transitionState: MutableStateFlow<ObservableTransitionState>,
+        assertDuringProgress: ((progress: Float) -> Unit) = {},
+    ) {
+        val currentScene by collectLastValue(sceneInteractor.currentScene)
+        val progressFlow = MutableStateFlow(0f)
+        transitionState.value =
+            ObservableTransitionState.Transition(
+                fromScene = checkNotNull(currentScene),
+                toScene = toScene,
+                progress = progressFlow,
+                isInitiatedByUserInput = true,
+                isUserInputOngoing = flowOf(true),
+            )
+        runCurrent()
+        assertDuringProgress(progressFlow.value)
+
+        progressFlow.value = 0.2f
+        runCurrent()
+        assertDuringProgress(progressFlow.value)
+
+        progressFlow.value = 0.6f
+        runCurrent()
+        assertDuringProgress(progressFlow.value)
+
+        progressFlow.value = 1f
+        runCurrent()
+        assertDuringProgress(progressFlow.value)
+
+        transitionState.value = ObservableTransitionState.Idle(toScene)
+        fakeSceneDataSource.changeScene(toScene)
+        runCurrent()
+        assertDuringProgress(progressFlow.value)
+
+        assertThat(currentScene).isEqualTo(toScene)
+    }
+
     companion object {
         private const val DEFAULT_DRAG_DOWN_AMOUNT = 123f
         private val DEFAULT_EXPANSION_EVENT =
@@ -70,6 +210,7 @@
                 fraction = 0.5f,
                 expanded = true,
                 tracking = true,
-                dragDownPxAmount = DEFAULT_DRAG_DOWN_AMOUNT)
+                dragDownPxAmount = DEFAULT_DRAG_DOWN_AMOUNT
+            )
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java
index 460892a..660e8da 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/system/RemoteTransitionTest.java
@@ -49,6 +49,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.animation.RemoteAnimationTargetCompat;
 import com.android.wm.shell.shared.TransitionUtil;
 
 import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinatorTest.kt
new file mode 100644
index 0000000..7daadb0
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAlertTimeCoordinatorTest.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2024 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.collection.coordinator
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.collection.listbuilder.OnAfterRenderEntryListener
+import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener
+import com.android.systemui.statusbar.notification.collection.render.NotifRowController
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.withArgCaptor
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoMoreInteractions
+import org.mockito.MockitoAnnotations.initMocks
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper
+class RowAlertTimeCoordinatorTest : SysuiTestCase() {
+    private lateinit var coordinator: RowAlertTimeCoordinator
+    private lateinit var beforeFinalizeFilterListener: OnBeforeFinalizeFilterListener
+    private lateinit var afterRenderEntryListener: OnAfterRenderEntryListener
+
+    @Mock private lateinit var pipeline: NotifPipeline
+
+    @Before
+    fun setUp() {
+        initMocks(this)
+        coordinator = RowAlertTimeCoordinator()
+        coordinator.attach(pipeline)
+        beforeFinalizeFilterListener = withArgCaptor {
+            verify(pipeline).addOnBeforeFinalizeFilterListener(capture())
+        }
+        afterRenderEntryListener = withArgCaptor {
+            verify(pipeline).addOnAfterRenderEntryListener(capture())
+        }
+    }
+
+    @Test
+    fun testSetLastAudiblyAlerted() {
+        val entry1 = NotificationEntryBuilder().setLastAudiblyAlertedMs(10).build()
+        val entry2 = NotificationEntryBuilder().setLastAudiblyAlertedMs(20).build()
+        val summary = NotificationEntryBuilder().setLastAudiblyAlertedMs(5).build()
+        val child1 = NotificationEntryBuilder().setLastAudiblyAlertedMs(0).build()
+        val child2 = NotificationEntryBuilder().setLastAudiblyAlertedMs(8).build()
+        val group =
+            GroupEntryBuilder()
+                .setKey("group")
+                .setSummary(summary)
+                .addChild(child1)
+                .addChild(child2)
+                .build()
+
+        val entries = listOf(entry1, summary, child1, child2, entry2)
+
+        beforeFinalizeFilterListener.onBeforeFinalizeFilter(listOf(entry1, group, entry2))
+        val actualTimesSet =
+            entries.associateWith {
+                val rowController = mock<NotifRowController>()
+                afterRenderEntryListener.onAfterRenderEntry(it, rowController)
+                withArgCaptor<Long> {
+                    verify(rowController).setLastAudibleMs(capture())
+                    verifyNoMoreInteractions(rowController)
+                }
+            }
+        val expectedTimesSet =
+            mapOf(
+                entry1 to 10L,
+                entry2 to 20L,
+                summary to 8L,
+                child1 to 0L,
+                child2 to 8L,
+            )
+        assertThat(actualTimesSet).containsExactlyEntriesIn(expectedTimesSet)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinatorTest.kt
index fa669fc..a66f8ce 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RowAppearanceCoordinatorTest.kt
@@ -76,7 +76,7 @@
             verify(pipeline).addOnAfterRenderEntryListener(capture())
         }
         whenever(assistantFeedbackController.getFeedbackIcon(any())).thenReturn(FeedbackIcon(1, 2))
-        entry1 = NotificationEntryBuilder().setSection(section1).setLastAudiblyAlertedMs(17).build()
+        entry1 = NotificationEntryBuilder().setSection(section1).build()
         entry2 = NotificationEntryBuilder().setSection(section2).build()
     }
 
@@ -103,12 +103,6 @@
     }
 
     @Test
-    fun testSetLastAudiblyAlerted() {
-        afterRenderEntryListener.onAfterRenderEntry(entry1, controller1)
-        verify(controller1).setLastAudibleMs(eq(17.toLong()))
-    }
-
-    @Test
     fun testSetFeedbackIcon() {
         afterRenderEntryListener.onAfterRenderEntry(entry1, controller1)
         verify(controller1).setFeedbackIcon(eq(FeedbackIcon(1, 2)))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt
index 7592356..933b5b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt
@@ -24,6 +24,7 @@
 import androidx.test.filters.SmallTest
 import com.android.server.notification.Flags
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.log.logcatLogBuffer
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.settings.FakeGlobalSettings
 import com.android.systemui.util.time.FakeSystemClock
@@ -38,6 +39,8 @@
 @RunWith(AndroidTestingRunner::class)
 @DisableFlags(Flags.FLAG_SCREENSHARE_NOTIFICATION_HIDING)
 class SensitiveNotificationProtectionControllerFlagDisabledTest : SysuiTestCase() {
+    private val logger = SensitiveNotificationProtectionControllerLogger(logcatLogBuffer())
+
     @Mock private lateinit var handler: Handler
     @Mock private lateinit var activityManager: IActivityManager
     @Mock private lateinit var mediaProjectionManager: MediaProjectionManager
@@ -54,7 +57,8 @@
                 mediaProjectionManager,
                 activityManager,
                 handler,
-                FakeExecutor(FakeSystemClock())
+                FakeExecutor(FakeSystemClock()),
+                logger
             )
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt
index a2af38f..4b4e315 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt
@@ -34,6 +34,7 @@
 import androidx.test.filters.SmallTest
 import com.android.server.notification.Flags
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.log.logcatLogBuffer
 import com.android.systemui.statusbar.RankingBuilder
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
@@ -63,6 +64,8 @@
 @RunWithLooper
 @EnableFlags(Flags.FLAG_SCREENSHARE_NOTIFICATION_HIDING)
 class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
+    private val logger = SensitiveNotificationProtectionControllerLogger(logcatLogBuffer())
+
     @Mock private lateinit var activityManager: IActivityManager
     @Mock private lateinit var mediaProjectionManager: MediaProjectionManager
     @Mock private lateinit var mediaProjectionInfo: MediaProjectionInfo
@@ -93,7 +96,8 @@
                 mediaProjectionManager,
                 activityManager,
                 mockExecutorHandler(executor),
-                executor
+                executor,
+                logger
             )
 
         // Process pending work (getting global setting and list of exemptions)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseControllerTest.kt
index 203096a..08b49f0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseControllerTest.kt
@@ -166,4 +166,28 @@
             assertThat(config.color).isEqualTo(expectedColor)
         }
     }
+
+    @Test
+    fun play_initializesShader() {
+        val expectedNoiseOffset = floatArrayOf(0.1f, 0.2f, 0.3f)
+        val config =
+            TurbulenceNoiseAnimationConfig(
+                noiseOffsetX = expectedNoiseOffset[0],
+                noiseOffsetY = expectedNoiseOffset[1],
+                noiseOffsetZ = expectedNoiseOffset[2]
+            )
+        val turbulenceNoiseView = TurbulenceNoiseView(context, null)
+        val turbulenceNoiseController = TurbulenceNoiseController(turbulenceNoiseView)
+
+        fakeExecutor.execute {
+            turbulenceNoiseController.play(SIMPLEX_NOISE, config)
+
+            assertThat(turbulenceNoiseView.noiseConfig).isNotNull()
+            val shader = turbulenceNoiseView.turbulenceNoiseShader!!
+            assertThat(shader).isNotNull()
+            assertThat(shader.noiseOffsetX).isEqualTo(expectedNoiseOffset[0])
+            assertThat(shader.noiseOffsetY).isEqualTo(expectedNoiseOffset[1])
+            assertThat(shader.noiseOffsetZ).isEqualTo(expectedNoiseOffset[2])
+        }
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java
index 766a5ce..5d34120 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/service/ObservableServiceConnectionTest.java
@@ -200,4 +200,25 @@
         assertThat(connection.bind()).isFalse();
         verify(mContext).unbindService(connection);
     }
+
+    @Test
+    public void testUnbindDoesNotCallUnbindServiceWhenBindThrowsError() {
+        ObservableServiceConnection<Foo> connection = new ObservableServiceConnection<>(mContext,
+                mIntent, mUserTracker, mExecutor, mTransformer);
+        connection.addCallback(mCallback);
+
+        when(mContext.bindServiceAsUser(eq(mIntent), eq(connection), anyInt(),
+                eq(UserHandle.of(MAIN_USER_ID))))
+                .thenThrow(new SecurityException());
+
+        // Verify that bind returns false and we properly unbind.
+        assertThat(connection.bind()).isFalse();
+        verify(mContext).unbindService(connection);
+
+        clearInvocations(mContext);
+
+        // Ensure unbind after the failed bind has no effect.
+        connection.unbind();
+        verify(mContext, never()).unbindService(eq(connection));
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
index d2e0386..3a6324d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java
@@ -61,7 +61,6 @@
 import android.widget.SeekBar;
 
 import androidx.test.core.view.MotionEventBuilder;
-import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.jank.InteractionJankMonitor;
@@ -502,7 +501,6 @@
     }
 
     @Test
-    @FlakyTest(bugId = 326204750)
     public void dialogDestroy_removesPostureControllerCallback() {
         verify(mPostureController, never()).removeCallback(any());
         mDialog.destroy();
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 b25ac24..a930860 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -26,6 +26,7 @@
 import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.notification.Flags.FLAG_SCREENSHARE_NOTIFICATION_HIDING;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -46,6 +47,7 @@
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
 import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
@@ -73,6 +75,8 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
 import android.service.dreams.IDreamManager;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.ZenModeConfig;
@@ -161,6 +165,7 @@
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;
+import com.android.systemui.statusbar.policy.SensitiveNotificationProtectionController;
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository;
 import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository;
@@ -257,6 +262,8 @@
     private NotificationShadeWindowView mNotificationShadeWindowView;
     @Mock
     private AuthController mAuthController;
+    @Mock
+    private SensitiveNotificationProtectionController mSensitiveNotificationProtectionController;
 
     private SysUiState mSysUiState;
     private boolean mSysUiStateBubblesExpanded;
@@ -272,6 +279,8 @@
     private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverArgumentCaptor;
     @Captor
     private ArgumentCaptor<KeyguardStateController.Callback> mKeyguardStateControllerCallbackCaptor;
+    @Captor
+    private ArgumentCaptor<Runnable> mSensitiveStateChangedListener;
 
     private BubblesManager mBubblesManager;
     private TestableBubbleController mBubbleController;
@@ -594,6 +603,7 @@
                 interruptionDecisionProvider,
                 mZenModeController,
                 mLockscreenUserManager,
+                mSensitiveNotificationProtectionController,
                 mCommonNotifCollection,
                 mNotifPipeline,
                 mSysUiState,
@@ -2203,6 +2213,33 @@
         assertThat(mBubbleController.getLayerView().isExpanded()).isFalse();
     }
 
+    @DisableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING)
+    @Test
+    public void doesNotRegisterSensitiveStateListener() {
+        verifyZeroInteractions(mSensitiveNotificationProtectionController);
+    }
+
+    @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING)
+    @Test
+    public void registerSensitiveStateListener() {
+        verify(mSensitiveNotificationProtectionController).registerSensitiveStateListener(any());
+    }
+
+    @EnableFlags(FLAG_SCREENSHARE_NOTIFICATION_HIDING)
+    @Test
+    public void onSensitiveNotificationProtectionStateChanged() {
+        verify(mSensitiveNotificationProtectionController, atLeastOnce())
+                .registerSensitiveStateListener(mSensitiveStateChangedListener.capture());
+
+        when(mSensitiveNotificationProtectionController.isSensitiveStateActive()).thenReturn(true);
+        mSensitiveStateChangedListener.getValue().run();
+        verify(mBubbleController).onSensitiveNotificationProtectionStateChanged(true);
+
+        when(mSensitiveNotificationProtectionController.isSensitiveStateActive()).thenReturn(false);
+        mSensitiveStateChangedListener.getValue().run();
+        verify(mBubbleController).onSensitiveNotificationProtectionStateChanged(false);
+    }
+
     /** Creates a bubble using the userId and package. */
     private Bubble createBubble(int userId, String pkg) {
         final UserHandle userHandle = new UserHandle(userId);
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/assist/data/repository/AssistRepositoryKosmos.kt
similarity index 66%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/assist/data/repository/AssistRepositoryKosmos.kt
index b370859..96155ed 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/assist/data/repository/AssistRepositoryKosmos.kt
@@ -14,14 +14,8 @@
  * limitations under the License.
  */
 
-package com.android.systemui.keyguard.ui.viewmodel
+package com.android.systemui.assist.data.repository
 
-import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
 import com.android.systemui.kosmos.Kosmos
 
-val Kosmos.dreamingToGlanceableHubTransitionViewModel by
-    Kosmos.Fixture {
-        DreamingToGlanceableHubTransitionViewModel(
-            animationFlow = keyguardTransitionAnimationFlow,
-        )
-    }
+val Kosmos.assistRepository by Kosmos.Fixture { AssistRepository() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/assist/domain/interactor/AssistInteractorKosmos.kt
similarity index 66%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/assist/domain/interactor/AssistInteractorKosmos.kt
index b370859..c3c1131 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/assist/domain/interactor/AssistInteractorKosmos.kt
@@ -14,14 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.systemui.keyguard.ui.viewmodel
+package com.android.systemui.assist.domain.interactor
 
-import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
+import com.android.systemui.assist.data.repository.assistRepository
 import com.android.systemui.kosmos.Kosmos
 
-val Kosmos.dreamingToGlanceableHubTransitionViewModel by
-    Kosmos.Fixture {
-        DreamingToGlanceableHubTransitionViewModel(
-            animationFlow = keyguardTransitionAnimationFlow,
-        )
-    }
+val Kosmos.assistInteractor by Kosmos.Fixture { AssistInteractor(assistRepository) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFacePropertyRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFacePropertyRepository.kt
index 77f501f..68ef555 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFacePropertyRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakeFacePropertyRepository.kt
@@ -33,6 +33,10 @@
     override val sensorLocation: StateFlow<Point?>
         get() = faceSensorLocation
 
+    private val currentCameraInfo = MutableStateFlow<CameraInfo?>(null)
+    override val cameraInfo: StateFlow<CameraInfo?>
+        get() = currentCameraInfo
+
     fun setLockoutMode(userId: Int, mode: LockoutMode) {
         lockoutModesForUser[userId] = mode
     }
@@ -47,4 +51,8 @@
     fun setSensorLocation(value: Point?) {
         faceSensorLocation.value = value
     }
+
+    fun setCameraIno(value: CameraInfo?) {
+        currentCameraInfo.value = value
+    }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFake.java b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFake.java
index 5038285..974a11c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFake.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/classifier/FalsingManagerFake.java
@@ -201,4 +201,13 @@
     public List<FalsingTapListener> getTapListeners() {
         return mTapListeners;
     }
+
+    /**
+     * Calls every registered {@link FalsingBeliefListener} as if false touch occurred.
+     */
+    public void sendFalsingBelief() {
+        for (FalsingBeliefListener listener : mFalsingBeliefListeners) {
+            listener.onFalse();
+        }
+    }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
index 6af08d3..6ac702e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/domain/interactor/CommunalInteractorKosmos.kt
@@ -31,6 +31,7 @@
 import com.android.systemui.log.logcatLogBuffer
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.shared.flag.fakeSceneContainerFlags
+import com.android.systemui.settings.userTracker
 import com.android.systemui.smartspace.data.repository.smartspaceRepository
 import com.android.systemui.user.data.repository.fakeUserRepository
 import com.android.systemui.util.mockito.mock
@@ -46,6 +47,7 @@
         appWidgetHost = mock(),
         keyguardInteractor = keyguardInteractor,
         editWidgetsActivityStarter = editWidgetsActivityStarter,
+        userTracker = userTracker,
         logBuffer = logcatLogBuffer("CommunalInteractor"),
         tableLogBuffer = mock(),
         communalSettingsInteractor = communalSettingsInteractor,
@@ -60,9 +62,11 @@
     fakeFeatureFlagsClassic.set(Flags.COMMUNAL_SERVICE_ENABLED, available)
     if (available) {
         fakeUserRepository.asMainUser()
-        with(fakeKeyguardRepository) {
-            setIsEncryptedOrLockdown(false)
-            setKeyguardShowing(true)
-        }
+    } else {
+        fakeUserRepository.asDefaultUser()
+    }
+    with(fakeKeyguardRepository) {
+        setIsEncryptedOrLockdown(!available)
+        setKeyguardShowing(available)
     }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitionsKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitionsKosmos.kt
index 55885bf..5dd5073 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitionsKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitionsKosmos.kt
@@ -19,13 +19,11 @@
 import com.android.systemui.communal.domain.interactor.communalInteractor
 import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
 import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.kosmos.applicationCoroutineScope
 import com.android.systemui.kosmos.testDispatcher
 
 val Kosmos.glanceableHubTransitions by
     Kosmos.Fixture {
         GlanceableHubTransitions(
-            scope = applicationCoroutineScope,
             bgDispatcher = testDispatcher,
             transitionRepository = keyguardTransitionRepository,
             transitionInteractor = keyguardTransitionInteractor,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorKosmos.kt
index d9a3192..8b0bba1 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/KeyguardBlueprintInteractorKosmos.kt
@@ -29,5 +29,6 @@
             applicationScope = applicationCoroutineScope,
             context = applicationContext,
             splitShadeStateController = splitShadeStateController,
+            clockInteractor = keyguardClockInteractor,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModelKosmos.kt
similarity index 62%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModelKosmos.kt
index b370859..c6f0706 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerToDozingTransitionViewModelKosmos.kt
@@ -16,12 +16,16 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor
 import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 
-val Kosmos.dreamingToGlanceableHubTransitionViewModel by
-    Kosmos.Fixture {
-        DreamingToGlanceableHubTransitionViewModel(
-            animationFlow = keyguardTransitionAnimationFlow,
-        )
-    }
+@ExperimentalCoroutinesApi
+val Kosmos.alternateBouncerToDozingTransitionViewModel by Fixture {
+    AlternateBouncerToDozingTransitionViewModel(
+        deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor,
+        animationFlow = keyguardTransitionAnimationFlow,
+    )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelKosmos.kt
similarity index 73%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelKosmos.kt
index b370859..36ddc29 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToGoneTransitionViewModelKosmos.kt
@@ -18,10 +18,12 @@
 
 import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 
-val Kosmos.dreamingToGlanceableHubTransitionViewModel by
-    Kosmos.Fixture {
-        DreamingToGlanceableHubTransitionViewModel(
-            animationFlow = keyguardTransitionAnimationFlow,
-        )
-    }
+@ExperimentalCoroutinesApi
+val Kosmos.dozingToGoneTransitionViewModel by Fixture {
+    DozingToGoneTransitionViewModel(
+        animationFlow = keyguardTransitionAnimationFlow,
+    )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelKosmos.kt
index 400a0d8..de52d84 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToLockscreenTransitionViewModelKosmos.kt
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-@file:OptIn(ExperimentalCoroutinesApi::class)
-
 package com.android.systemui.keyguard.ui.viewmodel
 
 import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
@@ -23,6 +21,7 @@
 import com.android.systemui.kosmos.Kosmos.Fixture
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 
+@ExperimentalCoroutinesApi
 val Kosmos.dozingToLockscreenTransitionViewModel by Fixture {
     DozingToLockscreenTransitionViewModel(
         animationFlow = keyguardTransitionAnimationFlow,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModelKosmos.kt
similarity index 71%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModelKosmos.kt
index b370859..dc6b26f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DozingToPrimaryBouncerTransitionViewModelKosmos.kt
@@ -18,10 +18,12 @@
 
 import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 
-val Kosmos.dreamingToGlanceableHubTransitionViewModel by
-    Kosmos.Fixture {
-        DreamingToGlanceableHubTransitionViewModel(
-            animationFlow = keyguardTransitionAnimationFlow,
-        )
-    }
+@ExperimentalCoroutinesApi
+val Kosmos.dozingToPrimaryBouncerTransitionViewModel by Fixture {
+    DozingToPrimaryBouncerTransitionViewModel(
+        animationFlow = keyguardTransitionAnimationFlow,
+    )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelKosmos.kt
similarity index 87%
rename from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelKosmos.kt
index b370859..00741eb 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModelKosmos.kt
@@ -16,12 +16,14 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
+import com.android.systemui.common.ui.domain.interactor.configurationInteractor
 import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
 import com.android.systemui.kosmos.Kosmos
 
 val Kosmos.dreamingToGlanceableHubTransitionViewModel by
     Kosmos.Fixture {
         DreamingToGlanceableHubTransitionViewModel(
+            configurationInteractor = configurationInteractor,
             animationFlow = keyguardTransitionAnimationFlow,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelKosmos.kt
index 8b5407c..5f70a2f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToLockscreenTransitionViewModelKosmos.kt
@@ -14,11 +14,8 @@
  * limitations under the License.
  */
 
-@file:OptIn(ExperimentalCoroutinesApi::class)
-
 package com.android.systemui.keyguard.ui.viewmodel
 
-import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor
 import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
 import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
 import com.android.systemui.kosmos.Kosmos
@@ -26,11 +23,11 @@
 import com.android.systemui.util.mockito.mock
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 
+@ExperimentalCoroutinesApi
 val Kosmos.dreamingToLockscreenTransitionViewModel by Fixture {
     DreamingToLockscreenTransitionViewModel(
         keyguardTransitionInteractor = keyguardTransitionInteractor,
         fromDreamingTransitionInteractor = mock(),
-        deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor,
         animationFlow = keyguardTransitionAnimationFlow,
     )
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelKosmos.kt
similarity index 77%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelKosmos.kt
index b370859..1302f15 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModelKosmos.kt
@@ -16,12 +16,14 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
+import com.android.systemui.common.ui.domain.interactor.configurationInteractor
 import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
 import com.android.systemui.kosmos.Kosmos
 
-val Kosmos.dreamingToGlanceableHubTransitionViewModel by
+val Kosmos.glanceableHubToDreamingTransitionViewModel by
     Kosmos.Fixture {
-        DreamingToGlanceableHubTransitionViewModel(
+        GlanceableHubToDreamingTransitionViewModel(
+            configurationInteractor = configurationInteractor,
             animationFlow = keyguardTransitionAnimationFlow,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelKosmos.kt
index 4daf460..b19d4e8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/GoneToDozingTransitionViewModelKosmos.kt
@@ -14,17 +14,18 @@
  * limitations under the License.
  */
 
-@file:OptIn(ExperimentalCoroutinesApi::class)
-
 package com.android.systemui.keyguard.ui.viewmodel
 
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor
 import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.Kosmos.Fixture
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 
+@ExperimentalCoroutinesApi
 val Kosmos.goneToDozingTransitionViewModel by Fixture {
     GoneToDozingTransitionViewModel(
+        deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor,
         animationFlow = keyguardTransitionAnimationFlow,
     )
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelKosmos.kt
similarity index 63%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelKosmos.kt
index b370859..aa8e9a8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToDozingTransitionViewModelKosmos.kt
@@ -16,12 +16,16 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor
 import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 
-val Kosmos.dreamingToGlanceableHubTransitionViewModel by
-    Kosmos.Fixture {
-        DreamingToGlanceableHubTransitionViewModel(
-            animationFlow = keyguardTransitionAnimationFlow,
-        )
-    }
+@ExperimentalCoroutinesApi
+val Kosmos.lockscreenToDozingTransitionViewModel by Fixture {
+    LockscreenToDozingTransitionViewModel(
+        deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor,
+        animationFlow = keyguardTransitionAnimationFlow,
+    )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelKosmos.kt
index 1b2337f..17c3a14 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelKosmos.kt
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-@file:OptIn(ExperimentalCoroutinesApi::class)
-
 package com.android.systemui.keyguard.ui.viewmodel
 
 import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
@@ -23,6 +21,7 @@
 import com.android.systemui.kosmos.Kosmos.Fixture
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 
+@ExperimentalCoroutinesApi
 val Kosmos.lockscreenToGoneTransitionViewModel by Fixture {
     LockscreenToGoneTransitionViewModel(
         animationFlow = keyguardTransitionAnimationFlow,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModelKosmos.kt
similarity index 63%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModelKosmos.kt
index b370859..d4e4b8c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/PrimaryBouncerToDozingTransitionViewModelKosmos.kt
@@ -16,12 +16,16 @@
 
 package com.android.systemui.keyguard.ui.viewmodel
 
+import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor
 import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 
-val Kosmos.dreamingToGlanceableHubTransitionViewModel by
-    Kosmos.Fixture {
-        DreamingToGlanceableHubTransitionViewModel(
-            animationFlow = keyguardTransitionAnimationFlow,
-        )
-    }
+@ExperimentalCoroutinesApi
+val Kosmos.primaryBouncerToDozingTransitionViewModel by Fixture {
+    PrimaryBouncerToDozingTransitionViewModel(
+        deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor,
+        animationFlow = keyguardTransitionAnimationFlow,
+    )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/SpatializerKosmos.kt
similarity index 63%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/media/SpatializerKosmos.kt
index b370859..7001ea8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/SpatializerKosmos.kt
@@ -14,14 +14,11 @@
  * limitations under the License.
  */
 
-package com.android.systemui.keyguard.ui.viewmodel
+package com.android.systemui.media
 
-import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
+import com.android.settingslib.media.domain.interactor.SpatializerInteractor
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.media.data.repository.FakeSpatializerRepository
 
-val Kosmos.dreamingToGlanceableHubTransitionViewModel by
-    Kosmos.Fixture {
-        DreamingToGlanceableHubTransitionViewModel(
-            animationFlow = keyguardTransitionAnimationFlow,
-        )
-    }
+val Kosmos.spatializerRepository by Kosmos.Fixture { FakeSpatializerRepository() }
+val Kosmos.spatializerInteractor by Kosmos.Fixture { SpatializerInteractor(spatializerRepository) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/data/repository/FakeSpatializerRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/data/repository/FakeSpatializerRepository.kt
new file mode 100644
index 0000000..0183b97
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/data/repository/FakeSpatializerRepository.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2024 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.media.data.repository
+
+import android.media.AudioDeviceAttributes
+import com.android.settingslib.media.data.repository.SpatializerRepository
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+class FakeSpatializerRepository : SpatializerRepository {
+
+    var defaultSpatialAudioAvailable: Boolean = false
+
+    private val spatialAudioAvailabilityByDevice: MutableMap<AudioDeviceAttributes, Boolean> =
+        mutableMapOf()
+    private val spatialAudioCompatibleDevices: MutableList<AudioDeviceAttributes> = mutableListOf()
+
+    private val mutableHeadTrackingAvailable = MutableStateFlow(false)
+    private val headTrackingEnabledByDevice = mutableMapOf<AudioDeviceAttributes, Boolean>()
+
+    override val isHeadTrackingAvailable: StateFlow<Boolean> =
+        mutableHeadTrackingAvailable.asStateFlow()
+
+    override suspend fun isSpatialAudioAvailableForDevice(
+        audioDeviceAttributes: AudioDeviceAttributes
+    ): Boolean =
+        spatialAudioAvailabilityByDevice.getOrDefault(
+            audioDeviceAttributes,
+            defaultSpatialAudioAvailable
+        )
+
+    override suspend fun getSpatialAudioCompatibleDevices(): Collection<AudioDeviceAttributes> =
+        spatialAudioCompatibleDevices
+
+    override suspend fun addSpatialAudioCompatibleDevice(
+        audioDeviceAttributes: AudioDeviceAttributes
+    ) {
+        spatialAudioCompatibleDevices.add(audioDeviceAttributes)
+    }
+
+    override suspend fun removeSpatialAudioCompatibleDevice(
+        audioDeviceAttributes: AudioDeviceAttributes
+    ) {
+        spatialAudioCompatibleDevices.remove(audioDeviceAttributes)
+    }
+
+    override suspend fun isHeadTrackingEnabled(
+        audioDeviceAttributes: AudioDeviceAttributes
+    ): Boolean = headTrackingEnabledByDevice.getOrDefault(audioDeviceAttributes, false)
+
+    override suspend fun setHeadTrackingEnabled(
+        audioDeviceAttributes: AudioDeviceAttributes,
+        isEnabled: Boolean
+    ) {
+        headTrackingEnabledByDevice[audioDeviceAttributes] = isEnabled
+    }
+
+    fun setIsSpatialAudioAvailable(
+        audioDeviceAttributes: AudioDeviceAttributes,
+        isAvailable: Boolean,
+    ) {
+        spatialAudioAvailabilityByDevice[audioDeviceAttributes] = isAvailable
+    }
+
+    fun setIsHeadTrackingAvailable(isAvailable: Boolean) {
+        mutableHeadTrackingAvailable.value = isAvailable
+    }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/PanelExpansionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/PanelExpansionInteractorKosmos.kt
new file mode 100644
index 0000000..a025846
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/PanelExpansionInteractorKosmos.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 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.stack.ui.viewmodel
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.scene.domain.interactor.PanelExpansionInteractor
+import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.shade.data.repository.shadeRepository
+
+val Kosmos.panelExpansionInteractor by Fixture {
+    PanelExpansionInteractor(
+        sceneInteractor = sceneInteractor,
+        shadeRepository = shadeRepository,
+    )
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
index 931a59d..3e9ae4d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
@@ -119,6 +119,13 @@
         yield()
     }
 
+    /** Resets the current user to the default of [DEFAULT_SELECTED_USER_INFO]. */
+    suspend fun asDefaultUser(): UserInfo {
+        setUserInfos(listOf(DEFAULT_SELECTED_USER_INFO))
+        setSelectedUserInfo(DEFAULT_SELECTED_USER_INFO)
+        return DEFAULT_SELECTED_USER_INFO
+    }
+
     /** Makes the current user [MAIN_USER]. */
     suspend fun asMainUser(): UserInfo {
         setUserInfos(listOf(MAIN_USER))
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index 53897e1..41a4a1a 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -47,6 +47,7 @@
     ],
     libs: [
         "framework-minus-apex.ravenwood",
+        "ravenwood-junit",
     ],
     visibility: ["//visibility:private"],
 }
diff --git a/ravenwood/framework-minus-apex-ravenwood-policies.txt b/ravenwood/framework-minus-apex-ravenwood-policies.txt
index 6b67364..371c3ac 100644
--- a/ravenwood/framework-minus-apex-ravenwood-policies.txt
+++ b/ravenwood/framework-minus-apex-ravenwood-policies.txt
@@ -55,3 +55,5 @@
     method getSystemService (Ljava/lang/Class;)Ljava/lang/Object; stub
 class android.content.pm.PackageManager stub
     method <init> ()V stub
+class android.text.ClipboardManager stub
+    method <init> ()V stub
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java
index 3668b03..c17d090 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java
@@ -16,18 +16,28 @@
 
 package android.platform.test.ravenwood;
 
+import android.content.ClipboardManager;
 import android.content.Context;
 import android.hardware.ISerialManager;
 import android.hardware.SerialManager;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
 import android.os.PermissionEnforcer;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.test.mock.MockContext;
 import android.util.ArrayMap;
 import android.util.Singleton;
 
+import java.util.Objects;
+import java.util.concurrent.Executor;
 import java.util.function.Supplier;
 
 public class RavenwoodContext extends MockContext {
+    private final String mPackageName;
+    private final HandlerThread mMainThread;
+
     private final RavenwoodPermissionEnforcer mEnforcer = new RavenwoodPermissionEnforcer();
 
     private final ArrayMap<Class<?>, String> mClassToName = new ArrayMap<>();
@@ -39,7 +49,13 @@
         mNameToFactory.put(serviceName, serviceSupplier);
     }
 
-    public RavenwoodContext() {
+    public RavenwoodContext(String packageName, HandlerThread mainThread) {
+        mPackageName = packageName;
+        mMainThread = mainThread;
+
+        registerService(ClipboardManager.class,
+                Context.CLIPBOARD_SERVICE, asSingleton(() ->
+                        new ClipboardManager(this, getMainThreadHandler())));
         registerService(PermissionEnforcer.class,
                 Context.PERMISSION_ENFORCER_SERVICE, () -> mEnforcer);
         registerService(SerialManager.class,
@@ -73,18 +89,79 @@
         }
     }
 
+    @Override
+    public Looper getMainLooper() {
+        Objects.requireNonNull(mMainThread,
+                "Test must request setProvideMainThread() via RavenwoodRule");
+        return mMainThread.getLooper();
+    }
+
+    @Override
+    public Handler getMainThreadHandler() {
+        Objects.requireNonNull(mMainThread,
+                "Test must request setProvideMainThread() via RavenwoodRule");
+        return mMainThread.getThreadHandler();
+    }
+
+    @Override
+    public Executor getMainExecutor() {
+        Objects.requireNonNull(mMainThread,
+                "Test must request setProvideMainThread() via RavenwoodRule");
+        return mMainThread.getThreadExecutor();
+    }
+
+    @Override
+    public String getPackageName() {
+        return Objects.requireNonNull(mPackageName,
+                "Test must request setPackageName() via RavenwoodRule");
+    }
+
+    @Override
+    public String getOpPackageName() {
+        return Objects.requireNonNull(mPackageName,
+                "Test must request setPackageName() via RavenwoodRule");
+    }
+
+    @Override
+    public String getAttributionTag() {
+        return null;
+    }
+
+    @Override
+    public UserHandle getUser() {
+        return android.os.UserHandle.of(android.os.UserHandle.myUserId());
+    }
+
+    @Override
+    public int getUserId() {
+        return android.os.UserHandle.myUserId();
+    }
+
+    @Override
+    public int getDeviceId() {
+        return Context.DEVICE_ID_DEFAULT;
+    }
+
     /**
      * Wrap the given {@link Supplier} to become a memoized singleton.
      */
-    private static <T> Supplier<T> asSingleton(Supplier<T> supplier) {
+    private static <T> Supplier<T> asSingleton(ThrowingSupplier<T> supplier) {
         final Singleton<T> singleton = new Singleton<>() {
             @Override
             protected T create() {
-                return supplier.get();
+                try {
+                    return supplier.get();
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
             }
         };
         return () -> {
             return singleton.get();
         };
     }
+
+    public interface ThrowingSupplier<T> {
+        T get() throws Exception;
+    }
 }
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
index 231cce9..56a3c64 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java
@@ -110,13 +110,16 @@
 
         ActivityManager.init$ravenwood(rule.mCurrentUser);
 
+        final HandlerThread main;
         if (rule.mProvideMainThread) {
-            final HandlerThread main = new HandlerThread(MAIN_THREAD_NAME);
+            main = new HandlerThread(MAIN_THREAD_NAME);
             main.start();
             Looper.setMainLooperForTest(main.getLooper());
+        } else {
+            main = null;
         }
 
-        rule.mContext = new RavenwoodContext();
+        rule.mContext = new RavenwoodContext(rule.mPackageName, main);
         rule.mInstrumentation = new Instrumentation();
         rule.mInstrumentation.basicInit(rule.mContext);
         InstrumentationRegistry.registerInstance(rule.mInstrumentation, Bundle.EMPTY);
diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java
index bb280f4..3de96c0 100644
--- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java
+++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodSystemServer.java
@@ -16,6 +16,7 @@
 
 package android.platform.test.ravenwood;
 
+import android.content.ClipboardManager;
 import android.hardware.SerialManager;
 import android.os.SystemClock;
 import android.util.ArrayMap;
@@ -40,7 +41,10 @@
     // authors to exhaustively declare all transitive services
 
     static {
-        sKnownServices.put(SerialManager.class, "com.android.server.SerialService$Lifecycle");
+        sKnownServices.put(ClipboardManager.class,
+                "com.android.server.FakeClipboardService$Lifecycle");
+        sKnownServices.put(SerialManager.class,
+                "com.android.server.SerialService$Lifecycle");
     }
 
     private static TimingsTraceAndSlog sTimings;
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
index a8c24fc..a520d4c 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java
@@ -121,6 +121,8 @@
     int mUid = NOBODY_UID;
     int mPid = sNextPid.getAndIncrement();
 
+    String mPackageName;
+
     boolean mProvideMainThread = false;
 
     final RavenwoodSystemProperties mSystemProperties = new RavenwoodSystemProperties();
@@ -158,6 +160,15 @@
         }
 
         /**
+         * Configure the identity of this process to be the given package name for the duration
+         * of the test. Has no effect on non-Ravenwood environments.
+         */
+        public Builder setPackageName(/* @NonNull */ String packageName) {
+            mRule.mPackageName = Objects.requireNonNull(packageName);
+            return this;
+        }
+
+        /**
          * Configure a "main" thread to be available for the duration of the test, as defined
          * by {@code Looper.getMainLooper()}. Has no effect on non-Ravenwood environments.
          */
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodUtils.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodUtils.java
index b736a76..37ceac6 100644
--- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodUtils.java
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodUtils.java
@@ -73,9 +73,9 @@
                     return;
                 }
             }
-            throw new UnsatisfiedLinkError("Library " + libname + " no found in "
+            throw new UnsatisfiedLinkError("Library " + libname + " not found in "
                     + "java.library.path: " + path);
-        } catch (Exception e) {
+        } catch (Throwable e) {
             dumpFiles(System.out);
             throw e;
         }
@@ -96,6 +96,10 @@
                     listFiles(out, gparent, "");
                 }
             }
+
+            var gparent = new File("../..").getCanonicalFile();
+            out.println("# ../..=" + gparent);
+            listFiles(out, gparent, "");
         } catch (Throwable th) {
             out.println("Error: " + th.toString());
             th.printStackTrace(out);
diff --git a/ravenwood/ravenwood-annotation-allowed-classes.txt b/ravenwood/ravenwood-annotation-allowed-classes.txt
index eb3c55c..9b4d378 100644
--- a/ravenwood/ravenwood-annotation-allowed-classes.txt
+++ b/ravenwood/ravenwood-annotation-allowed-classes.txt
@@ -186,6 +186,7 @@
 android.content.ClipData
 android.content.ClipData$Item
 android.content.ClipDescription
+android.content.ClipboardManager
 android.content.ComponentName
 android.content.ContentUris
 android.content.ContentValues
diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Log_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Log_host.java
index 5930a14..f301b9c 100644
--- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Log_host.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/Log_host.java
@@ -22,6 +22,13 @@
 
 import java.io.PrintStream;
 
+/**
+ * Ravenwood "native substitution" class for {@link android.util.Log}.
+ *
+ * {@link android.util.Log} already uses the actual native code and doesn't use this class.
+ * In order to switch to this Java implementation, uncomment the @RavenwoodNativeSubstitutionClass
+ * annotation on {@link android.util.Log}.
+ */
 public class Log_host {
 
     public static boolean isLoggable(String tag, @Level int level) {
diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java
index 1e12030..cc94090 100644
--- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java
+++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java
@@ -15,8 +15,9 @@
  */
 package com.android.platform.test.ravenwood.runtimehelper;
 
+import android.platform.test.ravenwood.RavenwoodUtils;
+
 import java.io.File;
-import java.io.PrintStream;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
 
@@ -27,8 +28,6 @@
  * load other JNI or do other set up here.
  */
 public class ClassLoadHook {
-    private static PrintStream sOut = System.out;
-
     /**
      * If true, we won't load `libandroid_runtime`
      *
@@ -36,7 +35,7 @@
      * so we need a way to remove the dependency.
      */
     private static final boolean SKIP_LOADING_LIBANDROID = "1".equals(System.getenv(
-            "HOSTTEST_SKIP_LOADING_LIBANDROID"));
+            "RAVENWOOD_SKIP_LOADING_LIBANDROID"));
 
     public static final String CORE_NATIVE_CLASSES = "core_native_classes";
     public static final String ICU_DATA_PATH = "icu.data.path";
@@ -44,7 +43,7 @@
     public static final String GRAPHICS_NATIVE_CLASSES = "graphics_native_classes";
 
     public static final String VALUE_N_A = "**n/a**";
-    public static final String LIBANDROID_RUNTIME_NAME = "libandroid_runtime";
+    public static final String LIBANDROID_RUNTIME_NAME = "android_runtime";
 
     private static String sInitialDir = new File("").getAbsolutePath();
 
@@ -68,7 +67,7 @@
     }
 
     private static void log(String message) {
-        sOut.println("ClassLoadHook: " + message);
+        System.out.println("ClassLoadHook: " + message);
     }
 
     private static void log(String fmt, Object... args) {
@@ -92,13 +91,6 @@
         }
     }
 
-    private static void loadJniLibrary(String name) {
-        final String path = sInitialDir + "/lib64/" + name + ".so";
-        System.out.println("Loading " + path + " ...");
-        System.load(path);
-        System.out.println("Done loading " + path);
-    }
-
     private static boolean sLoadFrameworkNativeCodeCalled = false;
 
     /**
@@ -115,7 +107,7 @@
         // libandroid_runtime uses Java's system properties to decide what JNI methods to set up.
         // Set up these properties for host-side tests.
 
-        if ("1".equals(System.getenv("HOSTTEST_DUMP_PROPERTIES"))) {
+        if ("1".equals(System.getenv("RAVENWOOD_DUMP_PROPERTIES"))) {
             log("Java system properties:");
             dumpSystemProperties();
         }
@@ -141,7 +133,7 @@
         setProperty(ICU_DATA_PATH, VALUE_N_A);
         setProperty(KEYBOARD_PATHS, VALUE_N_A);
 
-        loadJniLibrary(LIBANDROID_RUNTIME_NAME);
+        RavenwoodUtils.loadJniLibrary(LIBANDROID_RUNTIME_NAME);
     }
 
     /**
@@ -156,7 +148,7 @@
     };
 
     /**
-     * @return if a given method is a native method or not.
+     * @return if a given class has any native method or not.
      */
     private static boolean hasNativeMethod(Class<?> clazz) {
         for (var method : clazz.getDeclaredMethods()) {
diff --git a/rs/java/android/renderscript/ScriptC.java b/rs/java/android/renderscript/ScriptC.java
index 67c2caa..e9f6031 100644
--- a/rs/java/android/renderscript/ScriptC.java
+++ b/rs/java/android/renderscript/ScriptC.java
@@ -38,12 +38,12 @@
     private static final String TAG = "ScriptC";
 
     /**
-     * In targetSdkVersion 35 and above, Renderscript's ScriptC stops being supported
+     * In targetSdkVersion 36 and above, Renderscript's ScriptC stops being supported
      * and an exception is thrown when the class is instantiated.
-     * In targetSdkVersion 34 and below, Renderscript's ScriptC still works.
+     * In targetSdkVersion 35 and below, Renderscript's ScriptC still works.
      */
     @ChangeId
-    @EnabledAfter(targetSdkVersion = 35)
+    @EnabledAfter(targetSdkVersion = 36)
     private static final long RENDERSCRIPT_SCRIPTC_DEPRECATION_CHANGE_ID = 297019750L;
 
     /**
@@ -101,9 +101,21 @@
         setID(id);
     }
 
-    private static void throwExceptionIfSDKTooHigh() {
+    private static void throwExceptionIfScriptCUnsupported() {
+        // Checks that this device actually does have an ABI that supports ScriptC.
+        //
+        // For an explanation as to why `System.loadLibrary` is used, see discussion at
+        // https://android-review.googlesource.com/c/platform/frameworks/base/+/2957974/comment/2f908b80_a05292ee
+        try {
+            System.loadLibrary("RS");
+        } catch (UnsatisfiedLinkError e) {
+            String s = "This device does not have an ABI that supports ScriptC.";
+            throw new UnsupportedOperationException(s);
+        }
+
+        // Throw an exception if the target API is 36 or above
         String message =
-                "ScriptC scripts are not supported when targeting an API Level >= 35. Please refer "
+                "ScriptC scripts are not supported when targeting an API Level >= 36. Please refer "
                     + "to https://developer.android.com/guide/topics/renderscript/migration-guide "
                     + "for proposed alternatives.";
         Slog.w(TAG, message);
@@ -113,7 +125,7 @@
     }
 
     private static synchronized long internalCreate(RenderScript rs, Resources resources, int resourceID) {
-        throwExceptionIfSDKTooHigh();
+        throwExceptionIfScriptCUnsupported();
         byte[] pgm;
         int pgmLength;
         InputStream is = resources.openRawResource(resourceID);
@@ -150,7 +162,7 @@
 
     private static synchronized long internalStringCreate(RenderScript rs, String resName, byte[] bitcode) {
         //        Log.v(TAG, "Create script for resource = " + resName);
-        throwExceptionIfSDKTooHigh();
+        throwExceptionIfScriptCUnsupported();
         return rs.nScriptCCreate(resName, RenderScript.getCachePath(), bitcode, bitcode.length);
     }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 16119d11..54e545d 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -16,6 +16,8 @@
 
 package com.android.server.accessibility;
 
+import static android.view.InputDevice.SOURCE_CLASS_POINTER;
+import static android.view.MotionEvent.ACTION_SCROLL;
 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
 
@@ -425,6 +427,12 @@
 
     boolean shouldProcessMultiDeviceEvent(InputEvent event, int policyFlags) {
         if (event instanceof MotionEvent motion) {
+            if (!motion.isFromSource(SOURCE_CLASS_POINTER) || motion.getAction() == ACTION_SCROLL) {
+                // Non-pointer events are focus-dispatched and don't require special logic.
+                // Scroll events are stand-alone and therefore can be considered to not be part of
+                // a stream.
+                return true;
+            }
             // Only allow 1 device to be sending motion events at a time
             // If the event is from an active device, let it through.
             // If the event is not from an active device, only let it through if it starts a new
@@ -481,7 +489,7 @@
     }
 
     private void processMotionEvent(EventStreamState state, MotionEvent event, int policyFlags) {
-        if (!state.shouldProcessScroll() && event.getActionMasked() == MotionEvent.ACTION_SCROLL) {
+        if (!state.shouldProcessScroll() && event.getActionMasked() == ACTION_SCROLL) {
             super.onInputEvent(event, policyFlags);
             return;
         }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 46db624..43c018c 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -3460,13 +3460,20 @@
         if (!mMagnificationController.supportWindowMagnification()) {
             return;
         }
-        final boolean connect = (userState.isShortcutMagnificationEnabledLocked()
+
+        final boolean shortcutEnabled = (userState.isShortcutMagnificationEnabledLocked()
                 || userState.isMagnificationSingleFingerTripleTapEnabledLocked()
                 || (Flags.enableMagnificationMultipleFingerMultipleTapGesture()
-                && userState.isMagnificationTwoFingerTripleTapEnabledLocked()))
-                && (userState.getMagnificationCapabilitiesLocked()
-                != Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN)
+                    && userState.isMagnificationTwoFingerTripleTapEnabledLocked()));
+
+        final boolean createConnectionForCurrentCapability =
+                com.android.window.flags.Flags.magnificationAlwaysDrawFullscreenBorder()
+                        || (userState.getMagnificationCapabilitiesLocked()
+                                != Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
+
+        final boolean connect = (shortcutEnabled && createConnectionForCurrentCapability)
                 || userHasMagnificationServicesLocked(userState);
+
         getMagnificationConnectionManager().requestConnection(connect);
     }
 
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java
index e11c36a..bc14342 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionManager.java
@@ -674,6 +674,23 @@
     }
 
     /**
+     * Notify Fullscreen magnification activation changes.
+     */
+    public boolean onFullscreenMagnificationActivationChanged(int displayId, boolean activated) {
+        synchronized (mLock) {
+            waitForConnectionIfNeeded();
+            if (mConnectionWrapper == null) {
+                Slog.w(TAG,
+                        "onFullscreenMagnificationActivationChanged mConnectionWrapper is null. "
+                                + "mConnectionState=" + connectionStateToString(mConnectionState));
+                return false;
+            }
+            return mConnectionWrapper
+                    .onFullscreenMagnificationActivationChanged(displayId, activated);
+        }
+    }
+
+    /**
      * Calculates the number of fingers in the window.
      *
      * @param displayId The logical display id.
@@ -1267,15 +1284,7 @@
             float centerY, float magnificationFrameOffsetRatioX,
             float magnificationFrameOffsetRatioY,
             MagnificationAnimationCallback animationCallback) {
-        // Wait for the connection with a timeout.
-        final long endMillis = SystemClock.uptimeMillis() + WAIT_CONNECTION_TIMEOUT_MILLIS;
-        while (mConnectionState == CONNECTING && (SystemClock.uptimeMillis() < endMillis)) {
-            try {
-                mLock.wait(endMillis - SystemClock.uptimeMillis());
-            } catch (InterruptedException ie) {
-                /* ignore */
-            }
-        }
+        waitForConnectionIfNeeded();
         if (mConnectionWrapper == null) {
             Slog.w(TAG,
                     "enableWindowMagnificationInternal mConnectionWrapper is null. "
@@ -1317,4 +1326,16 @@
         return mConnectionWrapper != null && mConnectionWrapper.moveWindowMagnifierToPosition(
                 displayId, positionX, positionY, animationCallback);
     }
+
+    private void waitForConnectionIfNeeded() {
+        // Wait for the connection with a timeout.
+        final long endMillis = SystemClock.uptimeMillis() + WAIT_CONNECTION_TIMEOUT_MILLIS;
+        while (mConnectionState == CONNECTING && (SystemClock.uptimeMillis() < endMillis)) {
+            try {
+                mLock.wait(endMillis - SystemClock.uptimeMillis());
+            } catch (InterruptedException ie) {
+                /* ignore */
+            }
+        }
+    }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionWrapper.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionWrapper.java
index db5b313..f6fb24f 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionWrapper.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationConnectionWrapper.java
@@ -58,6 +58,22 @@
         mConnection.asBinder().linkToDeath(deathRecipient, 0);
     }
 
+    boolean onFullscreenMagnificationActivationChanged(int displayId, boolean activated) {
+        if (mTrace.isA11yTracingEnabledForTypes(FLAGS_MAGNIFICATION_CONNECTION)) {
+            mTrace.logTrace(TAG + ".onFullscreenMagnificationActivationChanged",
+                    FLAGS_MAGNIFICATION_CONNECTION);
+        }
+        try {
+            mConnection.onFullscreenMagnificationActivationChanged(displayId, activated);
+        } catch (RemoteException e) {
+            if (DBG) {
+                Slog.e(TAG, "Error calling onFullscreenMagnificationActivationChanged");
+            }
+            return false;
+        }
+        return true;
+    }
+
     boolean enableWindowMagnification(int displayId, float scale, float centerX, float centerY,
             float magnificationFrameOffsetRatioX, float magnificationFrameOffsetRatioY,
             @Nullable MagnificationAnimationCallback callback) {
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
index 52e123a..0d5fd14 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
@@ -50,6 +50,7 @@
 import com.android.server.LocalServices;
 import com.android.server.accessibility.AccessibilityManagerService;
 import com.android.server.wm.WindowManagerInternal;
+import com.android.window.flags.Flags;
 
 import java.util.concurrent.Executor;
 
@@ -586,6 +587,11 @@
 
     @Override
     public void onFullScreenMagnificationActivationState(int displayId, boolean activated) {
+        if (Flags.magnificationAlwaysDrawFullscreenBorder()) {
+            getMagnificationConnectionManager()
+                    .onFullscreenMagnificationActivationChanged(displayId, activated);
+        }
+
         if (activated) {
             synchronized (mLock) {
                 mFullScreenModeEnabledTimeArray.put(displayId, SystemClock.uptimeMillis());
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index c4341b9..d779fbf 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -2802,9 +2802,10 @@
 
         final int datasetIdx = AutofillManager.getDatasetIdFromAuthenticationId(
                 authenticationId);
+        Dataset dataset = null;
         // Authenticated a dataset - reset view state regardless if we got a response or a dataset
         if (datasetIdx != AutofillManager.AUTHENTICATION_ID_DATASET_ID_UNDEFINED) {
-            final Dataset dataset = authenticatedResponse.getDatasets().get(datasetIdx);
+            dataset = authenticatedResponse.getDatasets().get(datasetIdx);
             if (dataset == null) {
                 Slog.w(TAG, "no dataset with index " + datasetIdx + " on fill response");
                 mPresentationStatsEventLogger.maybeSetAuthenticationResult(
@@ -2819,12 +2820,29 @@
         mSessionFlags.mExpiredResponse = false;
 
         final Parcelable result = data.getParcelable(AutofillManager.EXTRA_AUTHENTICATION_RESULT);
+        final GetCredentialException exception = data.getSerializable(
+                CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION,
+                GetCredentialException.class);
 
         final Bundle newClientState = data.getBundle(AutofillManager.EXTRA_CLIENT_STATE);
         if (sDebug) {
             Slog.d(TAG, "setAuthenticationResultLocked(): result=" + result
                     + ", clientState=" + newClientState + ", authenticationId=" + authenticationId);
         }
+        if (Flags.autofillCredmanDevIntegration() && exception != null
+                && exception instanceof GetCredentialException) {
+            if (dataset != null && dataset.getFieldIds().size() == 1) {
+                if (sDebug) {
+                    Slog.d(TAG, "setAuthenticationResultLocked(): result returns with"
+                            + "Credential Manager Exception");
+                }
+                AutofillId autofillId = dataset.getFieldIds().get(0);
+                sendCredentialManagerResponseToApp(/*response=*/ null,
+                        (GetCredentialException) exception, autofillId);
+            }
+            return;
+        }
+
         if (result instanceof FillResponse) {
             if (sDebug) {
                 Slog.d(TAG, "setAuthenticationResultLocked(): received FillResponse from"
@@ -2840,13 +2858,21 @@
             }
             if (Flags.autofillCredmanDevIntegration()) {
                 GetCredentialResponse response = (GetCredentialResponse) result;
-                sendCredentialManagerResponseToApp(response,
-                        /*exception=*/ null, response.getAutofillId());
+                if (dataset != null && dataset.getFieldIds().size() == 1) {
+                    AutofillId autofillId = dataset.getFieldIds().get(0);
+                    if (sDebug) {
+                        Slog.d(TAG, "Received GetCredentialResponse from authentication flow,"
+                                + "for autofillId: " + autofillId);
+                    }
+                    sendCredentialManagerResponseToApp(response,
+                            /*exception=*/ null, autofillId);
+                }
             } else if (Flags.autofillCredmanIntegration()) {
-                Dataset dataset = getDatasetFromCredentialResponse(
+                Dataset datasetFromCredentialResponse = getDatasetFromCredentialResponse(
                         (GetCredentialResponse) result);
-                if (dataset != null) {
-                    autoFill(requestId, datasetIdx, dataset, false, UI_TYPE_UNKNOWN);
+                if (datasetFromCredentialResponse != null) {
+                    autoFill(requestId, datasetIdx, datasetFromCredentialResponse,
+                            false, UI_TYPE_UNKNOWN);
                 }
             }
         } else if (result instanceof Dataset) {
@@ -2863,12 +2889,12 @@
                     if (sDebug) Slog.d(TAG,  "Updating client state from auth dataset");
                     mClientState = newClientState;
                 }
-                Dataset dataset = getEffectiveDatasetForAuthentication((Dataset) result);
+                Dataset datasetFromResult = getEffectiveDatasetForAuthentication((Dataset) result);
                 final Dataset oldDataset = authenticatedResponse.getDatasets().get(datasetIdx);
                 if (!isAuthResultDatasetEphemeral(oldDataset, data)) {
-                    authenticatedResponse.getDatasets().set(datasetIdx, dataset);
+                    authenticatedResponse.getDatasets().set(datasetIdx, datasetFromResult);
                 }
-                autoFill(requestId, datasetIdx, dataset, false, UI_TYPE_UNKNOWN);
+                autoFill(requestId, datasetIdx, datasetFromResult, false, UI_TYPE_UNKNOWN);
             } else {
                 Slog.w(TAG, "invalid index (" + datasetIdx + ") for authentication id "
                         + authenticationId);
@@ -5052,12 +5078,16 @@
     }
 
     private void addCredentialManagerCallbackForDataset(Dataset dataset, int requestId) {
+        AutofillId autofillId = null;
+        if (dataset != null && dataset.getFieldIds().size() == 1) {
+            autofillId = dataset.getFieldIds().get(0);
+        }
+        final AutofillId finalAutofillId = autofillId;
         final ResultReceiver resultReceiver = new ResultReceiver(mHandler) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
                 if (resultCode == SUCCESS_CREDMAN_SELECTOR) {
                     Slog.d(TAG, "onReceiveResult from Credential Manager bottom sheet");
-                    boolean isCredmanCallbackInvoked = false;
                     GetCredentialResponse getCredentialResponse =
                             resultData.getParcelable(
                                     CredentialProviderService.EXTRA_GET_CREDENTIAL_RESPONSE,
@@ -5065,7 +5095,7 @@
 
                     if (Flags.autofillCredmanDevIntegration()) {
                         sendCredentialManagerResponseToApp(getCredentialResponse,
-                                /*exception=*/ null, getCredentialResponse.getAutofillId());
+                                /*exception=*/ null, finalAutofillId);
                     } else {
                         Dataset datasetFromCredential = getDatasetFromCredentialResponse(
                                 getCredentialResponse);
@@ -5082,7 +5112,9 @@
                         Slog.w(TAG, "Credman bottom sheet from pinned "
                                 + "entry failed with: + " + exception[0] + " , "
                                 + exception[1]);
-                        // TODO(b/326313420): Propagate exception
+                        sendCredentialManagerResponseToApp(/*response=*/ null,
+                                new GetCredentialException(exception[0], exception[1]),
+                                finalAutofillId);
                     }
                 } else {
                     Slog.d(TAG, "Unknown resultCode from credential "
@@ -5094,6 +5126,10 @@
                 toIpcFriendlyResultReceiver(resultReceiver);
 
         Intent metadataIntent = dataset.getCredentialFillInIntent();
+        if (metadataIntent == null) {
+            metadataIntent = new Intent();
+        }
+
         metadataIntent.putExtra(
                 android.credentials.selection.Constants.EXTRA_FINAL_RESPONSE_RECEIVER,
                 ipcFriendlyResultReceiver);
@@ -6380,7 +6416,8 @@
                     }
                 }
                 if (exception != null) {
-                    // TODO(b/326313420): Add Exception support
+                    mClient.onGetCredentialException(id, viewId, exception.getType(),
+                            exception.getMessage());
                 } else if (response != null) {
                     mClient.onGetCredentialResponse(id, viewId, response);
                 } else {
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java b/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java
index c734680..ffc80ee 100644
--- a/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java
@@ -16,6 +16,8 @@
 
 package com.android.server.autofill.ui;
 
+import static android.service.autofill.FillResponse.FLAG_CREDENTIAL_MANAGER_RESPONSE;
+
 import static com.android.server.autofill.Helper.sVerbose;
 
 import android.annotation.NonNull;
@@ -24,6 +26,7 @@
 import android.content.IntentSender;
 import android.service.autofill.Dataset;
 import android.service.autofill.FillResponse;
+import android.service.autofill.Flags;
 import android.service.autofill.InlinePresentation;
 import android.text.TextUtils;
 import android.util.Pair;
@@ -141,10 +144,12 @@
             return new InlineFillUi(inlineFillUiInfo, inlineAuthentication,
                     maxInputLengthForAutofill);
         } else if (response.getDatasets() != null) {
+            boolean ignoreHostSpec = Flags.autofillCredmanIntegration() && (
+                    (response.getFlags() & FLAG_CREDENTIAL_MANAGER_RESPONSE) != 0);
             SparseArray<Pair<Dataset, InlineSuggestion>> inlineSuggestions =
                     InlineSuggestionFactory.createInlineSuggestions(inlineFillUiInfo,
                             InlineSuggestionInfo.SOURCE_AUTOFILL, response.getDatasets(),
-                            uiCallback);
+                            uiCallback, ignoreHostSpec);
             return new InlineFillUi(inlineFillUiInfo, inlineSuggestions,
                     maxInputLengthForAutofill);
         }
@@ -160,7 +165,8 @@
             @NonNull InlineSuggestionUiCallback uiCallback) {
         SparseArray<Pair<Dataset, InlineSuggestion>> inlineSuggestions =
                 InlineSuggestionFactory.createInlineSuggestions(inlineFillUiInfo,
-                        InlineSuggestionInfo.SOURCE_PLATFORM, datasets, uiCallback);
+                        InlineSuggestionInfo.SOURCE_PLATFORM, datasets,
+                        uiCallback, /* ignoreHostSpec= */ false);
         return new InlineFillUi(inlineFillUiInfo, inlineSuggestions);
     }
 
@@ -254,7 +260,7 @@
         if (!TextUtils.isEmpty(mFilterText) && mFilterText.length() > mMaxInputLengthForAutofill) {
             if (sVerbose) {
                 Slog.v(TAG, "Not showing inline suggestion when user entered more than "
-                         + mMaxInputLengthForAutofill + " characters");
+                        + mMaxInputLengthForAutofill + " characters");
             }
             return new InlineSuggestionsResponse(inlineSuggestions);
         }
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
index 52109ba..d3b9501 100644
--- a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
@@ -16,6 +16,7 @@
 
 package com.android.server.autofill.ui;
 
+import static android.service.autofill.FillResponse.FLAG_CREDENTIAL_MANAGER_RESPONSE;
 import static android.view.inputmethod.InlineSuggestionInfo.TYPE_SUGGESTION;
 
 import static com.android.server.autofill.Helper.sDebug;
@@ -25,6 +26,7 @@
 import android.content.IntentSender;
 import android.service.autofill.Dataset;
 import android.service.autofill.FillResponse;
+import android.service.autofill.Flags;
 import android.service.autofill.InlinePresentation;
 import android.util.Pair;
 import android.util.Slog;
@@ -47,11 +49,14 @@
             @NonNull InlineFillUi.InlineSuggestionUiCallback uiCallback) {
         InlinePresentation inlineAuthentication = response.getInlinePresentation();
         final int requestId = response.getRequestId();
+        boolean ignoreHostSpec = Flags.autofillCredmanIntegration() && (
+                (response.getFlags() & FLAG_CREDENTIAL_MANAGER_RESPONSE) != 0);
 
         return createInlineSuggestion(inlineFillUiInfo, InlineSuggestionInfo.SOURCE_AUTOFILL,
                 InlineSuggestionInfo.TYPE_ACTION, () -> uiCallback.authenticate(requestId,
                         AutofillManager.AUTHENTICATION_ID_DATASET_ID_UNDEFINED),
-                mergedInlinePresentation(inlineFillUiInfo.mInlineRequest, 0, inlineAuthentication),
+                mergedInlinePresentation(inlineFillUiInfo.mInlineRequest, 0, inlineAuthentication,
+                        ignoreHostSpec),
                 createInlineSuggestionTooltip(inlineFillUiInfo.mInlineRequest,
                         inlineFillUiInfo, InlineSuggestionInfo.SOURCE_AUTOFILL,
                         response.getInlineTooltipPresentation()),
@@ -67,7 +72,7 @@
             @NonNull InlineFillUi.InlineFillUiInfo inlineFillUiInfo,
             @NonNull @InlineSuggestionInfo.Source String suggestionSource,
             @NonNull List<Dataset> datasets,
-            @NonNull InlineFillUi.InlineSuggestionUiCallback uiCallback) {
+            @NonNull InlineFillUi.InlineSuggestionUiCallback uiCallback, boolean ignoreHostSpec) {
         if (sDebug) Slog.d(TAG, "createInlineSuggestions(source=" + suggestionSource + ") called");
 
         final InlineSuggestionsRequest request = inlineFillUiInfo.mInlineRequest;
@@ -107,7 +112,8 @@
             InlineSuggestion inlineSuggestion = createInlineSuggestion(
                     inlineFillUiInfo, suggestionSource, suggestionType,
                     () -> uiCallback.autofill(dataset, index),
-                    mergedInlinePresentation(request, datasetIndex, inlinePresentation),
+                    mergedInlinePresentation(request, datasetIndex, inlinePresentation,
+                            ignoreHostSpec),
                     inlineSuggestionTooltip,
                     uiCallback);
             response.append(datasetIndex, Pair.create(dataset, inlineSuggestion));
@@ -141,16 +147,18 @@
      */
     private static InlinePresentation mergedInlinePresentation(
             @NonNull InlineSuggestionsRequest request,
-            int index, @NonNull InlinePresentation inlinePresentation) {
+            int index, @NonNull InlinePresentation inlinePresentation, boolean ignoreHostSpec) {
         final List<InlinePresentationSpec> specs = request.getInlinePresentationSpecs();
         if (specs.isEmpty()) {
             return inlinePresentation;
         }
         InlinePresentationSpec specFromHost = specs.get(Math.min(specs.size() - 1, index));
+        InlinePresentationSpec specToUse =
+                ignoreHostSpec ? inlinePresentation.getInlinePresentationSpec() : specFromHost;
         InlinePresentationSpec mergedInlinePresentation = new InlinePresentationSpec.Builder(
                 inlinePresentation.getInlinePresentationSpec().getMinSize(),
                 inlinePresentation.getInlinePresentationSpec().getMaxSize()).setStyle(
-                specFromHost.getStyle()).build();
+                specToUse.getStyle()).build();
 
         return new InlinePresentation(inlinePresentation.getSlice(), mergedInlinePresentation,
                 inlinePresentation.isPinned());
@@ -211,7 +219,7 @@
                 inlineFillUiInfo, tooltipInline, () -> { /* no operation */ }, uiCallback);
         final InlineSuggestionInfo tooltipInlineSuggestionInfo = new InlineSuggestionInfo(
                 mergedSpec, suggestionSource, /* autofillHints */ null, TYPE_SUGGESTION,
-                        /* pinned */ false, /* tooltip */ null);
+                /* pinned */ false, /* tooltip */ null);
         return new InlineSuggestion(tooltipInlineSuggestionInfo, tooltipContentProvider);
     }
 
diff --git a/services/companion/java/com/android/server/companion/AssociationRevokeProcessor.java b/services/companion/java/com/android/server/companion/AssociationRevokeProcessor.java
new file mode 100644
index 0000000..de6382e
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/AssociationRevokeProcessor.java
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2024 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.server.companion;
+
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
+import static android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION;
+
+import static com.android.internal.util.CollectionUtils.any;
+import static com.android.server.companion.MetricUtils.logRemoveAssociation;
+import static com.android.server.companion.RolesUtils.removeRoleHolderForAssociation;
+import static com.android.server.companion.CompanionDeviceManagerService.PerUserAssociationSet;
+
+import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.companion.AssociationInfo;
+import android.content.Context;
+import android.content.pm.PackageManagerInternal;
+import android.os.Binder;
+import android.os.UserHandle;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.companion.datatransfer.SystemDataTransferRequestStore;
+import com.android.server.companion.presence.CompanionDevicePresenceMonitor;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A class response for Association removal.
+ */
+@SuppressLint("LongLogTag")
+public class AssociationRevokeProcessor {
+
+    private static final String TAG = "CDM_AssociationRevokeProcessor";
+    private static final boolean DEBUG = false;
+    private final @NonNull Context mContext;
+    private final @NonNull CompanionDeviceManagerService mService;
+    private final @NonNull AssociationStoreImpl mAssociationStore;
+    private final @NonNull PackageManagerInternal mPackageManagerInternal;
+    private final @NonNull CompanionDevicePresenceMonitor mDevicePresenceMonitor;
+    private final @NonNull SystemDataTransferRequestStore mSystemDataTransferRequestStore;
+    private final @NonNull CompanionApplicationController mCompanionAppController;
+    private final OnPackageVisibilityChangeListener mOnPackageVisibilityChangeListener;
+    private final ActivityManager mActivityManager;
+
+    /**
+     * A structure that consists of a set of revoked associations that pending for role holder
+     * removal per each user.
+     *
+     * @see #maybeRemoveRoleHolderForAssociation(AssociationInfo)
+     * @see #addToPendingRoleHolderRemoval(AssociationInfo)
+     * @see #removeFromPendingRoleHolderRemoval(AssociationInfo)
+     * @see #getPendingRoleHolderRemovalAssociationsForUser(int)
+     */
+    @GuardedBy("mRevokedAssociationsPendingRoleHolderRemoval")
+    private final PerUserAssociationSet mRevokedAssociationsPendingRoleHolderRemoval =
+            new PerUserAssociationSet();
+    /**
+     * Contains uid-s of packages pending to be removed from the role holder list (after
+     * revocation of an association), which will happen one the package is no longer visible to the
+     * user.
+     * For quicker uid -> (userId, packageName) look-up this is not a {@code Set<Integer>} but
+     * a {@code Map<Integer, String>} which maps uid-s to packageName-s (userId-s can be derived
+     * from uid-s using {@link UserHandle#getUserId(int)}).
+     *
+     * @see #maybeRemoveRoleHolderForAssociation(AssociationInfo)
+     * @see #addToPendingRoleHolderRemoval(AssociationInfo)
+     * @see #removeFromPendingRoleHolderRemoval(AssociationInfo)
+     */
+    @GuardedBy("mRevokedAssociationsPendingRoleHolderRemoval")
+    private final Map<Integer, String> mUidsPendingRoleHolderRemoval = new HashMap<>();
+
+    AssociationRevokeProcessor(@NonNull CompanionDeviceManagerService service,
+            @NonNull AssociationStoreImpl associationStore,
+            @NonNull PackageManagerInternal packageManager,
+            @NonNull CompanionDevicePresenceMonitor devicePresenceMonitor,
+            @NonNull CompanionApplicationController applicationController,
+            @NonNull SystemDataTransferRequestStore systemDataTransferRequestStore) {
+        mService = service;
+        mContext = service.getContext();
+        mActivityManager = mContext.getSystemService(ActivityManager.class);
+        mAssociationStore = associationStore;
+        mPackageManagerInternal = packageManager;
+        mOnPackageVisibilityChangeListener =
+                new OnPackageVisibilityChangeListener(mActivityManager);
+        mDevicePresenceMonitor = devicePresenceMonitor;
+        mCompanionAppController = applicationController;
+        mSystemDataTransferRequestStore = systemDataTransferRequestStore;
+    }
+
+    // TODO: also revoke notification access
+    void disassociateInternal(int associationId) {
+        final AssociationInfo association = mAssociationStore.getAssociationById(associationId);
+        final int userId = association.getUserId();
+        final String packageName = association.getPackageName();
+        final String deviceProfile = association.getDeviceProfile();
+
+        if (!maybeRemoveRoleHolderForAssociation(association)) {
+            // Need to remove the app from list of the role holders, but will have to do it later
+            // (the app is in foreground at the moment).
+            addToPendingRoleHolderRemoval(association);
+        }
+
+        // Need to check if device still present now because CompanionDevicePresenceMonitor will
+        // remove current connected device after mAssociationStore.removeAssociation
+        final boolean wasPresent = mDevicePresenceMonitor.isDevicePresent(associationId);
+
+        // Removing the association.
+        mAssociationStore.removeAssociation(associationId);
+        // Do not need to persistUserState since CompanionDeviceManagerService will get callback
+        // from #onAssociationChanged, and it will handle the persistUserState which including
+        // active and revoked association.
+        logRemoveAssociation(deviceProfile);
+
+        // Remove all the system data transfer requests for the association.
+        mSystemDataTransferRequestStore.removeRequestsByAssociationId(userId, associationId);
+
+        if (!wasPresent || !association.isNotifyOnDeviceNearby()) return;
+        // The device was connected and the app was notified: check if we need to unbind the app
+        // now.
+        final boolean shouldStayBound = any(
+                mAssociationStore.getAssociationsForPackage(userId, packageName),
+                it -> it.isNotifyOnDeviceNearby()
+                        && mDevicePresenceMonitor.isDevicePresent(it.getId()));
+        if (shouldStayBound) return;
+        mCompanionAppController.unbindCompanionApplication(userId, packageName);
+    }
+
+    /**
+     * First, checks if the companion application should be removed from the list role holders when
+     * upon association's removal, i.e.: association's profile (matches the role) is not null,
+     * the application does not have other associations with the same profile, etc.
+     *
+     * <p>
+     * Then, if establishes that the application indeed has to be removed from the list of the role
+     * holders, checks if it could be done right now -
+     * {@link android.app.role.RoleManager#removeRoleHolderAsUser(String, String, int, UserHandle, java.util.concurrent.Executor, java.util.function.Consumer) RoleManager#removeRoleHolderAsUser()}
+     * will kill the application's process, which leads poor user experience if the application was
+     * in foreground when this happened, to avoid this CDMS delays invoking
+     * {@code RoleManager.removeRoleHolderAsUser()} until the app is no longer in foreground.
+     *
+     * @return {@code true} if the application does NOT need be removed from the list of the role
+     *         holders OR if the application was successfully removed from the list of role holders.
+     *         I.e.: from the role-management perspective the association is done with.
+     *         {@code false} if the application needs to be removed from the list of role the role
+     *         holders, BUT it CDMS would prefer to do it later.
+     *         I.e.: application is in the foreground at the moment, but invoking
+     *         {@code RoleManager.removeRoleHolderAsUser()} will kill the application's process,
+     *         which would lead to the poor UX, hence need to try later.
+     */
+    boolean maybeRemoveRoleHolderForAssociation(@NonNull AssociationInfo association) {
+        if (DEBUG) Log.d(TAG, "maybeRemoveRoleHolderForAssociation() association=" + association);
+        final String deviceProfile = association.getDeviceProfile();
+
+        if (deviceProfile == null) {
+            // No role was granted to for this association, there is nothing else we need to here.
+            return true;
+        }
+        // Do not need to remove the system role since it was pre-granted by the system.
+        if (deviceProfile.equals(DEVICE_PROFILE_AUTOMOTIVE_PROJECTION)) {
+            return true;
+        }
+
+        // Check if the applications is associated with another devices with the profile. If so,
+        // it should remain the role holder.
+        final int id = association.getId();
+        final int userId = association.getUserId();
+        final String packageName = association.getPackageName();
+        final boolean roleStillInUse = any(
+                mAssociationStore.getAssociationsForPackage(userId, packageName),
+                it -> deviceProfile.equals(it.getDeviceProfile()) && id != it.getId());
+        if (roleStillInUse) {
+            // Application should remain a role holder, there is nothing else we need to here.
+            return true;
+        }
+
+        final int packageProcessImportance = getPackageProcessImportance(userId, packageName);
+        if (packageProcessImportance <= IMPORTANCE_VISIBLE) {
+            // Need to remove the app from the list of role holders, but the process is visible to
+            // the user at the moment, so we'll need to it later: log and return false.
+            Slog.i(TAG, "Cannot remove role holder for the removed association id=" + id
+                    + " now - process is visible.");
+            return false;
+        }
+
+        removeRoleHolderForAssociation(mContext, association);
+        return true;
+    }
+
+    @SuppressLint("MissingPermission")
+    private int  getPackageProcessImportance(@UserIdInt int userId, @NonNull String packageName) {
+        return Binder.withCleanCallingIdentity(() -> {
+            final int uid =
+                    mPackageManagerInternal.getPackageUid(packageName, /* flags */0, userId);
+            return mActivityManager.getUidImportance(uid);
+        });
+    }
+
+    /**
+     * Set revoked flag for active association and add the revoked association and the uid into
+     * the caches.
+     *
+     * @see #mRevokedAssociationsPendingRoleHolderRemoval
+     * @see #mUidsPendingRoleHolderRemoval
+     * @see OnPackageVisibilityChangeListener
+     */
+    void addToPendingRoleHolderRemoval(@NonNull AssociationInfo association) {
+        // First: set revoked flag
+        association = (new AssociationInfo.Builder(association)).setRevoked(true).build();
+        final String packageName = association.getPackageName();
+        final int userId = association.getUserId();
+        final int uid = mPackageManagerInternal.getPackageUid(packageName, /* flags */0, userId);
+        // Second: add to the set.
+        synchronized (mRevokedAssociationsPendingRoleHolderRemoval) {
+            mRevokedAssociationsPendingRoleHolderRemoval.forUser(association.getUserId())
+                    .add(association);
+            if (!mUidsPendingRoleHolderRemoval.containsKey(uid)) {
+                mUidsPendingRoleHolderRemoval.put(uid, packageName);
+
+                if (mUidsPendingRoleHolderRemoval.size() == 1) {
+                    // Just added first uid: start the listener
+                    mOnPackageVisibilityChangeListener.startListening();
+                }
+            }
+        }
+    }
+
+    /**
+     * Remove the revoked association from the cache and also remove the uid from the map if
+     * there are other associations with the same package still pending for role holder removal.
+     *
+     * @see #mRevokedAssociationsPendingRoleHolderRemoval
+     * @see #mUidsPendingRoleHolderRemoval
+     * @see OnPackageVisibilityChangeListener
+     */
+    private void removeFromPendingRoleHolderRemoval(@NonNull AssociationInfo association) {
+        final String packageName = association.getPackageName();
+        final int userId = association.getUserId();
+        final int uid = mPackageManagerInternal.getPackageUid(packageName, /* flags */  0, userId);
+
+        synchronized (mRevokedAssociationsPendingRoleHolderRemoval) {
+            mRevokedAssociationsPendingRoleHolderRemoval.forUser(userId)
+                    .remove(association);
+
+            final boolean shouldKeepUidForRemoval = any(
+                    getPendingRoleHolderRemovalAssociationsForUser(userId),
+                    ai -> packageName.equals(ai.getPackageName()));
+            // Do not remove the uid from the map since other associations with
+            // the same packageName still pending for role holder removal.
+            if (!shouldKeepUidForRemoval) {
+                mUidsPendingRoleHolderRemoval.remove(uid);
+            }
+
+            if (mUidsPendingRoleHolderRemoval.isEmpty()) {
+                // The set is empty now - can "turn off" the listener.
+                mOnPackageVisibilityChangeListener.stopListening();
+            }
+        }
+    }
+
+    /**
+     * @return a copy of the revoked associations set (safeguarding against
+     *         {@code ConcurrentModificationException}-s).
+     */
+    @NonNull Set<AssociationInfo> getPendingRoleHolderRemovalAssociationsForUser(
+            @UserIdInt int userId) {
+        synchronized (mRevokedAssociationsPendingRoleHolderRemoval) {
+            // Return a copy.
+            return new ArraySet<>(mRevokedAssociationsPendingRoleHolderRemoval.forUser(userId));
+        }
+    }
+
+    private String getPackageNameByUid(int uid) {
+        synchronized (mRevokedAssociationsPendingRoleHolderRemoval) {
+            return mUidsPendingRoleHolderRemoval.get(uid);
+        }
+    }
+
+    /**
+     * An OnUidImportanceListener class which watches the importance of the packages.
+     * In this class, we ONLY interested in the importance of the running process is greater than
+     * {@link ActivityManager.RunningAppProcessInfo#IMPORTANCE_VISIBLE} for the uids have been added
+     * into the {@link #mUidsPendingRoleHolderRemoval}. Lastly remove the role holder for the
+     * revoked associations for the same packages.
+     *
+     * @see #maybeRemoveRoleHolderForAssociation(AssociationInfo)
+     * @see #removeFromPendingRoleHolderRemoval(AssociationInfo)
+     * @see #getPendingRoleHolderRemovalAssociationsForUser(int)
+     */
+    private class OnPackageVisibilityChangeListener implements
+            ActivityManager.OnUidImportanceListener {
+        final @NonNull ActivityManager mAm;
+
+        OnPackageVisibilityChangeListener(@NonNull ActivityManager am) {
+            this.mAm = am;
+        }
+
+        @SuppressLint("MissingPermission")
+        void startListening() {
+            Binder.withCleanCallingIdentity(
+                    () -> mAm.addOnUidImportanceListener(
+                            /* listener */ OnPackageVisibilityChangeListener.this,
+                            ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE));
+        }
+
+        @SuppressLint("MissingPermission")
+        void stopListening() {
+            Binder.withCleanCallingIdentity(
+                    () -> mAm.removeOnUidImportanceListener(
+                            /* listener */ OnPackageVisibilityChangeListener.this));
+        }
+
+        @Override
+        public void onUidImportance(int uid, int importance) {
+            if (importance <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
+                // The lower the importance value the more "important" the process is.
+                // We are only interested when the process ceases to be visible.
+                return;
+            }
+
+            final String packageName = getPackageNameByUid(uid);
+            if (packageName == null) {
+                // Not interested in this uid.
+                return;
+            }
+
+            final int userId = UserHandle.getUserId(uid);
+
+            boolean needToPersistStateForUser = false;
+
+            for (AssociationInfo association :
+                    getPendingRoleHolderRemovalAssociationsForUser(userId)) {
+                if (!packageName.equals(association.getPackageName())) continue;
+
+                if (!maybeRemoveRoleHolderForAssociation(association)) {
+                    // Did not remove the role holder, will have to try again later.
+                    continue;
+                }
+
+                removeFromPendingRoleHolderRemoval(association);
+                needToPersistStateForUser = true;
+            }
+
+            if (needToPersistStateForUser) {
+                mService.postPersistUserState(userId);
+            }
+        }
+    }
+}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index ba1f51b..09c7793 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -22,7 +22,6 @@
 import static android.Manifest.permission.MANAGE_COMPANION_DEVICES;
 import static android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE;
 import static android.Manifest.permission.USE_COMPANION_TRANSPORTS;
-import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
 import static android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION;
 import static android.companion.DevicePresenceEvent.EVENT_BLE_APPEARED;
 import static android.companion.DevicePresenceEvent.EVENT_BLE_DISAPPEARED;
@@ -39,7 +38,6 @@
 import static com.android.internal.util.Preconditions.checkState;
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 import static com.android.server.companion.AssociationStore.CHANGE_TYPE_UPDATED_ADDRESS_UNCHANGED;
-import static com.android.server.companion.MetricUtils.logRemoveAssociation;
 import static com.android.server.companion.PackageUtils.isRestrictedSettingsAllowed;
 import static com.android.server.companion.PackageUtils.enforceUsesCompanionDeviceFeature;
 import static com.android.server.companion.PackageUtils.getPackageInfo;
@@ -49,7 +47,6 @@
 import static com.android.server.companion.PermissionsUtils.enforceCallerIsSystemOr;
 import static com.android.server.companion.PermissionsUtils.enforceCallerIsSystemOrCanInteractWithUserId;
 import static com.android.server.companion.PermissionsUtils.sanitizeWithCallerChecks;
-import static com.android.server.companion.RolesUtils.removeRoleHolderForAssociation;
 
 import static java.util.Objects.requireNonNull;
 import static java.util.concurrent.TimeUnit.DAYS;
@@ -61,7 +58,6 @@
 import android.annotation.SuppressLint;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
-import android.app.ActivityManager.RunningAppProcessInfo;
 import android.app.ActivityManagerInternal;
 import android.app.AppOpsManager;
 import android.app.NotificationManager;
@@ -149,7 +145,7 @@
     static final String TAG = "CDM_CompanionDeviceManagerService";
     static final boolean DEBUG = false;
 
-    /** Range of Association IDs allocated for a user.*/
+    /** Range of Association IDs allocated for a user. */
     private static final int ASSOCIATIONS_IDS_PER_USER_RANGE = 100000;
     private static final long PAIR_WITHOUT_PROMPT_WINDOW_MS = 10 * 60 * 1000; // 10 min
 
@@ -162,8 +158,6 @@
     private static final int MAX_CN_LENGTH = 500;
 
     private final ActivityManager mActivityManager;
-    private final OnPackageVisibilityChangeListener mOnPackageVisibilityChangeListener;
-
     private PersistentDataStore mPersistentStore;
     private final PersistUserStateHandler mUserPersistenceHandler;
 
@@ -175,6 +169,7 @@
     private CompanionDevicePresenceMonitor mDevicePresenceMonitor;
     private CompanionApplicationController mCompanionAppController;
     private CompanionTransportManager mTransportManager;
+    private AssociationRevokeProcessor mAssociationRevokeProcessor;
 
     private final ActivityTaskManagerInternal mAtmInternal;
     private final ActivityManagerInternal mAmInternal;
@@ -193,33 +188,6 @@
     @GuardedBy("mPreviouslyUsedIds")
     private final SparseArray<Map<String, Set<Integer>>> mPreviouslyUsedIds = new SparseArray<>();
 
-    /**
-     * A structure that consists of a set of revoked associations that pending for role holder
-     * removal per each user.
-     *
-     * @see #maybeRemoveRoleHolderForAssociation(AssociationInfo)
-     * @see #addToPendingRoleHolderRemoval(AssociationInfo)
-     * @see #removeFromPendingRoleHolderRemoval(AssociationInfo)
-     * @see #getPendingRoleHolderRemovalAssociationsForUser(int)
-     */
-    @GuardedBy("mRevokedAssociationsPendingRoleHolderRemoval")
-    private final PerUserAssociationSet mRevokedAssociationsPendingRoleHolderRemoval =
-            new PerUserAssociationSet();
-    /**
-     * Contains uid-s of packages pending to be removed from the role holder list (after
-     * revocation of an association), which will happen one the package is no longer visible to the
-     * user.
-     * For quicker uid -> (userId, packageName) look-up this is not a {@code Set<Integer>} but
-     * a {@code Map<Integer, String>} which maps uid-s to packageName-s (userId-s can be derived
-     * from uid-s using {@link UserHandle#getUserId(int)}).
-     *
-     * @see #maybeRemoveRoleHolderForAssociation(AssociationInfo)
-     * @see #addToPendingRoleHolderRemoval(AssociationInfo)
-     * @see #removeFromPendingRoleHolderRemoval(AssociationInfo)
-     */
-    @GuardedBy("mRevokedAssociationsPendingRoleHolderRemoval")
-    private final Map<Integer, String> mUidsPendingRoleHolderRemoval = new HashMap<>();
-
     private final RemoteCallbackList<IOnAssociationsChangedListener> mListeners =
             new RemoteCallbackList<>();
 
@@ -243,8 +211,6 @@
         mAssociationStore = new AssociationStoreImpl();
         mSystemDataTransferRequestStore = new SystemDataTransferRequestStore();
 
-        mOnPackageVisibilityChangeListener =
-                new OnPackageVisibilityChangeListener(mActivityManager);
         mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
         mObservableUuidStore = new ObservableUuidStore();
     }
@@ -276,6 +242,9 @@
         mSystemDataTransferProcessor = new SystemDataTransferProcessor(this,
                 mPackageManagerInternal, mAssociationStore,
                 mSystemDataTransferRequestStore, mTransportManager);
+        mAssociationRevokeProcessor = new AssociationRevokeProcessor(this, mAssociationStore,
+                mPackageManagerInternal, mDevicePresenceMonitor, mCompanionAppController,
+                mSystemDataTransferRequestStore);
         // TODO(b/279663946): move context sync to a dedicated system service
         mCrossDeviceSyncController = new CrossDeviceSyncController(getContext(), mTransportManager);
 
@@ -307,12 +276,13 @@
                 mBackupRestoreProcessor.addToPendingAppInstall(association);
             } else if (!association.isRevoked()) {
                 activeAssociations.add(association);
-            } else if (maybeRemoveRoleHolderForAssociation(association)) {
+            } else if (mAssociationRevokeProcessor.maybeRemoveRoleHolderForAssociation(
+                    association)) {
                 // Nothing more to do here, but we'll need to persist all the associations to the
                 // disk afterwards.
                 usersToPersistStateFor.add(association.getUserId());
             } else {
-                addToPendingRoleHolderRemoval(association);
+                mAssociationRevokeProcessor.addToPendingRoleHolderRemoval(association);
             }
         }
 
@@ -374,7 +344,7 @@
                 final List<ParcelUuid> deviceUuids = ArrayUtils.isEmpty(bluetoothDeviceUuids)
                         ? Collections.emptyList() : Arrays.asList(bluetoothDeviceUuids);
 
-                for (AssociationInfo ai:
+                for (AssociationInfo ai :
                         mAssociationStore.getAssociationsByAddress(bluetoothDevice.getAddress())) {
                     Slog.i(TAG, "onUserUnlocked, device id( " + ai.getId() + " ) is connected");
                     mDevicePresenceMonitor.onBluetoothCompanionDeviceConnected(ai.getId());
@@ -495,7 +465,7 @@
         final String packageName = uuid.getPackageName();
         final int userId = uuid.getUserId();
 
-        switch(event) {
+        switch (event) {
             case EVENT_BT_CONNECTED:
                 if (!mCompanionAppController.isCompanionApplicationBound(userId, packageName)) {
                     mCompanionAppController.bindCompanionApplication(
@@ -544,8 +514,8 @@
 
     /**
      * @return whether the package should be bound (i.e. at least one of the devices associated with
-     *         the package is currently present OR the UUID to be observed by this package is
-     *         currently present).
+     * the package is currently present OR the UUID to be observed by this package is
+     * currently present).
      */
     private boolean shouldBindPackage(@UserIdInt int userId, @NonNull String packageName) {
         final List<AssociationInfo> packageAssociations =
@@ -599,7 +569,8 @@
         allAssociations = new ArrayList<>(
                 mAssociationStore.getAssociationsForUser(userId));
         // ... and add the revoked (removed) association, that are yet to be permanently removed.
-        allAssociations.addAll(getPendingRoleHolderRemovalAssociationsForUser(userId));
+        allAssociations.addAll(
+                mAssociationRevokeProcessor.getPendingRoleHolderRemovalAssociationsForUser(userId));
         // ... and add the restored associations that are pending missing package installation.
         allAssociations.addAll(mBackupRestoreProcessor
                 .getAssociationsPendingAppInstallForUser(userId));
@@ -654,7 +625,7 @@
         }
         // Clear role holders
         for (AssociationInfo association : associationsForPackage) {
-            maybeRemoveRoleHolderForAssociation(association);
+            mAssociationRevokeProcessor.maybeRemoveRoleHolderForAssociation(association);
         }
         // Clear the uuids to be observed.
         for (ObservableUuid uuid : uuidsTobeObserved) {
@@ -712,7 +683,7 @@
             final int id = association.getId();
 
             Slog.i(TAG, "Removing inactive self-managed association id=" + id);
-            disassociateInternal(id);
+            mAssociationRevokeProcessor.disassociateInternal(id);
         }
     }
 
@@ -857,7 +828,7 @@
 
             final AssociationInfo association =
                     getAssociationWithCallerChecks(userId, packageName, deviceMacAddress);
-            disassociateInternal(association.getId());
+            mAssociationRevokeProcessor.disassociateInternal(association.getId());
         }
 
         @Override
@@ -866,7 +837,7 @@
 
             final AssociationInfo association =
                     getAssociationWithCallerChecks(associationId);
-            disassociateInternal(association.getId());
+            mAssociationRevokeProcessor.disassociateInternal(association.getId());
         }
 
         @Override
@@ -902,9 +873,9 @@
         }
 
         /**
-        * @deprecated Use
-        * {@link NotificationManager#isNotificationListenerAccessGranted(ComponentName)} instead.
-        */
+         * @deprecated Use
+         * {@link NotificationManager#isNotificationListenerAccessGranted(ComponentName)} instead.
+         */
         @Deprecated
         @Override
         public boolean hasNotificationAccess(ComponentName component) throws RemoteException {
@@ -1300,7 +1271,7 @@
             return new CompanionDeviceShellCommand(CompanionDeviceManagerService.this,
                     mAssociationStore, mDevicePresenceMonitor, mTransportManager,
                     mSystemDataTransferProcessor, mAssociationRequestsProcessor,
-                    mBackupRestoreProcessor)
+                    mBackupRestoreProcessor, mAssociationRevokeProcessor)
                     .exec(this, in.getFileDescriptor(), out.getFileDescriptor(),
                             err.getFileDescriptor(), args);
         }
@@ -1381,7 +1352,7 @@
             // another association by the time when it is activated from the package installation.
             final Set<AssociationInfo> pendingAssociations = mBackupRestoreProcessor
                     .getAssociationsPendingAppInstallForUser(userId);
-            for (AssociationInfo it: pendingAssociations) {
+            for (AssociationInfo it : pendingAssociations) {
                 usedIds.put(it.getId(), true);
             }
 
@@ -1407,198 +1378,6 @@
         }
     }
 
-    // TODO: also revoke notification access
-    void disassociateInternal(int associationId) {
-        final AssociationInfo association = mAssociationStore.getAssociationById(associationId);
-        final int userId = association.getUserId();
-        final String packageName = association.getPackageName();
-        final String deviceProfile = association.getDeviceProfile();
-
-        if (!maybeRemoveRoleHolderForAssociation(association)) {
-            // Need to remove the app from list of the role holders, but will have to do it later
-            // (the app is in foreground at the moment).
-            addToPendingRoleHolderRemoval(association);
-        }
-
-        // Need to check if device still present now because CompanionDevicePresenceMonitor will
-        // remove current connected device after mAssociationStore.removeAssociation
-        final boolean wasPresent = mDevicePresenceMonitor.isDevicePresent(associationId);
-
-        // Removing the association.
-        mAssociationStore.removeAssociation(associationId);
-        // Do not need to persistUserState since CompanionDeviceManagerService will get callback
-        // from #onAssociationChanged, and it will handle the persistUserState which including
-        // active and revoked association.
-        logRemoveAssociation(deviceProfile);
-
-        // Remove all the system data transfer requests for the association.
-        mSystemDataTransferRequestStore.removeRequestsByAssociationId(userId, associationId);
-
-        if (!wasPresent || !association.isNotifyOnDeviceNearby()) return;
-        // The device was connected and the app was notified: check if we need to unbind the app
-        // now.
-        final boolean shouldStayBound = any(
-                mAssociationStore.getAssociationsForPackage(userId, packageName),
-                it -> it.isNotifyOnDeviceNearby()
-                        && mDevicePresenceMonitor.isDevicePresent(it.getId()));
-        if (shouldStayBound) return;
-        mCompanionAppController.unbindCompanionApplication(userId, packageName);
-    }
-
-    /**
-     * First, checks if the companion application should be removed from the list role holders when
-     * upon association's removal, i.e.: association's profile (matches the role) is not null,
-     * the application does not have other associations with the same profile, etc.
-     *
-     * <p>
-     * Then, if establishes that the application indeed has to be removed from the list of the role
-     * holders, checks if it could be done right now -
-     * {@link android.app.role.RoleManager#removeRoleHolderAsUser(String, String, int, UserHandle, java.util.concurrent.Executor, java.util.function.Consumer) RoleManager#removeRoleHolderAsUser()}
-     * will kill the application's process, which leads poor user experience if the application was
-     * in foreground when this happened, to avoid this CDMS delays invoking
-     * {@code RoleManager.removeRoleHolderAsUser()} until the app is no longer in foreground.
-     *
-     * @return {@code true} if the application does NOT need be removed from the list of the role
-     *         holders OR if the application was successfully removed from the list of role holders.
-     *         I.e.: from the role-management perspective the association is done with.
-     *         {@code false} if the application needs to be removed from the list of role the role
-     *         holders, BUT it CDMS would prefer to do it later.
-     *         I.e.: application is in the foreground at the moment, but invoking
-     *         {@code RoleManager.removeRoleHolderAsUser()} will kill the application's process,
-     *         which would lead to the poor UX, hence need to try later.
-     */
-
-    private boolean maybeRemoveRoleHolderForAssociation(@NonNull AssociationInfo association) {
-        if (DEBUG) Log.d(TAG, "maybeRemoveRoleHolderForAssociation() association=" + association);
-
-        final String deviceProfile = association.getDeviceProfile();
-        if (deviceProfile == null) {
-            // No role was granted to for this association, there is nothing else we need to here.
-            return true;
-        }
-        // Do not need to remove the system role since it was pre-granted by the system.
-        if (deviceProfile.equals(DEVICE_PROFILE_AUTOMOTIVE_PROJECTION)) {
-            return true;
-        }
-
-        // Check if the applications is associated with another devices with the profile. If so,
-        // it should remain the role holder.
-        final int id = association.getId();
-        final int userId = association.getUserId();
-        final String packageName = association.getPackageName();
-        final boolean roleStillInUse = any(
-                mAssociationStore.getAssociationsForPackage(userId, packageName),
-                it -> deviceProfile.equals(it.getDeviceProfile()) && id != it.getId());
-        if (roleStillInUse) {
-            // Application should remain a role holder, there is nothing else we need to here.
-            return true;
-        }
-
-        final int packageProcessImportance = getPackageProcessImportance(userId, packageName);
-        if (packageProcessImportance <= IMPORTANCE_VISIBLE) {
-            // Need to remove the app from the list of role holders, but the process is visible to
-            // the user at the moment, so we'll need to it later: log and return false.
-            Slog.i(TAG, "Cannot remove role holder for the removed association id=" + id
-                    + " now - process is visible.");
-            return false;
-        }
-
-        removeRoleHolderForAssociation(getContext(), association);
-        return true;
-    }
-
-    private int getPackageProcessImportance(@UserIdInt int userId, @NonNull String packageName) {
-        return Binder.withCleanCallingIdentity(() -> {
-            final int uid =
-                    mPackageManagerInternal.getPackageUid(packageName, /* flags */0, userId);
-            return mActivityManager.getUidImportance(uid);
-        });
-    }
-
-    /**
-     * Set revoked flag for active association and add the revoked association and the uid into
-     * the caches.
-     *
-     * @see #mRevokedAssociationsPendingRoleHolderRemoval
-     * @see #mUidsPendingRoleHolderRemoval
-     * @see OnPackageVisibilityChangeListener
-     */
-    private void addToPendingRoleHolderRemoval(@NonNull AssociationInfo association) {
-        // First: set revoked flag.
-        association = (new AssociationInfo.Builder(association))
-                .setRevoked(true)
-                .build();
-
-        final String packageName = association.getPackageName();
-        final int userId = association.getUserId();
-        final int uid = mPackageManagerInternal.getPackageUid(packageName, /* flags */0, userId);
-
-        // Second: add to the set.
-        synchronized (mRevokedAssociationsPendingRoleHolderRemoval) {
-            mRevokedAssociationsPendingRoleHolderRemoval.forUser(association.getUserId())
-                    .add(association);
-            if (!mUidsPendingRoleHolderRemoval.containsKey(uid)) {
-                mUidsPendingRoleHolderRemoval.put(uid, packageName);
-
-                if (mUidsPendingRoleHolderRemoval.size() == 1) {
-                    // Just added first uid: start the listener
-                    mOnPackageVisibilityChangeListener.startListening();
-                }
-            }
-        }
-    }
-
-    /**
-     * Remove the revoked association from the cache and also remove the uid from the map if
-     * there are other associations with the same package still pending for role holder removal.
-     *
-     * @see #mRevokedAssociationsPendingRoleHolderRemoval
-     * @see #mUidsPendingRoleHolderRemoval
-     * @see OnPackageVisibilityChangeListener
-     */
-    private void removeFromPendingRoleHolderRemoval(@NonNull AssociationInfo association) {
-        final String packageName = association.getPackageName();
-        final int userId = association.getUserId();
-        final int uid = mPackageManagerInternal.getPackageUid(packageName, /* flags */0, userId);
-
-        synchronized (mRevokedAssociationsPendingRoleHolderRemoval) {
-            mRevokedAssociationsPendingRoleHolderRemoval.forUser(userId)
-                    .remove(association);
-
-            final boolean shouldKeepUidForRemoval = any(
-                    getPendingRoleHolderRemovalAssociationsForUser(userId),
-                    ai -> packageName.equals(ai.getPackageName()));
-            // Do not remove the uid from the map since other associations with
-            // the same packageName still pending for role holder removal.
-            if (!shouldKeepUidForRemoval) {
-                mUidsPendingRoleHolderRemoval.remove(uid);
-            }
-
-            if (mUidsPendingRoleHolderRemoval.isEmpty()) {
-                // The set is empty now - can "turn off" the listener.
-                mOnPackageVisibilityChangeListener.stopListening();
-            }
-        }
-    }
-
-    /**
-     * @return a copy of the revoked associations set (safeguarding against
-     *         {@code ConcurrentModificationException}-s).
-     */
-    private @NonNull Set<AssociationInfo> getPendingRoleHolderRemovalAssociationsForUser(
-            @UserIdInt int userId) {
-        synchronized (mRevokedAssociationsPendingRoleHolderRemoval) {
-            // Return a copy.
-            return new ArraySet<>(mRevokedAssociationsPendingRoleHolderRemoval.forUser(userId));
-        }
-    }
-
-    private String getPackageNameByUid(int uid) {
-        synchronized (mRevokedAssociationsPendingRoleHolderRemoval) {
-            return mUidsPendingRoleHolderRemoval.get(uid);
-        }
-    }
-
     void updateSpecialAccessPermissionForAssociatedPackage(AssociationInfo association) {
         final PackageInfo packageInfo =
                 getPackageInfo(getContext(), association.getUserId(), association.getPackageName());
@@ -1704,11 +1483,11 @@
 
     private final AssociationStore.OnChangeListener mAssociationStoreChangeListener =
             new AssociationStore.OnChangeListener() {
-        @Override
-        public void onAssociationChanged(int changeType, AssociationInfo association) {
-            onAssociationChangedInternal(changeType, association);
-        }
-    };
+                @Override
+                public void onAssociationChanged(int changeType, AssociationInfo association) {
+                    onAssociationChangedInternal(changeType, association);
+                }
+            };
 
     private final CompanionDevicePresenceMonitor.Callback mDevicePresenceCallback =
             new CompanionDevicePresenceMonitor.Callback() {
@@ -1731,7 +1510,7 @@
                 public void onDevicePresenceEventByUuid(ObservableUuid uuid, int event) {
                     onDevicePresenceEventByUuidInternal(uuid, event);
                 }
-    };
+            };
 
     private final PackageMonitor mPackageMonitor = new PackageMonitor() {
         @Override
@@ -1887,73 +1666,8 @@
         }
     }
 
-    /**
-     * An OnUidImportanceListener class which watches the importance of the packages.
-     * In this class, we ONLY interested in the importance of the running process is greater than
-     * {@link RunningAppProcessInfo.IMPORTANCE_VISIBLE} for the uids have been added into the
-     * {@link mUidsPendingRoleHolderRemoval}. Lastly remove the role holder for the revoked
-     * associations for the same packages.
-     *
-     * @see #maybeRemoveRoleHolderForAssociation(AssociationInfo)
-     * @see #removeFromPendingRoleHolderRemoval(AssociationInfo)
-     * @see #getPendingRoleHolderRemovalAssociationsForUser(int)
-     */
-    private class OnPackageVisibilityChangeListener implements
-            ActivityManager.OnUidImportanceListener {
-        final @NonNull ActivityManager mAm;
-
-        OnPackageVisibilityChangeListener(@NonNull ActivityManager am) {
-            this.mAm = am;
-        }
-
-        void startListening() {
-            Binder.withCleanCallingIdentity(
-                    () -> mAm.addOnUidImportanceListener(
-                            /* listener */ OnPackageVisibilityChangeListener.this,
-                            RunningAppProcessInfo.IMPORTANCE_VISIBLE));
-        }
-
-        void stopListening() {
-            Binder.withCleanCallingIdentity(
-                    () -> mAm.removeOnUidImportanceListener(
-                            /* listener */ OnPackageVisibilityChangeListener.this));
-        }
-
-        @Override
-        public void onUidImportance(int uid, int importance) {
-            if (importance <= RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
-                // The lower the importance value the more "important" the process is.
-                // We are only interested when the process ceases to be visible.
-                return;
-            }
-
-            final String packageName = getPackageNameByUid(uid);
-            if (packageName == null) {
-                // Not interested in this uid.
-                return;
-            }
-
-            final int userId = UserHandle.getUserId(uid);
-
-            boolean needToPersistStateForUser = false;
-
-            for (AssociationInfo association :
-                    getPendingRoleHolderRemovalAssociationsForUser(userId)) {
-                if (!packageName.equals(association.getPackageName())) continue;
-
-                if (!maybeRemoveRoleHolderForAssociation(association)) {
-                    // Did not remove the role holder, will have to try again later.
-                    continue;
-                }
-
-                removeFromPendingRoleHolderRemoval(association);
-                needToPersistStateForUser = true;
-            }
-
-            if (needToPersistStateForUser) {
-                mUserPersistenceHandler.postPersistUserState(userId);
-            }
-        }
+    void postPersistUserState(@UserIdInt int userId) {
+        mUserPersistenceHandler.postPersistUserState(userId);
     }
 
     static class PerUserAssociationSet extends PerUser<Set<AssociationInfo>> {
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
index 5663434..de4f2b6 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
@@ -45,6 +45,7 @@
     private static final String TAG = "CDM_CompanionDeviceShellCommand";
 
     private final CompanionDeviceManagerService mService;
+    private final AssociationRevokeProcessor mRevokeProcessor;
     private final AssociationStoreImpl mAssociationStore;
     private final CompanionDevicePresenceMonitor mDevicePresenceMonitor;
     private final CompanionTransportManager mTransportManager;
@@ -59,7 +60,8 @@
             CompanionTransportManager transportManager,
             SystemDataTransferProcessor systemDataTransferProcessor,
             AssociationRequestsProcessor associationRequestsProcessor,
-            BackupRestoreProcessor backupRestoreProcessor) {
+            BackupRestoreProcessor backupRestoreProcessor,
+            AssociationRevokeProcessor revokeProcessor) {
         mService = service;
         mAssociationStore = associationStore;
         mDevicePresenceMonitor = devicePresenceMonitor;
@@ -67,6 +69,7 @@
         mSystemDataTransferProcessor = systemDataTransferProcessor;
         mAssociationRequestsProcessor = associationRequestsProcessor;
         mBackupRestoreProcessor = backupRestoreProcessor;
+        mRevokeProcessor = revokeProcessor;
     }
 
     @Override
@@ -126,7 +129,7 @@
                     final AssociationInfo association =
                             mService.getAssociationWithCallerChecks(userId, packageName, address);
                     if (association != null) {
-                        mService.disassociateInternal(association.getId());
+                        mRevokeProcessor.disassociateInternal(association.getId());
                     }
                 }
                 break;
@@ -138,7 +141,7 @@
                             mAssociationStore.getAssociationsForPackage(userId, packageName);
                     for (AssociationInfo association : userAssociations) {
                         if (sanitizeWithCallerChecks(mService.getContext(), association) != null) {
-                            mService.disassociateInternal(association.getId());
+                            mRevokeProcessor.disassociateInternal(association.getId());
                         }
                     }
                 }
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 7940ca6..d1d7ee7 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -41,16 +41,18 @@
 genrule {
     name: "services.core.protologsrc",
     srcs: [
+        ":protolog-impl",
         ":protolog-groups",
         ":services.core-sources-am-wm",
     ],
     tools: ["protologtool"],
     cmd: "$(location protologtool) transform-protolog-calls " +
         "--protolog-class com.android.internal.protolog.common.ProtoLog " +
-        "--protolog-impl-class com.android.internal.protolog.ProtoLogImpl " +
-        "--protolog-cache-class 'com.android.server.wm.ProtoLogCache' " +
         "--loggroups-class com.android.internal.protolog.ProtoLogGroup " +
         "--loggroups-jar $(location :protolog-groups) " +
+        "--viewer-config-file-path /etc/core.protolog.pb " +
+        "--legacy-viewer-config-file-path /system/etc/protolog.conf.json.gz " +
+        "--legacy-output-file-path /data/misc/wmtrace/wm_log.winscope " +
         "--output-srcjar $(out) " +
         "$(locations :services.core-sources-am-wm)",
     out: ["services.core.protolog.srcjar"],
@@ -67,12 +69,30 @@
         "--protolog-class com.android.internal.protolog.common.ProtoLog " +
         "--loggroups-class com.android.internal.protolog.ProtoLogGroup " +
         "--loggroups-jar $(location :protolog-groups) " +
-        "--viewer-conf $(out) " +
+        "--viewer-config-type json " +
+        "--viewer-config $(out) " +
         "$(locations :services.core-sources-am-wm)",
     out: ["services.core.protolog.json"],
 }
 
 genrule {
+    name: "gen-core.protolog.pb",
+    srcs: [
+        ":protolog-groups",
+        ":services.core-sources-am-wm",
+    ],
+    tools: ["protologtool"],
+    cmd: "$(location protologtool) generate-viewer-config " +
+        "--protolog-class com.android.internal.protolog.common.ProtoLog " +
+        "--loggroups-class com.android.internal.protolog.ProtoLogGroup " +
+        "--loggroups-jar $(location :protolog-groups) " +
+        "--viewer-config-type proto " +
+        "--viewer-config $(out) " +
+        "$(locations :services.core-sources-am-wm)",
+    out: ["core.protolog.pb"],
+}
+
+genrule {
     name: "checked-protolog.json",
     srcs: [
         ":generate-protolog.json",
@@ -89,6 +109,22 @@
 }
 
 genrule {
+    name: "checked-core.protolog.pb",
+    srcs: [
+        ":gen-core.protolog.pb",
+        ":file-core.protolog.pb",
+    ],
+    cmd: "cp $(location :gen-core.protolog.pb) $(out) && " +
+        "{ ! (diff $(out) $(location :file-core.protolog.pb) | grep -q '^<') || " +
+        "{ echo -e '\\n\\n################################################################\\n#\\n" +
+        "#  ERROR: ProtoLog viewer config is stale.  To update it, run:\\n#\\n" +
+        "#  cp $${ANDROID_BUILD_TOP}/$(location :gen-core.protolog.pb) " +
+        "$${ANDROID_BUILD_TOP}/$(location :file-core.protolog.pb)\\n#\\n" +
+        "################################################################\\n\\n' >&2 && false; } }",
+    out: ["core.protolog.pb"],
+}
+
+genrule {
     name: "statslog-art-java-gen",
     tools: ["stats-log-api-gen"],
     cmd: "$(location stats-log-api-gen) --java $(out) --module art" +
@@ -158,6 +194,7 @@
         "default_television.xml",
         "gps_debug.conf",
         "protolog.conf.json.gz",
+        "core.protolog.pb",
     ],
 
     static_libs: [
@@ -269,3 +306,8 @@
     name: "protolog.conf.json.gz",
     src: ":services.core.json.gz",
 }
+
+prebuilt_etc {
+    name: "core.protolog.pb",
+    src: ":checked-core.protolog.pb",
+}
diff --git a/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java b/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java
index 0904c47..7d8aad7 100644
--- a/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java
+++ b/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java
@@ -63,6 +63,9 @@
     @Nullable private MediaProjectionManager mProjectionManager;
     @Nullable private WindowManagerInternal mWindowManager;
 
+    // screen recorder packages exempted from screen share protection.
+    private ArraySet<String> mExemptedPackages = null;
+
     final Object mSensitiveContentProtectionLock = new Object();
 
     @GuardedBy("mSensitiveContentProtectionLock")
@@ -76,7 +79,7 @@
                     Trace.beginSection(
                             "SensitiveContentProtectionManagerService.onProjectionStart");
                     try {
-                        onProjectionStart();
+                        onProjectionStart(info);
                     } finally {
                         Trace.endSection();
                     }
@@ -113,15 +116,25 @@
         if (DEBUG) Log.d(TAG, "onBootPhase - PHASE_BOOT_COMPLETED");
 
         init(getContext().getSystemService(MediaProjectionManager.class),
-                LocalServices.getService(WindowManagerInternal.class));
+                LocalServices.getService(WindowManagerInternal.class),
+                getExemptedPackages());
         if (sensitiveContentAppProtection()) {
             publishBinderService(Context.SENSITIVE_CONTENT_PROTECTION_SERVICE,
                     new SensitiveContentProtectionManagerServiceBinder());
         }
     }
 
+    // These packages are exempted from screen share protection.
+    private ArraySet<String> getExemptedPackages() {
+        final ArraySet<String> exemptedPackages =
+                SystemConfig.getInstance().getBugreportWhitelistedPackages();
+        // TODO(b/323361046) - Add sys ui recorder package.
+        return exemptedPackages;
+    }
+
     @VisibleForTesting
-    void init(MediaProjectionManager projectionManager, WindowManagerInternal windowManager) {
+    void init(MediaProjectionManager projectionManager, WindowManagerInternal windowManager,
+            ArraySet<String> exemptedPackages) {
         if (DEBUG) Log.d(TAG, "init");
 
         Objects.requireNonNull(projectionManager);
@@ -129,6 +142,7 @@
 
         mProjectionManager = projectionManager;
         mWindowManager = windowManager;
+        mExemptedPackages = exemptedPackages;
 
         // TODO(b/317250444): use MediaProjectionManagerService directly, reduces unnecessary
         //  handler, delegate, and binder death recipient
@@ -165,7 +179,11 @@
         }
     }
 
-    private void onProjectionStart() {
+    private void onProjectionStart(MediaProjectionInfo info) {
+        if (mExemptedPackages != null && mExemptedPackages.contains(info.getPackageName())) {
+            Log.w(TAG, info.getPackageName() + " is exempted from screen share protection.");
+            return;
+        }
         // TODO(b/324447419): move GlobalSettings lookup to background thread
         boolean disableScreenShareProtections =
                 Settings.Global.getInt(getContext().getContentResolver(),
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2dd2f8f..e222878 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -18462,7 +18462,8 @@
                             (WindowProcessController) procsToKill.get(i);
                     final ProcessRecord pr = (ProcessRecord) wpc.mOwner;
                     if (ActivityManager.isProcStateBackground(pr.mState.getSetProcState())
-                            && pr.mReceivers.numberOfCurReceivers() == 0) {
+                            && pr.mReceivers.numberOfCurReceivers() == 0
+                            && !pr.mState.hasStartedServices()) {
                         pr.killLocked("remove task", ApplicationExitInfo.REASON_USER_REQUESTED,
                                 ApplicationExitInfo.SUBREASON_REMOVE_TASK, true);
                     } else {
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 9568116..31328ae 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -3322,7 +3322,8 @@
                 reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);
             }
             if (app.getWaitingToKill() != null && app.mReceivers.numberOfCurReceivers() == 0
-                    && ActivityManager.isProcStateBackground(state.getSetProcState())) {
+                    && ActivityManager.isProcStateBackground(state.getSetProcState())
+                    && !state.hasStartedServices()) {
                 app.killLocked(app.getWaitingToKill(), ApplicationExitInfo.REASON_USER_REQUESTED,
                         ApplicationExitInfo.SUBREASON_REMOVE_TASK, true);
                 success = false;
diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
index 1412259..2ef433c 100644
--- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
@@ -64,6 +64,9 @@
 import java.io.File;
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
 import java.util.UUID;
 import java.util.concurrent.ExecutionException;
@@ -76,6 +79,9 @@
  * The error state of the process, such as if it's crashing/ANR etc.
  */
 class ProcessErrorStateRecord {
+    private static final DateTimeFormatter DROPBOX_TIME_FORMATTER =
+            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSZ");
+
     final ProcessRecord mApp;
     private final ActivityManagerService mService;
 
@@ -444,6 +450,13 @@
             info.append("ErrorId: ").append(errorId.toString()).append("\n");
         }
         info.append("Frozen: ").append(mApp.mOptRecord.isFrozen()).append("\n");
+        if (timeoutRecord != null && timeoutRecord.mEndUptimeMillis > 0) {
+            long millisSinceEndUptimeMs = anrTime - timeoutRecord.mEndUptimeMillis;
+            String formattedTime = DROPBOX_TIME_FORMATTER.format(
+                    Instant.now().minusMillis(millisSinceEndUptimeMs)
+                            .atZone(ZoneId.systemDefault()));
+            info.append("Timestamp: ").append(formattedTime).append("\n");
+        }
 
         // Retrieve controller with max ANR delay from AnrControllers
         // Note that we retrieve the controller before dumping stacks because dumping stacks can
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 767f54d..d1bda79 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -120,11 +120,13 @@
     static final String[] sDeviceConfigAconfigScopes = new String[] {
         "accessibility",
         "android_core_networking",
+        "android_stylus",
         "aoc",
         "app_widgets",
         "arc_next",
         "avic",
         "bluetooth",
+        "brownout_mitigation_audio",
         "build",
         "biometrics",
         "biometrics_framework",
diff --git a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java
index 5f12ce1..9f31f37 100644
--- a/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java
+++ b/services/core/java/com/android/server/ambientcontext/AmbientContextManagerService.java
@@ -73,8 +73,7 @@
     private static final Set<Integer> DEFAULT_EVENT_SET = Sets.newHashSet(
             AmbientContextEvent.EVENT_COUGH,
             AmbientContextEvent.EVENT_SNORE,
-            AmbientContextEvent.EVENT_BACK_DOUBLE_TAP,
-            AmbientContextEvent.EVENT_HEART_RATE);
+            AmbientContextEvent.EVENT_BACK_DOUBLE_TAP);
 
     /** Default value in absence of {@link DeviceConfig} override. */
     private static final boolean DEFAULT_SERVICE_ENABLED = true;
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 0cc6494..fb62785 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -661,8 +661,12 @@
         @NonNull OpEntry createEntryLocked(String persistentDeviceId) {
             // TODO(b/308201969): Update this method when we introduce disk persistence of events
             // for accesses on external devices.
-            final ArrayMap<String, AttributedOp> attributedOps = mDeviceAttributedOps.get(
+            ArrayMap<String, AttributedOp> attributedOps = mDeviceAttributedOps.get(
                     persistentDeviceId);
+            if (attributedOps == null) {
+                attributedOps = new ArrayMap<>();
+            }
+
             final ArrayMap<String, AppOpsManager.AttributedOpEntry> attributionEntries =
                     new ArrayMap<>(attributedOps.size());
             for (int i = 0; i < attributedOps.size(); i++) {
@@ -680,8 +684,12 @@
         @NonNull OpEntry createSingleAttributionEntryLocked(@Nullable String attributionTag) {
             // TODO(b/308201969): Update this method when we introduce disk persistence of events
             // for accesses on external devices.
-            final ArrayMap<String, AttributedOp> attributedOps = mDeviceAttributedOps.get(
+            ArrayMap<String, AttributedOp> attributedOps = mDeviceAttributedOps.get(
                     PERSISTENT_DEVICE_ID_DEFAULT);
+            if (attributedOps == null) {
+                attributedOps = new ArrayMap<>();
+            }
+
             final ArrayMap<String, AttributedOpEntry> attributionEntries = new ArrayMap<>(1);
             if (attributedOps.get(attributionTag) != null) {
                 attributionEntries.put(attributionTag,
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 082776a..fb4976d 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -16,6 +16,7 @@
 
 package com.android.server.display;
 
+import static com.android.server.display.BrightnessMappingStrategy.INVALID_LUX;
 import static com.android.server.display.config.DisplayBrightnessMappingConfig.autoBrightnessModeToString;
 
 import android.annotation.IntDef;
@@ -202,7 +203,7 @@
     private float mScreenBrighteningThreshold;
     private float mScreenDarkeningThreshold;
     // The most recent light sample.
-    private float mLastObservedLux;
+    private float mLastObservedLux = INVALID_LUX;
 
     // The time of the most light recent sample.
     private long mLastObservedLuxTime;
@@ -403,8 +404,8 @@
             brightnessEvent.setFlags(brightnessEvent.getFlags()
                     | (!mAmbientLuxValid ? BrightnessEvent.FLAG_INVALID_LUX : 0)
                     | (mDisplayPolicy == DisplayPowerRequest.POLICY_DOZE
-                        ? BrightnessEvent.FLAG_DOZE_SCALE : 0)
-                    | (isInIdleMode() ? BrightnessEvent.FLAG_IDLE_CURVE : 0));
+                        ? BrightnessEvent.FLAG_DOZE_SCALE : 0));
+            brightnessEvent.setAutoBrightnessMode(getMode());
         }
 
         if (!mAmbientLuxValid) {
@@ -420,6 +421,35 @@
         return mRawScreenAutoBrightness;
     }
 
+    /**
+     * Get the automatic screen brightness based on the last observed lux reading. Used e.g. when
+     * entering doze - we disable the light sensor, invalidate the lux, but we still need to set
+     * the initial brightness in doze mode.
+     */
+    public float getAutomaticScreenBrightnessBasedOnLastObservedLux(
+            BrightnessEvent brightnessEvent) {
+        if (mLastObservedLux == INVALID_LUX) {
+            return PowerManager.BRIGHTNESS_INVALID_FLOAT;
+        }
+
+        float brightness = mCurrentBrightnessMapper.getBrightness(mLastObservedLux,
+                mForegroundAppPackageName, mForegroundAppCategory);
+        if (mDisplayPolicy == DisplayPowerRequest.POLICY_DOZE) {
+            brightness *= mDozeScaleFactor;
+        }
+
+        if (brightnessEvent != null) {
+            brightnessEvent.setLux(mLastObservedLux);
+            brightnessEvent.setRecommendedBrightness(brightness);
+            brightnessEvent.setFlags(brightnessEvent.getFlags()
+                    | (mLastObservedLux == INVALID_LUX ? BrightnessEvent.FLAG_INVALID_LUX : 0)
+                    | (mDisplayPolicy == DisplayPowerRequest.POLICY_DOZE
+                    ? BrightnessEvent.FLAG_DOZE_SCALE : 0));
+            brightnessEvent.setAutoBrightnessMode(getMode());
+        }
+        return brightness;
+    }
+
     public boolean hasValidAmbientLux() {
         return mAmbientLuxValid;
     }
@@ -539,7 +569,7 @@
     }
 
     private boolean setScreenBrightnessByUser(float lux, float brightness) {
-        if (lux == BrightnessMappingStrategy.INVALID_LUX || Float.isNaN(brightness)) {
+        if (lux == INVALID_LUX || Float.isNaN(brightness)) {
             return false;
         }
         mCurrentBrightnessMapper.addUserDataPoint(lux, brightness);
@@ -564,6 +594,15 @@
         return false;
     }
 
+    /**
+     * @return The auto-brightness mode of the current mapping strategy. Different modes use
+     * different brightness curves.
+     */
+    @AutomaticBrightnessController.AutomaticBrightnessMode
+    public int getMode() {
+        return mCurrentBrightnessMapper.getMode();
+    }
+
     public boolean isInIdleMode() {
         return mCurrentBrightnessMapper.getMode() == AUTO_BRIGHTNESS_MODE_IDLE;
     }
@@ -1236,12 +1275,12 @@
         // light.
         // The anchor determines what were the light levels when the user has set their preference,
         // and we use a relative threshold to determine when to revert to the OEM curve.
-        private float mAnchor = BrightnessMappingStrategy.INVALID_LUX;
+        private float mAnchor = INVALID_LUX;
         private float mBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
         private boolean mIsValid = false;
 
         private void reset() {
-            mAnchor = BrightnessMappingStrategy.INVALID_LUX;
+            mAnchor = INVALID_LUX;
             mBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
             mIsValid = false;
         }
@@ -1265,7 +1304,7 @@
         private boolean maybeReset(float currentLux) {
             // If the short term model was invalidated and the change is drastic enough, reset it.
             // Otherwise, we revalidate it.
-            if (!mIsValid && mAnchor != BrightnessMappingStrategy.INVALID_LUX) {
+            if (!mIsValid && mAnchor != INVALID_LUX) {
                 if (mCurrentBrightnessMapper.shouldResetShortTermModel(currentLux, mAnchor)) {
                     resetShortTermModel();
                 } else {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 3965d55..dbe85ea 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -16,6 +16,8 @@
 
 package com.android.server.display;
 
+import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE;
+
 import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT;
 import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DOZE;
 import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_IDLE;
@@ -37,7 +39,6 @@
 import android.hardware.display.BrightnessChangeEvent;
 import android.hardware.display.BrightnessConfiguration;
 import android.hardware.display.BrightnessInfo;
-import android.hardware.display.DisplayManagerInternal;
 import android.hardware.display.DisplayManagerInternal.DisplayOffloadSession;
 import android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks;
 import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
@@ -1378,7 +1379,7 @@
         // Switch to doze auto-brightness mode if needed
         if (mFlags.areAutoBrightnessModesEnabled() && mAutomaticBrightnessController != null
                 && !mAutomaticBrightnessController.isInIdleMode()) {
-            setAutomaticScreenBrightnessMode(Display.isDozeState(state)
+            mAutomaticBrightnessController.switchMode(mPowerRequest.policy == POLICY_DOZE
                     ? AUTO_BRIGHTNESS_MODE_DOZE : AUTO_BRIGHTNESS_MODE_DEFAULT);
         }
 
@@ -1466,6 +1467,22 @@
             mAutomaticBrightnessStrategy.setAutoBrightnessApplied(false);
         }
 
+        // If there's an offload session and auto-brightness is on, we need to set the initial doze
+        // brightness using the doze auto-brightness curve before the offload session starts
+        // controlling the brightness.
+        if (Float.isNaN(brightnessState) && mFlags.areAutoBrightnessModesEnabled()
+                && mFlags.isDisplayOffloadEnabled()
+                && mPowerRequest.policy == POLICY_DOZE
+                && mDisplayOffloadSession != null
+                && mAutomaticBrightnessStrategy.shouldUseAutoBrightness()) {
+            rawBrightnessState = mAutomaticBrightnessController
+                    .getAutomaticScreenBrightnessBasedOnLastObservedLux(mTempBrightnessEvent);
+            if (BrightnessUtils.isValidBrightnessValue(rawBrightnessState)) {
+                brightnessState = clampScreenBrightness(rawBrightnessState);
+                mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE_INITIAL);
+            }
+        }
+
         // Use default brightness when dozing unless overridden.
         if ((Float.isNaN(brightnessState))
                 && Display.isDozeState(state)) {
@@ -1618,7 +1635,7 @@
 
             // if doze or suspend state is requested, we want to finish brightnes animation fast
             // to allow state animation to start
-            if (mPowerRequest.policy == DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE
+            if (mPowerRequest.policy == POLICY_DOZE
                     && (mPowerRequest.dozeScreenState == Display.STATE_UNKNOWN  // dozing
                     || mPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND
                     || mPowerRequest.dozeScreenState == Display.STATE_ON_SUSPEND)) {
@@ -1706,6 +1723,7 @@
         mTempBrightnessEvent.setTime(System.currentTimeMillis());
         mTempBrightnessEvent.setBrightness(brightnessState);
         mTempBrightnessEvent.setPhysicalDisplayId(mUniqueDisplayId);
+        mTempBrightnessEvent.setDisplayState(state);
         mTempBrightnessEvent.setReason(mBrightnessReason);
         mTempBrightnessEvent.setHbmMax(mBrightnessRangeController.getCurrentBrightnessMax());
         mTempBrightnessEvent.setHbmMode(mBrightnessRangeController.getHighBrightnessMode());
@@ -2879,7 +2897,7 @@
                     (flags & BrightnessEvent.FLAG_INVALID_LUX) > 0,
                     (flags & BrightnessEvent.FLAG_DOZE_SCALE) > 0,
                     (flags & BrightnessEvent.FLAG_USER_SET) > 0,
-                    (flags & BrightnessEvent.FLAG_IDLE_CURVE) > 0,
+                    event.getAutoBrightnessMode() == AUTO_BRIGHTNESS_MODE_IDLE,
                     (flags & BrightnessEvent.FLAG_LOW_POWER_MODE) > 0);
         }
     }
diff --git a/services/core/java/com/android/server/display/brightness/BrightnessEvent.java b/services/core/java/com/android/server/display/brightness/BrightnessEvent.java
index d4d1bae..5423b74 100644
--- a/services/core/java/com/android/server/display/brightness/BrightnessEvent.java
+++ b/services/core/java/com/android/server/display/brightness/BrightnessEvent.java
@@ -16,11 +16,16 @@
 
 package com.android.server.display.brightness;
 
+import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT;
+import static com.android.server.display.config.DisplayBrightnessMappingConfig.autoBrightnessModeToString;
+
 import android.hardware.display.BrightnessInfo;
 import android.os.PowerManager;
 import android.os.SystemClock;
+import android.view.Display;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.display.AutomaticBrightnessController;
 
 import java.text.SimpleDateFormat;
 import java.util.Date;
@@ -33,7 +38,6 @@
     public static final int FLAG_INVALID_LUX = 0x2;
     public static final int FLAG_DOZE_SCALE = 0x4;
     public static final int FLAG_USER_SET = 0x8;
-    public static final int FLAG_IDLE_CURVE = 0x10;
     public static final int FLAG_LOW_POWER_MODE = 0x20;
 
     private static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
@@ -41,6 +45,7 @@
     private BrightnessReason mReason = new BrightnessReason();
     private int mDisplayId;
     private String mPhysicalDisplayId;
+    private int mDisplayState;
     private long mTime;
     private float mLux;
     private float mPreThresholdLux;
@@ -58,6 +63,8 @@
     private int mAdjustmentFlags;
     private boolean mAutomaticBrightnessEnabled;
     private String mDisplayBrightnessStrategyName;
+    @AutomaticBrightnessController.AutomaticBrightnessMode
+    private int mAutoBrightnessMode;
 
     public BrightnessEvent(BrightnessEvent that) {
         copyFrom(that);
@@ -77,6 +84,7 @@
         mReason.set(that.getReason());
         mDisplayId = that.getDisplayId();
         mPhysicalDisplayId = that.getPhysicalDisplayId();
+        mDisplayState = that.mDisplayState;
         mTime = that.getTime();
         // Lux values
         mLux = that.getLux();
@@ -98,6 +106,7 @@
         // Auto-brightness setting
         mAutomaticBrightnessEnabled = that.isAutomaticBrightnessEnabled();
         mDisplayBrightnessStrategyName = that.getDisplayBrightnessStrategyName();
+        mAutoBrightnessMode = that.mAutoBrightnessMode;
     }
 
     /**
@@ -107,6 +116,7 @@
         mReason = new BrightnessReason();
         mTime = SystemClock.uptimeMillis();
         mPhysicalDisplayId = "";
+        mDisplayState = Display.STATE_UNKNOWN;
         // Lux values
         mLux = 0;
         mPreThresholdLux = 0;
@@ -127,6 +137,7 @@
         // Auto-brightness setting
         mAutomaticBrightnessEnabled = true;
         mDisplayBrightnessStrategyName = "";
+        mAutoBrightnessMode = AUTO_BRIGHTNESS_MODE_DEFAULT;
     }
 
     /**
@@ -143,6 +154,7 @@
         return mReason.equals(that.mReason)
                 && mDisplayId == that.mDisplayId
                 && mPhysicalDisplayId.equals(that.mPhysicalDisplayId)
+                && mDisplayState == that.mDisplayState
                 && Float.floatToRawIntBits(mLux) == Float.floatToRawIntBits(that.mLux)
                 && Float.floatToRawIntBits(mPreThresholdLux)
                 == Float.floatToRawIntBits(that.mPreThresholdLux)
@@ -163,7 +175,8 @@
                 && mFlags == that.mFlags
                 && mAdjustmentFlags == that.mAdjustmentFlags
                 && mAutomaticBrightnessEnabled == that.mAutomaticBrightnessEnabled
-                && mDisplayBrightnessStrategyName.equals(that.mDisplayBrightnessStrategyName);
+                && mDisplayBrightnessStrategyName.equals(that.mDisplayBrightnessStrategyName)
+                && mAutoBrightnessMode == that.mAutoBrightnessMode;
     }
 
     /**
@@ -177,6 +190,7 @@
                 + "BrightnessEvent: "
                 + "disp=" + mDisplayId
                 + ", physDisp=" + mPhysicalDisplayId
+                + ", displayState=" + Display.stateToString(mDisplayState)
                 + ", brt=" + mBrightness + ((mFlags & FLAG_USER_SET) != 0 ? "(user_set)" : "")
                 + ", initBrt=" + mInitialBrightness
                 + ", rcmdBrt=" + mRecommendedBrightness
@@ -192,7 +206,8 @@
                 + ", flags=" + flagsToString()
                 + ", reason=" + mReason.toString(mAdjustmentFlags)
                 + ", autoBrightness=" + mAutomaticBrightnessEnabled
-                + ", strategy=" + mDisplayBrightnessStrategyName;
+                + ", strategy=" + mDisplayBrightnessStrategyName
+                + ", autoBrightnessMode=" + autoBrightnessModeToString(mAutoBrightnessMode);
     }
 
     @Override
@@ -232,6 +247,10 @@
         this.mPhysicalDisplayId = mPhysicalDisplayId;
     }
 
+    public void setDisplayState(int state) {
+        mDisplayState = state;
+    }
+
     public float getLux() {
         return mLux;
     }
@@ -374,6 +393,16 @@
         this.mAutomaticBrightnessEnabled = mAutomaticBrightnessEnabled;
     }
 
+    @AutomaticBrightnessController.AutomaticBrightnessMode
+    public int getAutoBrightnessMode() {
+        return mAutoBrightnessMode;
+    }
+
+    public void setAutoBrightnessMode(
+            @AutomaticBrightnessController.AutomaticBrightnessMode int mode) {
+        mAutoBrightnessMode = mode;
+    }
+
     /**
      * A utility to stringify flags from a BrightnessEvent
      * @return Stringified flags from BrightnessEvent
@@ -384,7 +413,6 @@
                 + ((mFlags & FLAG_RBC) != 0 ? "rbc " : "")
                 + ((mFlags & FLAG_INVALID_LUX) != 0 ? "invalid_lux " : "")
                 + ((mFlags & FLAG_DOZE_SCALE) != 0 ? "doze_scale " : "")
-                + ((mFlags & FLAG_IDLE_CURVE) != 0 ? "idle_curve " : "")
                 + ((mFlags & FLAG_LOW_POWER_MODE) != 0 ? "low_power_mode " : "");
     }
 }
diff --git a/services/core/java/com/android/server/display/brightness/BrightnessReason.java b/services/core/java/com/android/server/display/brightness/BrightnessReason.java
index bc443a8..fc95d15 100644
--- a/services/core/java/com/android/server/display/brightness/BrightnessReason.java
+++ b/services/core/java/com/android/server/display/brightness/BrightnessReason.java
@@ -40,7 +40,8 @@
     public static final int REASON_SCREEN_OFF_BRIGHTNESS_SENSOR = 9;
     public static final int REASON_FOLLOWER = 10;
     public static final int REASON_OFFLOAD = 11;
-    public static final int REASON_MAX = REASON_OFFLOAD;
+    public static final int REASON_DOZE_INITIAL = 12;
+    public static final int REASON_MAX = REASON_DOZE_INITIAL;
 
     public static final int MODIFIER_DIMMED = 0x1;
     public static final int MODIFIER_LOW_POWER = 0x2;
@@ -207,6 +208,8 @@
                 return "follower";
             case REASON_OFFLOAD:
                 return "offload";
+            case REASON_DOZE_INITIAL:
+                return "doze_initial";
             default:
                 return Integer.toString(reason);
         }
diff --git a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
index 3e6e09d..8eaecef 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
@@ -267,6 +267,23 @@
     }
 
     /**
+     * Get the automatic screen brightness based on the last observed lux reading. Used e.g. when
+     * entering doze - we disable the light sensor, invalidate the lux, but we still need to set
+     * the initial brightness in doze mode.
+     * @param brightnessEvent Event object to populate with details about why the specific
+     *                        brightness was chosen.
+     */
+    public float getAutomaticScreenBrightnessBasedOnLastObservedLux(
+            BrightnessEvent brightnessEvent) {
+        float brightness = (mAutomaticBrightnessController != null)
+                ? mAutomaticBrightnessController
+                .getAutomaticScreenBrightnessBasedOnLastObservedLux(brightnessEvent)
+                : PowerManager.BRIGHTNESS_INVALID_FLOAT;
+        adjustAutomaticBrightnessStateIfValid(brightness);
+        return brightness;
+    }
+
+    /**
      * Gets the auto-brightness adjustment flag change reason
      */
     public int getAutoBrightnessAdjustmentReasonsFlags() {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index 70993ca..1e90ab2 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -317,6 +317,10 @@
         if ((systemAudioOnPowerOnProp == ALWAYS_SYSTEM_AUDIO_CONTROL_ON_POWER_ON)
                 || ((systemAudioOnPowerOnProp == USE_LAST_STATE_SYSTEM_AUDIO_CONTROL_ON_POWER_ON)
                 && lastSystemAudioControlStatus && isSystemAudioControlFeatureEnabled())) {
+            if (hasAction(SystemAudioInitiationActionFromAvr.class)) {
+                Slog.i(TAG, "SystemAudioInitiationActionFromAvr is in progress. Restarting.");
+                removeAction(SystemAudioInitiationActionFromAvr.class);
+            }
             addAndStartAction(new SystemAudioInitiationActionFromAvr(this));
         }
     }
@@ -1032,6 +1036,10 @@
     void onSystemAudioControlFeatureSupportChanged(boolean enabled) {
         setSystemAudioControlFeatureEnabled(enabled);
         if (enabled) {
+            if (hasAction(SystemAudioInitiationActionFromAvr.class)) {
+                Slog.i(TAG, "SystemAudioInitiationActionFromAvr is in progress. Restarting.");
+                removeAction(SystemAudioInitiationActionFromAvr.class);
+            }
             addAndStartAction(new SystemAudioInitiationActionFromAvr(this));
         }
     }
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 7b18fb6..a79e771 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -38,7 +38,6 @@
 import android.hardware.SensorPrivacyManager;
 import android.hardware.SensorPrivacyManager.Sensors;
 import android.hardware.SensorPrivacyManagerInternal;
-import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManagerInternal;
 import android.hardware.display.DisplayViewport;
 import android.hardware.input.HostUsiVersion;
@@ -322,6 +321,9 @@
     // Manages Keyboard modifier keys remapping
     private final KeyRemapper mKeyRemapper;
 
+    // Manages loading PointerIcons
+    private final PointerIconCache mPointerIconCache;
+
     // Maximum number of milliseconds to wait for input event injection.
     private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;
 
@@ -408,44 +410,6 @@
     private boolean mShowKeyPresses = false;
     private boolean mShowRotaryInput = false;
 
-    @GuardedBy("mLoadedPointerIconsByDisplayAndType")
-    final SparseArray<SparseArray<PointerIcon>> mLoadedPointerIconsByDisplayAndType =
-            new SparseArray<>();
-    @GuardedBy("mLoadedPointerIconsByDisplayAndType")
-    boolean mUseLargePointerIcons = false;
-    @GuardedBy("mLoadedPointerIconsByDisplayAndType")
-    final SparseArray<Context> mDisplayContexts = new SparseArray<>();
-
-    final DisplayManager.DisplayListener mDisplayListener = new DisplayManager.DisplayListener() {
-        @Override
-        public void onDisplayAdded(int displayId) {
-
-        }
-
-        @Override
-        public void onDisplayRemoved(int displayId) {
-            synchronized (mLoadedPointerIconsByDisplayAndType) {
-                mLoadedPointerIconsByDisplayAndType.remove(displayId);
-                mDisplayContexts.remove(displayId);
-            }
-        }
-
-        @Override
-        public void onDisplayChanged(int displayId) {
-            synchronized (mLoadedPointerIconsByDisplayAndType) {
-                // The display density could have changed, so force all cached pointer icons to be
-                // reloaded for the display.
-                var iconsByType = mLoadedPointerIconsByDisplayAndType.get(displayId);
-                if (iconsByType == null) {
-                    return;
-                }
-                iconsByType.clear();
-                mDisplayContexts.remove(displayId);
-            }
-            mNative.reloadPointerIcons();
-        }
-    };
-
     /** Point of injection for test dependencies. */
     @VisibleForTesting
     static class Injector {
@@ -504,6 +468,7 @@
                 : new KeyboardBacklightControllerInterface() {};
         mStickyModifierStateController = new StickyModifierStateController();
         mKeyRemapper = new KeyRemapper(mContext, mNative, mDataStore, injector.getLooper());
+        mPointerIconCache = new PointerIconCache(mContext, mNative);
 
         mUseDevInputEventForAudioJack =
                 mContext.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
@@ -613,14 +578,11 @@
             mWiredAccessoryCallbacks.systemReady();
         }
 
-        Objects.requireNonNull(
-                mContext.getSystemService(DisplayManager.class)).registerDisplayListener(
-                mDisplayListener, mHandler);
-
         mKeyboardLayoutManager.systemRunning();
         mBatteryController.systemRunning();
         mKeyboardBacklightController.systemRunning();
         mKeyRemapper.systemRunning();
+        mPointerIconCache.systemRunning();
     }
 
     private void reloadDeviceAliases() {
@@ -2374,8 +2336,8 @@
         synchronized (mLidSwitchLock) { /* Test if blocked by lid switch lock. */ }
         synchronized (mInputMonitors) { /* Test if blocked by input monitor lock. */ }
         synchronized (mAdditionalDisplayInputPropertiesLock) { /* Test if blocked by props lock */ }
-        synchronized (mLoadedPointerIconsByDisplayAndType) { /* Test if blocked by pointer lock */}
         mBatteryController.monitor();
+        mPointerIconCache.monitor();
         mNative.monitor();
     }
 
@@ -2769,21 +2731,7 @@
     // Native callback.
     @SuppressWarnings("unused")
     private @NonNull PointerIcon getLoadedPointerIcon(int displayId, int type) {
-        synchronized (mLoadedPointerIconsByDisplayAndType) {
-            SparseArray<PointerIcon> iconsByType = mLoadedPointerIconsByDisplayAndType.get(
-                    displayId);
-            if (iconsByType == null) {
-                iconsByType = new SparseArray<>();
-                mLoadedPointerIconsByDisplayAndType.put(displayId, iconsByType);
-            }
-            PointerIcon icon = iconsByType.get(type);
-            if (icon == null) {
-                icon = PointerIcon.getLoadedSystemIcon(getContextForDisplay(displayId), type,
-                        mUseLargePointerIcons);
-                iconsByType.put(type, icon);
-            }
-            return Objects.requireNonNull(icon);
-        }
+        return mPointerIconCache.getLoadedPointerIcon(displayId, type);
     }
 
     // Native callback.
@@ -2796,33 +2744,6 @@
         return sc.mNativeObject;
     }
 
-    @GuardedBy("mLoadedPointerIconsByDisplayAndType")
-    @NonNull
-    private Context getContextForDisplay(int displayId) {
-        if (displayId == Display.INVALID_DISPLAY) {
-            // Fallback to using the default context.
-            return mContext;
-        }
-        if (displayId == mContext.getDisplay().getDisplayId()) {
-            return mContext;
-        }
-
-        Context displayContext = mDisplayContexts.get(displayId);
-        if (displayContext == null) {
-            final DisplayManager displayManager = Objects.requireNonNull(
-                    mContext.getSystemService(DisplayManager.class));
-            final Display display = displayManager.getDisplay(displayId);
-            if (display == null) {
-                // Fallback to using the default context.
-                return mContext;
-            }
-
-            displayContext = mContext.createDisplayContext(display);
-            mDisplayContexts.put(displayId, displayContext);
-        }
-        return displayContext;
-    }
-
     // Native callback.
     @SuppressWarnings("unused")
     private String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier, String languageTag,
@@ -3628,15 +3549,7 @@
     }
 
     void setUseLargePointerIcons(boolean useLargeIcons) {
-        synchronized (mLoadedPointerIconsByDisplayAndType) {
-            if (mUseLargePointerIcons == useLargeIcons) {
-                return;
-            }
-            mUseLargePointerIcons = useLargeIcons;
-            // Clear all cached icons on all displays.
-            mLoadedPointerIconsByDisplayAndType.clear();
-        }
-        mNative.reloadPointerIcons();
+        mPointerIconCache.setUseLargePointerIcons(useLargeIcons);
     }
 
     interface KeyboardBacklightControllerInterface {
diff --git a/services/core/java/com/android/server/input/PointerIconCache.java b/services/core/java/com/android/server/input/PointerIconCache.java
new file mode 100644
index 0000000..233b865
--- /dev/null
+++ b/services/core/java/com/android/server/input/PointerIconCache.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2024 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.server.input;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.display.DisplayManager;
+import android.os.Handler;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+import android.view.Display;
+import android.view.DisplayInfo;
+import android.view.PointerIcon;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.UiThread;
+
+import java.util.Objects;
+
+/**
+ * A thread-safe component of {@link InputManagerService} responsible for caching loaded
+ * {@link PointerIcon}s and triggering reloading of the icons.
+ */
+final class PointerIconCache {
+    private static final String TAG = PointerIconCache.class.getSimpleName();
+
+    private final Context mContext;
+
+    // Do not hold the lock when calling into native code.
+    private final NativeInputManagerService mNative;
+
+    // We use the UI thread for loading pointer icons.
+    private final Handler mUiThreadHandler = UiThread.getHandler();
+
+    @GuardedBy("mLoadedPointerIconsByDisplayAndType")
+    private final SparseArray<SparseArray<PointerIcon>> mLoadedPointerIconsByDisplayAndType =
+            new SparseArray<>();
+    @GuardedBy("mLoadedPointerIconsByDisplayAndType")
+    private boolean mUseLargePointerIcons = false;
+    @GuardedBy("mLoadedPointerIconsByDisplayAndType")
+    private final SparseArray<Context> mDisplayContexts = new SparseArray<>();
+    @GuardedBy("mLoadedPointerIconsByDisplayAndType")
+    private final SparseIntArray mDisplayDensities = new SparseIntArray();
+
+    private final DisplayManager.DisplayListener mDisplayListener =
+            new DisplayManager.DisplayListener() {
+                @Override
+                public void onDisplayAdded(int displayId) {
+                    synchronized (mLoadedPointerIconsByDisplayAndType) {
+                        updateDisplayDensityLocked(displayId);
+                    }
+                }
+
+                @Override
+                public void onDisplayRemoved(int displayId) {
+                    synchronized (mLoadedPointerIconsByDisplayAndType) {
+                        mLoadedPointerIconsByDisplayAndType.remove(displayId);
+                        mDisplayContexts.remove(displayId);
+                        mDisplayDensities.delete(displayId);
+                    }
+                }
+
+                @Override
+                public void onDisplayChanged(int displayId) {
+                    handleDisplayChanged(displayId);
+                }
+            };
+
+    /* package */ PointerIconCache(Context context, NativeInputManagerService nativeService) {
+        mContext = context;
+        mNative = nativeService;
+    }
+
+    public void systemRunning() {
+        final DisplayManager displayManager = Objects.requireNonNull(
+                mContext.getSystemService(DisplayManager.class));
+        displayManager.registerDisplayListener(mDisplayListener, mUiThreadHandler);
+        final Display[] displays = displayManager.getDisplays();
+        for (int i = 0; i < displays.length; i++) {
+            mDisplayListener.onDisplayAdded(displays[i].getDisplayId());
+        }
+    }
+
+    public void monitor() {
+        synchronized (mLoadedPointerIconsByDisplayAndType) { /* Test if blocked by lock */}
+    }
+
+    /** Set whether the large pointer icons should be used for accessibility. */
+    public void setUseLargePointerIcons(boolean useLargeIcons) {
+        mUiThreadHandler.post(() -> handleSetUseLargePointerIcons(useLargeIcons));
+    }
+
+    /**
+     * Get a loaded system pointer icon. This will fetch the icon from the cache, or load it if
+     * it isn't already cached.
+     */
+    public @NonNull PointerIcon getLoadedPointerIcon(int displayId, int type) {
+        synchronized (mLoadedPointerIconsByDisplayAndType) {
+            SparseArray<PointerIcon> iconsByType = mLoadedPointerIconsByDisplayAndType.get(
+                    displayId);
+            if (iconsByType == null) {
+                iconsByType = new SparseArray<>();
+                mLoadedPointerIconsByDisplayAndType.put(displayId, iconsByType);
+            }
+            PointerIcon icon = iconsByType.get(type);
+            if (icon == null) {
+                icon = PointerIcon.getLoadedSystemIcon(getContextForDisplayLocked(displayId), type,
+                        mUseLargePointerIcons);
+                iconsByType.put(type, icon);
+            }
+            return Objects.requireNonNull(icon);
+        }
+    }
+
+    @GuardedBy("mLoadedPointerIconsByDisplayAndType")
+    private @NonNull Context getContextForDisplayLocked(int displayId) {
+        if (displayId == Display.INVALID_DISPLAY) {
+            // Fallback to using the default context.
+            return mContext;
+        }
+        if (displayId == mContext.getDisplay().getDisplayId()) {
+            return mContext;
+        }
+
+        Context displayContext = mDisplayContexts.get(displayId);
+        if (displayContext == null) {
+            final DisplayManager displayManager = Objects.requireNonNull(
+                    mContext.getSystemService(DisplayManager.class));
+            final Display display = displayManager.getDisplay(displayId);
+            if (display == null) {
+                // Fallback to using the default context.
+                return mContext;
+            }
+
+            displayContext = mContext.createDisplayContext(display);
+            mDisplayContexts.put(displayId, displayContext);
+        }
+        return displayContext;
+    }
+
+    @android.annotation.UiThread
+    private void handleDisplayChanged(int displayId) {
+        synchronized (mLoadedPointerIconsByDisplayAndType) {
+            if (!updateDisplayDensityLocked(displayId)) {
+                return;
+            }
+            // The display density changed, so force all cached pointer icons to be
+            // reloaded for the display.
+            Slog.i(TAG, "Reloading pointer icons due to density change on display: " + displayId);
+            var iconsByType = mLoadedPointerIconsByDisplayAndType.get(displayId);
+            if (iconsByType == null) {
+                return;
+            }
+            iconsByType.clear();
+            mDisplayContexts.remove(displayId);
+        }
+        mNative.reloadPointerIcons();
+    }
+
+    @android.annotation.UiThread
+    private void handleSetUseLargePointerIcons(boolean useLargeIcons) {
+        synchronized (mLoadedPointerIconsByDisplayAndType) {
+            if (mUseLargePointerIcons == useLargeIcons) {
+                return;
+            }
+            mUseLargePointerIcons = useLargeIcons;
+            // Clear all cached icons on all displays.
+            mLoadedPointerIconsByDisplayAndType.clear();
+        }
+        mNative.reloadPointerIcons();
+    }
+
+    // Updates the cached display density for the given displayId, and returns true if
+    // the cached density changed.
+    @GuardedBy("mLoadedPointerIconsByDisplayAndType")
+    private boolean updateDisplayDensityLocked(int displayId) {
+        final DisplayManager displayManager = Objects.requireNonNull(
+                mContext.getSystemService(DisplayManager.class));
+        final Display display = displayManager.getDisplay(displayId);
+        if (display == null) {
+            return false;
+        }
+        DisplayInfo info = new DisplayInfo();
+        display.getDisplayInfo(info);
+        final int oldDensity = mDisplayDensities.get(displayId, 0 /* default */);
+        if (oldDensity == info.logicalDensityDpi) {
+            return false;
+        }
+        mDisplayDensities.put(displayId, info.logicalDensityDpi);
+        return true;
+    }
+}
diff --git a/services/core/java/com/android/server/inputmethod/ClientController.java b/services/core/java/com/android/server/inputmethod/ClientController.java
index 86f4db9..0381a31 100644
--- a/services/core/java/com/android/server/inputmethod/ClientController.java
+++ b/services/core/java/com/android/server/inputmethod/ClientController.java
@@ -33,36 +33,10 @@
 import java.util.function.Consumer;
 
 /**
- * Store and manage {@link InputMethodManagerService} clients. This class was designed to be a
- * singleton in {@link InputMethodManagerService} since it stores information about all clients,
- * still the current client will be defined per display.
- *
- * <p>
- * As part of the re-architecture plan (described in go/imms-rearchitecture-plan), the following
- * fields and methods will be moved out from IMMS and placed here:
- * <ul>
- * <li>mClients (ArrayMap of ClientState indexed by IBinder)</li>
- * </ul>
- * <p>
- * Nested Classes (to move from IMMS):
- * <ul>
- * <li>ClientDeathRecipient</li>
- * <li>ClientState<</li>
- * </ul>
- * <p>
- * Methods to rewrite and/or extract from IMMS and move here:
- * <ul>
- * <li>addClient</li>
- * <li>removeClient</li>
- * <li>verifyClientAndPackageMatch</li>
- * <li>setImeTraceEnabledForAllClients (make it reactive)</li>
- * </ul>
+ * Store and manage {@link InputMethodManagerService} clients.
  */
-// TODO(b/314150112): Update the Javadoc above, by removing the re-architecture steps, once this
-//  class is finalized
 final class ClientController {
 
-    // TODO(b/314150112): Make this field private when breaking the cycle with IMMS.
     @GuardedBy("ImfLock.class")
     private final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
 
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 76956c88..307b70a 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2193,7 +2193,7 @@
         }
     }
 
-    // TODO(b/314150112): Move this method to InputMethodBindingController
+    // TODO(b/325515685): Move this method to InputMethodBindingController
     /**
      * Hide the IME if the removed user is the current user.
      */
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 75be068..a608049 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -463,11 +463,13 @@
                     com.android.internal.R.bool.config_useGnssHardwareProvider);
             AbstractLocationProvider gnssProvider = null;
             if (!useGnssHardwareProvider) {
+                // TODO: Create a separate config_enableGnssLocationOverlay config resource
+                // if we want to selectively enable a GNSS overlay but disable a fused overlay.
                 gnssProvider = ProxyLocationProvider.create(
                         mContext,
                         GPS_PROVIDER,
                         ACTION_GNSS_PROVIDER,
-                        com.android.internal.R.bool.config_useGnssHardwareProvider,
+                        com.android.internal.R.bool.config_enableFusedLocationOverlay,
                         com.android.internal.R.string.config_gnssLocationProviderPackageName);
             }
             if (gnssProvider == null) {
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index ecb4fcc..40e538b 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -1618,6 +1618,17 @@
      */
     @SuppressLint("AndroidFrameworkRequiresPermission")
     public boolean isVisibleToCaller() {
+        // Anything sharing the system's UID can view all providers
+        if (Binder.getCallingUid() == Process.SYSTEM_UID) {
+            return true;
+        }
+
+        // If an app mocked this provider, anybody can access it (the goal is
+        // to behave as if this provider didn't naturally exist).
+        if (mProvider.isMock()) {
+            return true;
+        }
+
         for (String permission : mRequiredPermissions) {
             if (mContext.checkCallingOrSelfPermission(permission) != PERMISSION_GRANTED) {
                 return false;
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index b5c51af..31bfc695 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -727,7 +727,7 @@
      * Map of uid -> UidStateCallbackInfo objects holding the data received from
      * {@link IUidObserver#onUidStateChanged(int, int, long, int)} callbacks. In order to avoid
      * creating a new object for every callback received, we hold onto the object created for each
-     * uid and reuse it.
+     * uid and reuse it until the uid stays alive.
      *
      * Note that the lock used for accessing this object should not be used for anything else and we
      * should not be acquiring new locks or doing any heavy work while this lock is held since this
@@ -800,6 +800,13 @@
                 Clock.systemUTC());
     }
 
+    @VisibleForTesting
+    UidState getUidStateForTest(int uid) {
+        synchronized (mUidRulesFirstLock) {
+            return mUidState.get(uid);
+        }
+    }
+
     static class Dependencies {
         final Context mContext;
         final NetworkStatsManager mNetworkStatsManager;
@@ -1254,6 +1261,10 @@
         }
 
         @Override public void onUidGone(int uid, boolean disabled) {
+            synchronized (mUidStateCallbackInfos) {
+                mUidStateCallbackInfos.remove(uid);
+            }
+            // TODO: b/327058756 - Remove any pending UID_MSG_STATE_CHANGED on the handler.
             mUidEventHandler.obtainMessage(UID_MSG_GONE, uid, 0).sendToTarget();
         }
     };
@@ -5915,7 +5926,7 @@
     void handleUidGone(int uid) {
         Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "onUidGone");
         try {
-            boolean updated;
+            final boolean updated;
             synchronized (mUidRulesFirstLock) {
                 updated = removeUidStateUL(uid);
             }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index fc7b873..3a7ac0b 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -8206,7 +8206,7 @@
                 try {
                     return mTelecomManager.isInManagedCall()
                             || mTelecomManager.isInSelfManagedCall(pkg,
-                            UserHandle.getUserHandleForUid(uid), /* hasCrossUserAccess */ true);
+                            /* hasCrossUserAccess */ true);
                 } catch (IllegalStateException ise) {
                     // Telecom is not ready (this is likely early boot), so there are no calls.
                     return false;
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index eed0eec..6857869 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -1285,8 +1285,8 @@
      */
     private static void updateZenDeviceEffects(ZenRule zenRule,
             @Nullable ZenDeviceEffects newEffects, boolean isFromApp, boolean updateBitmask) {
+        // Same as with ZenPolicy, supplying null effects means keeping the previous ones.
         if (newEffects == null) {
-            zenRule.zenDeviceEffects = null;
             return;
         }
 
diff --git a/services/core/java/com/android/server/pdb/PersistentDataBlockService.java b/services/core/java/com/android/server/pdb/PersistentDataBlockService.java
index 5ad5507..5ebcca8 100644
--- a/services/core/java/com/android/server/pdb/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/pdb/PersistentDataBlockService.java
@@ -626,7 +626,7 @@
             // version.  If so, we deactivate FRP and set the secret to the default value.
             if (isUpgradingFromPreVRelease()) {
                 Slog.w(TAG, "Upgrading from Android 14 or lower, defaulting FRP secret");
-                writeFrpMagicAndDefaultSecretLocked();
+                writeFrpMagicAndDefaultSecret();
                 mFrpActive = false;
                 return true;
             }
@@ -726,7 +726,7 @@
         synchronized (mLock) {
             if (!hasFrpSecretMagic()) {
                 Slog.i(TAG, "No FRP secret magic, system must have been upgraded.");
-                writeFrpMagicAndDefaultSecretLocked();
+                writeFrpMagicAndDefaultSecret();
             }
         }
 
@@ -748,7 +748,7 @@
         }
     }
 
-    private void writeFrpMagicAndDefaultSecretLocked() {
+    private void writeFrpMagicAndDefaultSecret() {
         try (FileChannel channel = getBlockOutputChannelIgnoringFrp()) {
             synchronized (mLock) {
                 Slog.i(TAG, "Writing default FRP secret");
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index a1dac04..5bd8ca6 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -17,6 +17,8 @@
 package com.android.server.pm;
 
 import static android.content.pm.Flags.disallowSdkLibsToBeApps;
+import static android.content.pm.PackageManager.APP_METADATA_SOURCE_APK;
+import static android.content.pm.PackageManager.APP_METADATA_SOURCE_INSTALLER;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
@@ -43,11 +45,11 @@
 import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
 import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL;
 
+import static com.android.internal.pm.pkg.parsing.ParsingPackageUtils.APP_METADATA_FILE_NAME;
 import static com.android.server.pm.DexOptHelper.useArtService;
 import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
 import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
-import static com.android.server.pm.PackageManagerService.APP_METADATA_FILE_NAME;
 import static com.android.server.pm.PackageManagerService.DEBUG_COMPRESSION;
 import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL;
 import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING;
@@ -701,7 +703,7 @@
                     pkgSetting.setUninstallReason(PackageManager.UNINSTALL_REASON_UNKNOWN, userId);
                     pkgSetting.setFirstInstallTime(System.currentTimeMillis(), userId);
                     // Clear any existing archive state.
-                    mPm.mInstallerService.mPackageArchiver.clearArchiveState(packageName, userId);
+                    mPm.mInstallerService.mPackageArchiver.clearArchiveState(pkgSetting, userId);
                     mPm.mSettings.writePackageRestrictionsLPr(userId);
                     mPm.mSettings.writeKernelMappingLPr(pkgSetting);
                     installed = true;
@@ -829,7 +831,8 @@
 
         if (DEBUG_INSTALL) Log.v(TAG, "+ starting restore round-trip " + token);
 
-        if (request.getReturnCode() == PackageManager.INSTALL_SUCCEEDED && doRestore) {
+        final boolean succeeded = request.getReturnCode() == PackageManager.INSTALL_SUCCEEDED;
+        if (succeeded && doRestore) {
             // Pass responsibility to the Backup Manager.  It will perform a
             // restore if appropriate, then pass responsibility back to the
             // Package Manager to run the post-install observer callbacks
@@ -843,10 +846,27 @@
         // need to be snapshotted or restored for the package.
         //
         // TODO(narayan): Get this working for cases where userId == UserHandle.USER_ALL.
-        if (request.getReturnCode() == PackageManager.INSTALL_SUCCEEDED && !doRestore && update) {
+        if (succeeded && !doRestore && update) {
             doRestore = performRollbackManagerRestore(userId, token, request);
         }
 
+        if (succeeded && !request.hasPostInstallRunnable()) {
+            boolean hasNeverBeenRestored =
+                    packageSetting != null && packageSetting.isPendingRestore();
+            request.setPostInstallRunnable(() -> {
+                // Permissions should be restored on each user that has the app installed for the
+                // first time, unless it's an unarchive install for an archived app, in which case
+                // the permissions should be restored on each user that has the app updated.
+                int[] userIdsToRestorePermissions = hasNeverBeenRestored
+                        ? request.getUpdateBroadcastUserIds()
+                        : request.getFirstTimeBroadcastUserIds();
+                for (int restorePermissionUserId : userIdsToRestorePermissions) {
+                    mPm.restorePermissionsAndUpdateRolesForNewUserInstall(request.getName(),
+                            restorePermissionUserId);
+                }
+            });
+        }
+
         if (doRestore) {
             if (packageSetting != null) {
                 synchronized (mPm.mLock) {
@@ -2207,10 +2227,16 @@
                 if (appMetadataFile.exists()) {
                     ps.setAppMetadataFilePath(appMetadataFile.getAbsolutePath());
                     if (Flags.aslInApkAppMetadataSource()) {
-                        ps.setAppMetadataSource(PackageManager.APP_METADATA_SOURCE_INSTALLER);
+                        ps.setAppMetadataSource(APP_METADATA_SOURCE_INSTALLER);
                     }
                 } else {
-                    ps.setAppMetadataFilePath(null);
+                    if (Flags.aslInApkAppMetadataSource()
+                            && parsedPackage.isAppMetadataFileInApk()) {
+                        ps.setAppMetadataFilePath(appMetadataFile.getAbsolutePath());
+                        ps.setAppMetadataSource(APP_METADATA_SOURCE_APK);
+                    } else {
+                        ps.setAppMetadataFilePath(null);
+                    }
                 }
             }
             if (installRequest.getReturnCode() == PackageManager.INSTALL_SUCCEEDED) {
@@ -2327,7 +2353,7 @@
                                 installerPackageName);
                     }
                     // Clear any existing archive state.
-                    mPm.mInstallerService.mPackageArchiver.clearArchiveState(pkgName, userId);
+                    mPm.mInstallerService.mPackageArchiver.clearArchiveState(ps, userId);
                 } else if (allUsers != null) {
                     // The caller explicitly specified INSTALL_ALL_USERS flag.
                     // Thus, updating the settings to install the app for all users.
@@ -2351,7 +2377,7 @@
                                         installerPackageName);
                             }
                             // Clear any existing archive state.
-                            mPm.mInstallerService.mPackageArchiver.clearArchiveState(pkgName,
+                            mPm.mInstallerService.mPackageArchiver.clearArchiveState(ps,
                                     currentUserId);
                         } else {
                             ps.setInstalled(false, currentUserId);
@@ -2851,7 +2877,6 @@
             mPm.notifyInstantAppPackageInstalled(request.getPkg().getPackageName(),
                     request.getNewUsers());
 
-            request.populateBroadcastUsers();
             final int[] firstUserIds = request.getFirstTimeBroadcastUserIds();
 
             if (request.getPkg().getStaticSharedLibraryName() == null) {
@@ -2863,12 +2888,6 @@
                     mPm.mRequiredInstallerPackage,
                     /* packageSender= */ mPm, launchedForRestore, killApp, update, archived);
 
-            // Work that needs to happen on first install within each user
-            for (int userId : firstUserIds) {
-                mPm.restorePermissionsAndUpdateRolesForNewUserInstall(packageName,
-                        userId);
-            }
-
             if (request.isAllNewUsers() && !update) {
                 mPm.notifyPackageAdded(packageName, request.getAppId());
             } else {
diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java
index 4fb0c22..43075a2 100644
--- a/services/core/java/com/android/server/pm/InstallRequest.java
+++ b/services/core/java/com/android/server/pm/InstallRequest.java
@@ -692,6 +692,14 @@
         }
     }
 
+    public void setPostInstallRunnable(Runnable runnable) {
+        mPostInstallRunnable = runnable;
+    }
+
+    public boolean hasPostInstallRunnable() {
+        return mPostInstallRunnable != null;
+    }
+
     public void runPostInstallRunnable() {
         if (mPostInstallRunnable != null) {
             mPostInstallRunnable.run();
@@ -753,6 +761,7 @@
 
     public void setNewUsers(int[] newUsers) {
         mNewUsers = newUsers;
+        populateBroadcastUsers();
     }
 
     public void setOriginPackage(String originPackage) {
@@ -829,10 +838,11 @@
     }
 
     /**
-     *  Determine the set of users who are adding this package for the first time vs. those who are
-     *  seeing an update.
+     *  Determine the set of users who are adding this package for the first time (aka "new" users)
+     *  vs. those who are seeing an update (aka "update" users). The lists can be calculated as soon
+     *  as the "new" users are set.
      */
-    public void populateBroadcastUsers() {
+    private void populateBroadcastUsers() {
         assertScanResultExists();
         mFirstTimeBroadcastUserIds = EMPTY_INT_ARRAY;
         mFirstTimeBroadcastInstantUserIds = EMPTY_INT_ARRAY;
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index d8d8dd2..3f9e989 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -2209,8 +2209,10 @@
             for (UserHandle user : users) {
                 mPackageManagerInternal.forEachInstalledPackage(pkg -> {
                     final String packageName = pkg.getPackageName();
-                    if (mPackageManagerInternal.getIncrementalStatesInfo(packageName,
-                            Process.myUid(), user.getIdentifier()).isLoading()) {
+                    final IncrementalStatesInfo info =
+                            mPackageManagerInternal.getIncrementalStatesInfo(packageName,
+                                    Process.myUid(), user.getIdentifier());
+                    if (info != null && info.isLoading()) {
                         mPackageManagerInternal.registerInstalledLoadingProgressCallback(
                                 packageName, new PackageLoadingProgressCallback(packageName, user),
                                 user.getIdentifier());
diff --git a/services/core/java/com/android/server/pm/PackageArchiver.java b/services/core/java/com/android/server/pm/PackageArchiver.java
index cdd52a4..2b20bfd 100644
--- a/services/core/java/com/android/server/pm/PackageArchiver.java
+++ b/services/core/java/com/android/server/pm/PackageArchiver.java
@@ -356,19 +356,34 @@
     }
 
     void clearArchiveState(String packageName, int userId) {
+        final PackageSetting ps;
         synchronized (mPm.mLock) {
-            PackageSetting ps = mPm.mSettings.getPackageLPr(packageName);
-            if (ps != null) {
-                ps.setArchiveState(/* archiveState= */ null, userId);
-            }
+            ps = mPm.mSettings.getPackageLPr(packageName);
         }
-        File iconsDir = getIconsDir(packageName, userId);
+        clearArchiveState(ps, userId);
+    }
+
+    void clearArchiveState(PackageSetting ps, int userId) {
+        synchronized (mPm.mLock) {
+            if (ps == null || ps.getUserStateOrDefault(userId).getArchiveState() == null) {
+                // No archive states to clear
+                return;
+            }
+            if (DEBUG) {
+                Slog.e(TAG, "Clearing archive states for " + ps.getPackageName());
+            }
+            ps.setArchiveState(/* archiveState= */ null, userId);
+        }
+        File iconsDir = getIconsDir(ps.getPackageName(), userId);
         if (!iconsDir.exists()) {
+            if (DEBUG) {
+                Slog.e(TAG, "Icons are already deleted at " + iconsDir.getAbsolutePath());
+            }
             return;
         }
         // TODO(b/319238030) Move this into installd.
         if (!FileUtils.deleteContentsAndDir(iconsDir)) {
-            Slog.e(TAG, "Failed to clean up archive files for " + packageName);
+            Slog.e(TAG, "Failed to clean up archive files for " + ps.getPackageName());
         } else {
             if (DEBUG) {
                 Slog.e(TAG, "Deleted icons at " + iconsDir.getAbsolutePath());
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 5792d86..ba90378 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -358,7 +358,7 @@
     /** Default byte size limit for app metadata */
     private static final long DEFAULT_APP_METADATA_BYTE_SIZE_LIMIT = 32000;
 
-    private static final int APP_METADATA_FILE_ACCESS_MODE = 0640;
+    static final int APP_METADATA_FILE_ACCESS_MODE = 0640;
 
     /**
      * Throws IllegalArgumentException if the {@link IntentSender} from an immutable
@@ -964,7 +964,7 @@
 
     private boolean isEmergencyInstallerEnabled(String packageName, Computer snapshot) {
         final PackageStateInternal ps = snapshot.getPackageStateInternal(packageName);
-        if (ps == null || ps.getPkg() == null || !ps.isSystem()) {
+        if (ps == null || ps.getPkg() == null) {
             return false;
         }
         String emergencyInstaller = ps.getPkg().getEmergencyInstaller();
@@ -1782,8 +1782,7 @@
     }
 
     private File getStagedAppMetadataFile() {
-        File file = new File(stageDir, APP_METADATA_FILE_NAME);
-        return file.exists() ? file : null;
+        return new File(stageDir, APP_METADATA_FILE_NAME);
     }
 
     private static boolean isAppMetadata(String name) {
@@ -1799,7 +1798,7 @@
         assertCallerIsOwnerOrRoot();
         synchronized (mLock) {
             assertPreparedAndNotCommittedOrDestroyedLocked("getAppMetadataFd");
-            if (getStagedAppMetadataFile() == null) {
+            if (!getStagedAppMetadataFile().exists()) {
                 return null;
             }
             try {
@@ -1813,12 +1812,12 @@
     @Override
     public void removeAppMetadata() {
         File file = getStagedAppMetadataFile();
-        if (file != null) {
+        if (file.exists()) {
             file.delete();
         }
     }
 
-    private static long getAppMetadataSizeLimit() {
+    static long getAppMetadataSizeLimit() {
         final long token = Binder.clearCallingIdentity();
         try {
             return DeviceConfig.getLong(NAMESPACE_PACKAGE_MANAGER_SERVICE,
@@ -2131,7 +2130,7 @@
         }
 
         File appMetadataFile = getStagedAppMetadataFile();
-        if (appMetadataFile != null) {
+        if (appMetadataFile.exists()) {
             long sizeLimit = getAppMetadataSizeLimit();
             if (appMetadataFile.length() > sizeLimit) {
                 appMetadataFile.delete();
@@ -3419,7 +3418,7 @@
 
         final List<ApkLite> addedFiles = getAddedApkLitesLocked();
         if (addedFiles.isEmpty()
-                && (removeSplitList.size() == 0 || getStagedAppMetadataFile() != null)) {
+                && (removeSplitList.size() == 0 || getStagedAppMetadataFile().exists())) {
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                     TextUtils.formatSimple("Session: %d. No packages staged in %s", sessionId,
                           stageDir.getAbsolutePath()));
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index dadafd7..69f7906 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -18,6 +18,8 @@
 import static android.Manifest.permission.MANAGE_DEVICE_ADMINS;
 import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS;
 import static android.app.AppOpsManager.MODE_IGNORED;
+import static android.content.pm.PackageManager.APP_METADATA_SOURCE_APK;
+import static android.content.pm.PackageManager.APP_METADATA_SOURCE_UNKNOWN;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
@@ -596,7 +598,8 @@
     static final String RANDOM_DIR_PREFIX = "~~";
     static final char RANDOM_CODEPATH_PREFIX = '-';
 
-    static final String APP_METADATA_FILE_NAME = "app.metadata";
+    public static final String APP_METADATA_FILE_NAME = "app.metadata";
+    public static final String APP_METADATA_FILE_IN_APK_PATH = "assets/" + APP_METADATA_FILE_NAME;
 
     static final int DEFAULT_FILE_ACCESS_MODE = 0644;
 
@@ -721,7 +724,6 @@
 
     PackageManagerInternal.ExternalSourcesPolicy mExternalSourcesPolicy;
 
-    @GuardedBy("mAvailableFeatures")
     private final ArrayMap<String, FeatureInfo> mAvailableFeatures;
 
     @Watched
@@ -2983,13 +2985,11 @@
 
     public boolean hasSystemFeature(String name, int version) {
         // allow instant applications
-        synchronized (mAvailableFeatures) {
-            final FeatureInfo feat = mAvailableFeatures.get(name);
-            if (feat == null) {
-                return false;
-            } else {
-                return feat.version >= version;
-            }
+        final FeatureInfo feat = mAvailableFeatures.get(name);
+        if (feat == null) {
+            return false;
+        } else {
+            return feat.version >= version;
         }
     }
 
@@ -5230,15 +5230,30 @@
                         new PackageManager.NameNotFoundException(packageName));
             }
             String filePath = ps.getAppMetadataFilePath();
-            if (filePath != null) {
-                File file = new File(filePath);
-                try {
-                    return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
-                } catch (FileNotFoundException e) {
+            if (filePath == null) {
+                return null;
+            }
+            File file = new File(filePath);
+            if (Flags.aslInApkAppMetadataSource() && !file.exists()
+                    && ps.getAppMetadataSource() == APP_METADATA_SOURCE_APK) {
+                String apkPath = ps.getPkg().getSplits().get(0).getPath();
+                if (!PackageManagerServiceUtils.extractAppMetadataFromApk(apkPath, file)) {
+                    if (file.exists()) {
+                        file.delete();
+                    }
+                    synchronized (mLock) {
+                        PackageSetting pkgSetting = mSettings.getPackageLPr(packageName);
+                        pkgSetting.setAppMetadataFilePath(null);
+                        pkgSetting.setAppMetadataSource(APP_METADATA_SOURCE_UNKNOWN);
+                    }
                     return null;
                 }
             }
-            return null;
+            try {
+                return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
+            } catch (FileNotFoundException e) {
+                return null;
+            }
         }
 
         @android.annotation.EnforcePermission(android.Manifest.permission.GET_APP_METADATA)
@@ -5335,10 +5350,8 @@
         public @NonNull ParceledListSlice<FeatureInfo> getSystemAvailableFeatures() {
             // allow instant applications
             ArrayList<FeatureInfo> res;
-            synchronized (mAvailableFeatures) {
-                res = new ArrayList<>(mAvailableFeatures.size() + 1);
-                res.addAll(mAvailableFeatures.values());
-            }
+            res = new ArrayList<>(mAvailableFeatures.size() + 1);
+            res.addAll(mAvailableFeatures.values());
             final FeatureInfo fi = new FeatureInfo();
             fi.reqGlEsVersion = SystemProperties.getInt("ro.opengles.version",
                     FeatureInfo.GL_ES_VERSION_UNDEFINED);
@@ -6542,9 +6555,7 @@
                     mOverlayConfigSignaturePackage,
                     mRecentsPackage);
             final ArrayMap<String, FeatureInfo> availableFeatures;
-            synchronized (mAvailableFeatures) {
-                availableFeatures = new ArrayMap<>(mAvailableFeatures);
-            }
+            availableFeatures = new ArrayMap<>(mAvailableFeatures);
             final ArraySet<String> protectedBroadcasts;
             synchronized (mProtectedBroadcasts) {
                 protectedBroadcasts = new ArraySet<>(mProtectedBroadcasts);
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 0a3dfc0..189a138 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -27,6 +27,9 @@
 import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
 import static com.android.internal.util.FrameworkStatsLog.UNSAFE_INTENT_EVENT_REPORTED__EVENT_TYPE__EXPLICIT_INTENT_FILTER_UNMATCH;
 import static com.android.server.LocalManagerRegistry.ManagerNotFoundException;
+import static com.android.server.pm.PackageInstallerSession.APP_METADATA_FILE_ACCESS_MODE;
+import static com.android.server.pm.PackageInstallerSession.getAppMetadataSizeLimit;
+import static com.android.server.pm.PackageManagerService.APP_METADATA_FILE_IN_APK_PATH;
 import static com.android.server.pm.PackageManagerService.COMPRESSED_EXTENSION;
 import static com.android.server.pm.PackageManagerService.DEBUG_COMPRESSION;
 import static com.android.server.pm.PackageManagerService.DEBUG_INTENT_MATCHING;
@@ -142,6 +145,8 @@
 import java.util.function.Function;
 import java.util.function.Predicate;
 import java.util.zip.GZIPInputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
 
 /**
  * Class containing helper methods for the PackageManagerService.
@@ -1559,6 +1564,35 @@
         return initiatingPackageName == null || SHELL_PACKAGE_NAME.equals(initiatingPackageName);
     }
 
+    /**
+     * Extract the app.metadata file from apk.
+     */
+    public static boolean extractAppMetadataFromApk(String apkPath, File appMetadataFile) {
+        boolean found = false;
+        try (ZipInputStream zipInputStream =
+                     new ZipInputStream(new FileInputStream(new File(apkPath)))) {
+            ZipEntry zipEntry = null;
+            while ((zipEntry = zipInputStream.getNextEntry()) != null) {
+                if (zipEntry.getName().equals(APP_METADATA_FILE_IN_APK_PATH)) {
+                    found = true;
+                    try (FileOutputStream out = new FileOutputStream(appMetadataFile)) {
+                        FileUtils.copy(zipInputStream, out);
+                    }
+                    if (appMetadataFile.length() > getAppMetadataSizeLimit()) {
+                        appMetadataFile.delete();
+                        return false;
+                    }
+                    Os.chmod(appMetadataFile.getAbsolutePath(), APP_METADATA_FILE_ACCESS_MODE);
+                    break;
+                }
+            }
+        } catch (Exception e) {
+            Slog.e(TAG, e.getMessage());
+            return false;
+        }
+        return found;
+    }
+
     public static void linkFilesToOldDirs(@NonNull Installer installer,
                                            @NonNull String packageName,
                                            @NonNull File newPath,
diff --git a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
index 5e8778d..9a7916a 100644
--- a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
+++ b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
@@ -53,7 +53,7 @@
  * as install) led to the request.
  */
 final class ReconcilePackageUtils {
-    private static final boolean ALLOW_NON_PRELOADS_SYSTEM_SIGNATURE = Build.IS_DEBUGGABLE;
+    private static final boolean ALLOW_NON_PRELOADS_SYSTEM_SIGNATURE = Build.IS_DEBUGGABLE || true;
 
     public static List<ReconciledPackage> reconcilePackages(
             List<InstallRequest> installRequests,
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index 1c70af0..b18503d 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -596,7 +596,7 @@
         ai.requiredDisplayCategory = a.getRequiredDisplayCategory();
         ai.requireContentUriPermissionFromCaller = a.getRequireContentUriPermissionFromCaller();
         ai.setKnownActivityEmbeddingCerts(a.getKnownActivityEmbeddingCerts());
-        assignFieldsComponentInfoParsedMainComponent(ai, a, pkgSetting, userId);
+        assignFieldsComponentInfoParsedMainComponent(ai, a, pkgSetting, state, userId);
         return ai;
     }
 
@@ -659,7 +659,7 @@
             // Backwards compatibility, coerce to null if empty
             si.metaData = metaData.isEmpty() ? null : metaData;
         }
-        assignFieldsComponentInfoParsedMainComponent(si, s, pkgSetting, userId);
+        assignFieldsComponentInfoParsedMainComponent(si, s, pkgSetting, state, userId);
         return si;
     }
 
@@ -710,7 +710,7 @@
             pi.metaData = metaData.isEmpty() ? null : metaData;
         }
         pi.applicationInfo = applicationInfo;
-        assignFieldsComponentInfoParsedMainComponent(pi, p, pkgSetting, userId);
+        assignFieldsComponentInfoParsedMainComponent(pi, p, pkgSetting, state, userId);
         return pi;
     }
 
@@ -903,8 +903,13 @@
 
     private static void assignFieldsComponentInfoParsedMainComponent(
             @NonNull ComponentInfo info, @NonNull ParsedMainComponent component,
-            @NonNull PackageStateInternal pkgSetting, @UserIdInt int userId) {
+            @NonNull PackageStateInternal pkgSetting, @NonNull PackageUserStateInternal state,
+            @UserIdInt int userId) {
         assignFieldsComponentInfoParsedMainComponent(info, component);
+        // overwrite the enabled state with the current user state
+        info.enabled = PackageUserStateUtils.isEnabled(state, info.applicationInfo.enabled,
+                info.enabled, info.name, /* flags */ 0);
+
         Pair<CharSequence, Integer> labelAndIcon =
                 ParsedComponentStateUtils.getNonLocalizedLabelAndIcon(component, pkgSetting,
                         userId);
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index f15646f..98499417 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -237,7 +237,7 @@
         mAppOpsCallback = new IAppOpsCallback.Stub() {
             public void opChanged(int op, int uid, @Nullable String packageName,
                     String persistentDeviceId) {
-                if (Objects.equals(persistentDeviceId,
+                if (!Objects.equals(persistentDeviceId,
                         VirtualDeviceManager.PERSISTENT_DEVICE_ID_DEFAULT)) {
                     return;
                 }
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
index b22e37b..c8cb92b 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java
@@ -167,6 +167,9 @@
     /** Config flag to track if battery saver's sticky behaviour is disabled. */
     private final boolean mBatterySaverStickyBehaviourDisabled;
 
+    /** Config flag to track if "Battery Saver turned off" notification is enabled. */
+    private final boolean mBatterySaverTurnedOffNotificationEnabled;
+
     /**
      * Whether or not to end sticky battery saver upon reaching a level specified by
      * {@link #mSettingBatterySaverStickyAutoDisableThreshold}.
@@ -250,6 +253,8 @@
 
         mBatterySaverStickyBehaviourDisabled = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled);
+        mBatterySaverTurnedOffNotificationEnabled = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_batterySaverTurnedOffNotificationEnabled);
         mDynamicPowerSavingsDefaultDisableThreshold = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_dynamicPowerSavingsDefaultDisableThreshold);
     }
@@ -858,6 +863,9 @@
 
     @VisibleForTesting
     void triggerStickyDisabledNotification() {
+        if (!mBatterySaverTurnedOffNotificationEnabled) {
+            return;
+        }
         // The current lock is the PowerManager lock, which sits very low in the service lock
         // hierarchy. We shouldn't call out to NotificationManager with the PowerManager lock.
         runOnBgThread(() -> {
@@ -997,6 +1005,8 @@
             ipw.println(mSettingBatterySaverTriggerThreshold);
             ipw.print("mBatterySaverStickyBehaviourDisabled=");
             ipw.println(mBatterySaverStickyBehaviourDisabled);
+            ipw.print("mBatterySaverTurnedOffNotificationEnabled=");
+            ipw.println(mBatterySaverTurnedOffNotificationEnabled);
 
             ipw.print("mDynamicPowerSavingsDefaultDisableThreshold=");
             ipw.println(mDynamicPowerSavingsDefaultDisableThreshold);
diff --git a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
index bf06c2a..8e3c6ac 100644
--- a/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
+++ b/services/core/java/com/android/server/power/stats/BatteryStatsImpl.java
@@ -1591,32 +1591,76 @@
     @Override
     public WakeLockStats getWakeLockStats() {
         final long realtimeMs = mClock.elapsedRealtime();
-        final long realtimeUs = realtimeMs * 1000;
         List<WakeLockStats.WakeLock> uidWakeLockStats = new ArrayList<>();
+        List<WakeLockStats.WakeLock> uidAggregatedWakeLockStats = new ArrayList<>();
         for (int i = mUidStats.size() - 1; i >= 0; i--) {
             final Uid uid = mUidStats.valueAt(i);
+
+            // Converts unaggregated wakelocks.
             final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelockStats =
                     uid.mWakelockStats.getMap();
             for (int j = wakelockStats.size() - 1; j >= 0; j--) {
                 final String name = wakelockStats.keyAt(j);
                 final Uid.Wakelock wakelock = (Uid.Wakelock) wakelockStats.valueAt(j);
-                final DualTimer timer = wakelock.mTimerPartial;
-                if (timer != null) {
-                    final long totalTimeLockHeldMs =
-                            timer.getTotalTimeLocked(realtimeUs, STATS_SINCE_CHARGED) / 1000;
-                    if (totalTimeLockHeldMs != 0) {
-                        uidWakeLockStats.add(
-                                new WakeLockStats.WakeLock(uid.getUid(), name,
-                                        timer.getCountLocked(STATS_SINCE_CHARGED),
-                                        totalTimeLockHeldMs,
-                                        timer.isRunningLocked()
-                                                ? timer.getCurrentDurationMsLocked(realtimeMs)
-                                                : 0));
-                    }
+                final WakeLockStats.WakeLock wakeLockItem =
+                        createWakeLock(uid, name, /* isAggregated= */ false, wakelock.mTimerPartial,
+                                realtimeMs);
+                if (wakeLockItem != null) {
+                    uidWakeLockStats.add(wakeLockItem);
                 }
             }
+
+            // Converts aggregated wakelocks.
+            final WakeLockStats.WakeLock aggregatedWakeLockItem =
+                    createWakeLock(
+                    uid,
+                    WakeLockStats.WakeLock.NAME_AGGREGATED,
+                    /* isAggregated= */ true,
+                    uid.mAggregatedPartialWakelockTimer,
+                    realtimeMs);
+            if (aggregatedWakeLockItem != null) {
+                uidAggregatedWakeLockStats.add(aggregatedWakeLockItem);
+            }
         }
-        return new WakeLockStats(uidWakeLockStats);
+        return new WakeLockStats(uidWakeLockStats, uidAggregatedWakeLockStats);
+    }
+
+    // Returns a valid {@code WakeLockStats.WakeLock} or null.
+    private WakeLockStats.WakeLock createWakeLock(
+            Uid uid, String name, boolean isAggregated, DualTimer timer, final long realtimeMs) {
+        if (timer == null) {
+            return null;
+        }
+        // Uses the primary timer for total wakelock data and used the sub timer for background
+        // wakelock data.
+        final WakeLockStats.WakeLockData totalWakeLockData = createWakeLockData(timer, realtimeMs);
+        final WakeLockStats.WakeLockData backgroundWakeLockData =
+                createWakeLockData(timer.getSubTimer(), realtimeMs);
+
+        return WakeLockStats.WakeLock.isDataValid(totalWakeLockData, backgroundWakeLockData)
+                ? new WakeLockStats.WakeLock(
+                uid.getUid(),
+                name,
+                isAggregated,
+                totalWakeLockData,
+                backgroundWakeLockData) : null;
+    }
+
+    @NonNull
+    private WakeLockStats.WakeLockData createWakeLockData(
+            DurationTimer timer, final long realtimeMs) {
+        if (timer == null) {
+            return WakeLockStats.WakeLockData.EMPTY;
+        }
+        final long totalTimeLockHeldMs =
+                timer.getTotalTimeLocked(realtimeMs * 1000, STATS_SINCE_CHARGED) / 1000;
+        if (totalTimeLockHeldMs == 0) {
+            return WakeLockStats.WakeLockData.EMPTY;
+        }
+        return new WakeLockStats.WakeLockData(
+            timer.getCountLocked(STATS_SINCE_CHARGED),
+            totalTimeLockHeldMs,
+            timer.isRunningLocked() ? timer.getCurrentDurationMsLocked(realtimeMs) : 0);
     }
 
     @Override
@@ -1817,9 +1861,8 @@
         if (historyDirectory == null) {
             mCheckinFile = null;
             mStatsFile = null;
-            mHistory = new BatteryStatsHistory(mConstants.MAX_HISTORY_FILES,
-                    mConstants.MAX_HISTORY_BUFFER, mStepDetailsCalculator, mClock, mMonotonicClock,
-                    traceDelegate, eventLogger);
+            mHistory = new BatteryStatsHistory(mConstants.MAX_HISTORY_BUFFER,
+                    mStepDetailsCalculator, mClock, mMonotonicClock, traceDelegate, eventLogger);
         } else {
             mCheckinFile = new AtomicFile(new File(historyDirectory, "batterystats-checkin.bin"));
             mStatsFile = new AtomicFile(new File(historyDirectory, "batterystats.bin"));
@@ -10962,8 +11005,8 @@
             mStatsFile = null;
             mCheckinFile = null;
             mDailyFile = null;
-            mHistory = new BatteryStatsHistory(mConstants.MAX_HISTORY_FILES,
-                    mConstants.MAX_HISTORY_BUFFER, mStepDetailsCalculator, mClock, mMonotonicClock);
+            mHistory = new BatteryStatsHistory(mConstants.MAX_HISTORY_BUFFER,
+                    mStepDetailsCalculator, mClock, mMonotonicClock);
         } else {
             mStatsFile = new AtomicFile(new File(systemDir, "batterystats.bin"));
             mCheckinFile = new AtomicFile(new File(systemDir, "batterystats-checkin.bin"));
diff --git a/services/core/java/com/android/server/power/stats/PowerStatsSpan.java b/services/core/java/com/android/server/power/stats/PowerStatsSpan.java
index 3b260ca..4df919d 100644
--- a/services/core/java/com/android/server/power/stats/PowerStatsSpan.java
+++ b/services/core/java/com/android/server/power/stats/PowerStatsSpan.java
@@ -57,7 +57,7 @@
      * {@link #isCompatibleXmlFormat} to return true for all legacy versions
      * that are compatible with the new one.
      */
-    private static final int VERSION = 1;
+    private static final int VERSION = 2;
 
     private static final String XML_TAG_METADATA = "metadata";
     private static final String XML_ATTR_ID = "id";
diff --git a/services/core/java/com/android/server/search/SearchManagerService.java b/services/core/java/com/android/server/search/SearchManagerService.java
index 7091c47..ecfc040 100644
--- a/services/core/java/com/android/server/search/SearchManagerService.java
+++ b/services/core/java/com/android/server/search/SearchManagerService.java
@@ -17,6 +17,7 @@
 package com.android.server.search;
 
 import android.annotation.NonNull;
+import android.annotation.UserIdInt;
 import android.app.ISearchManager;
 import android.app.SearchManager;
 import android.app.SearchableInfo;
@@ -24,6 +25,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.database.ContentObserver;
 import android.os.Binder;
@@ -32,6 +34,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.util.ArraySet;
 import android.util.Log;
 import android.util.SparseArray;
 
@@ -47,6 +50,7 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -71,11 +75,6 @@
         }
 
         @Override
-        public void onUserUnlocking(@NonNull TargetUser user) {
-            mService.mHandler.post(() -> mService.onUnlockUser(user.getUserIdentifier()));
-        }
-
-        @Override
         public void onUserStopped(@NonNull TargetUser user) {
             mService.onCleanupUser(user.getUserIdentifier());
         }
@@ -102,10 +101,6 @@
     }
 
     private Searchables getSearchables(int userId) {
-        return getSearchables(userId, false);
-    }
-
-    private Searchables getSearchables(int userId, boolean forceUpdate) {
         final long token = Binder.clearCallingIdentity();
         try {
             final UserManager um = mContext.getSystemService(UserManager.class);
@@ -122,21 +117,11 @@
             Searchables searchables = mSearchables.get(userId);
             if (searchables == null) {
                 searchables = new Searchables(mContext, userId);
-                searchables.updateSearchableList();
-                mSearchables.append(userId, searchables);
-            } else if (forceUpdate) {
-                searchables.updateSearchableList();
+                mSearchables.put(userId, searchables);
             }
-            return searchables;
-        }
-    }
 
-    private void onUnlockUser(int userId) {
-        try {
-            getSearchables(userId, true);
-        } catch (IllegalStateException ignored) {
-            // We're just trying to warm a cache, so we don't mind if the user
-            // was stopped or destroyed before we got here.
+            searchables.updateSearchableListIfNeeded();
+            return searchables;
         }
     }
 
@@ -150,28 +135,110 @@
      * Refreshes the "searchables" list when packages are added/removed.
      */
     class MyPackageMonitor extends PackageMonitor {
+        /**
+         * Packages that are appeared, disappeared, or modified for whatever reason.
+         */
+        private final ArrayList<String> mChangedPackages = new ArrayList<>();
+
+        /**
+         * {@code true} if one or more packages that contain {@link SearchableInfo} appeared.
+         */
+        private boolean mSearchablePackageAppeared = false;
 
         @Override
-        public void onSomePackagesChanged() {
-            updateSearchables();
+        public void onBeginPackageChanges() {
+            clearPackageChangeState();
         }
 
         @Override
-        public void onPackageModified(String pkg) {
-            updateSearchables();
+        public void onPackageAppeared(String packageName, int reason) {
+            if (!mSearchablePackageAppeared) {
+                // Check if the new appeared package contains SearchableInfo.
+                mSearchablePackageAppeared =
+                        hasSearchableForPackage(packageName, getChangingUserId());
+            }
+            mChangedPackages.add(packageName);
         }
 
-        private void updateSearchables() {
-            final int changingUserId = getChangingUserId();
+        @Override
+        public void onPackageDisappeared(String packageName, int reason) {
+            mChangedPackages.add(packageName);
+        }
+
+        @Override
+        public void onPackageModified(String packageName) {
+            mChangedPackages.add(packageName);
+        }
+
+        @Override
+        public void onFinishPackageChanges() {
+            onFinishPackageChangesInternal();
+            clearPackageChangeState();
+        }
+
+        private void clearPackageChangeState() {
+            mChangedPackages.clear();
+            mSearchablePackageAppeared = false;
+        }
+
+        private boolean hasSearchableForPackage(String packageName, int userId) {
+            final List<ResolveInfo> searchList = querySearchableActivities(mContext,
+                    new Intent(Intent.ACTION_SEARCH).setPackage(packageName), userId);
+            if (!searchList.isEmpty()) {
+                return true;
+            }
+
+            final List<ResolveInfo> webSearchList = querySearchableActivities(mContext,
+                    new Intent(Intent.ACTION_WEB_SEARCH).setPackage(packageName), userId);
+            if (!webSearchList.isEmpty()) {
+                return true;
+            }
+
+            final List<ResolveInfo> globalSearchList = querySearchableActivities(mContext,
+                    new Intent(SearchManager.INTENT_ACTION_GLOBAL_SEARCH).setPackage(packageName),
+                    userId);
+            return !globalSearchList.isEmpty();
+        }
+
+        private boolean shouldRebuildSearchableList(@UserIdInt int changingUserId) {
+            // This method is guaranteed to be called only on getRegisteredHandler()
+            if (mSearchablePackageAppeared) {
+                return true;
+            }
+
+            ArraySet<String> knownSearchablePackageNames = new ArraySet<>();
             synchronized (mSearchables) {
-                // Update list of searchable activities
-                for (int i = 0; i < mSearchables.size(); i++) {
-                    if (changingUserId == mSearchables.keyAt(i)) {
-                        mSearchables.valueAt(i).updateSearchableList();
-                        break;
-                    }
+                Searchables searchables = mSearchables.get(changingUserId);
+                if (searchables != null) {
+                    knownSearchablePackageNames = searchables.getKnownSearchablePackageNames();
                 }
             }
+
+            final int numOfPackages = mChangedPackages.size();
+            for (int i = 0; i < numOfPackages; i++) {
+                final String packageName = mChangedPackages.get(i);
+                if (knownSearchablePackageNames.contains(packageName)) {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        private void onFinishPackageChangesInternal() {
+            final int changingUserId = getChangingUserId();
+            if (!shouldRebuildSearchableList(changingUserId)) {
+                return;
+            }
+
+            synchronized (mSearchables) {
+                // Invalidate the searchable list.
+                Searchables searchables = mSearchables.get(changingUserId);
+                if (searchables != null) {
+                    searchables.invalidateSearchableList();
+                }
+            }
+
             // Inform all listeners that the list of searchables has been updated.
             Intent intent = new Intent(SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED);
             intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
@@ -180,6 +247,17 @@
         }
     }
 
+    @NonNull
+    static List<ResolveInfo> querySearchableActivities(Context context, Intent searchIntent,
+            @UserIdInt int userId) {
+        final List<ResolveInfo> activities = context.getPackageManager()
+                .queryIntentActivitiesAsUser(searchIntent, PackageManager.GET_META_DATA
+                        | PackageManager.MATCH_INSTANT
+                        | PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userId);
+        return activities;
+    }
+
+
     class GlobalSearchProviderObserver extends ContentObserver {
         private final ContentResolver mResolver;
 
@@ -196,7 +274,7 @@
         public void onChange(boolean selfChange) {
             synchronized (mSearchables) {
                 for (int i = 0; i < mSearchables.size(); i++) {
-                    mSearchables.valueAt(i).updateSearchableList();
+                    mSearchables.valueAt(i).invalidateSearchableList();
                 }
             }
             Intent intent = new Intent(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);
diff --git a/services/core/java/com/android/server/search/Searchables.java b/services/core/java/com/android/server/search/Searchables.java
index 7b39775..dc67339 100644
--- a/services/core/java/com/android/server/search/Searchables.java
+++ b/services/core/java/com/android/server/search/Searchables.java
@@ -35,8 +35,10 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.ArraySet;
 import android.util.Log;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.server.LocalServices;
 
 import java.io.FileDescriptor;
@@ -62,7 +64,6 @@
     private static final String MD_SEARCHABLE_SYSTEM_SEARCH = "*";
 
     private Context mContext;
-
     private HashMap<ComponentName, SearchableInfo> mSearchablesMap = null;
     private ArrayList<SearchableInfo> mSearchablesList = null;
     private ArrayList<SearchableInfo> mSearchablesInGlobalSearchList = null;
@@ -81,6 +82,12 @@
     final private IPackageManager mPm;
     // User for which this Searchables caches information
     private int mUserId;
+    @GuardedBy("this")
+    private boolean mRebuildSearchables = true;
+
+    // Package names that are known to contain {@link SearchableInfo}
+    @GuardedBy("this")
+    private ArraySet<String> mKnownSearchablePackageNames = new ArraySet<>();
 
     /**
      *
@@ -224,7 +231,14 @@
      *
      * TODO: sort the list somehow?  UI choice.
      */
-    public void updateSearchableList() {
+    public void updateSearchableListIfNeeded() {
+        synchronized (this) {
+            if (!mRebuildSearchables) {
+                // The searchable list is valid, no need to rebuild.
+                return;
+            }
+        }
+
         // These will become the new values at the end of the method
         HashMap<ComponentName, SearchableInfo> newSearchablesMap
                                 = new HashMap<ComponentName, SearchableInfo>();
@@ -232,6 +246,7 @@
                                 = new ArrayList<SearchableInfo>();
         ArrayList<SearchableInfo> newSearchablesInGlobalSearchList
                                 = new ArrayList<SearchableInfo>();
+        ArraySet<String> newKnownSearchablePackageNames = new ArraySet<>();
 
         // Use intent resolver to generate list of ACTION_SEARCH & ACTION_WEB_SEARCH receivers.
         List<ResolveInfo> searchList;
@@ -264,6 +279,7 @@
                                 mUserId);
                         if (searchable != null) {
                             newSearchablesList.add(searchable);
+                            newKnownSearchablePackageNames.add(ai.packageName);
                             newSearchablesMap.put(searchable.getSearchActivity(), searchable);
                             if (searchable.shouldIncludeInGlobalSearch()) {
                                 newSearchablesInGlobalSearchList.add(searchable);
@@ -286,16 +302,41 @@
             synchronized (this) {
                 mSearchablesMap = newSearchablesMap;
                 mSearchablesList = newSearchablesList;
+                mKnownSearchablePackageNames = newKnownSearchablePackageNames;
                 mSearchablesInGlobalSearchList = newSearchablesInGlobalSearchList;
                 mGlobalSearchActivities = newGlobalSearchActivities;
                 mCurrentGlobalSearchActivity = newGlobalSearchActivity;
                 mWebSearchActivity = newWebSearchActivity;
+                for (ResolveInfo globalSearchActivity: mGlobalSearchActivities) {
+                    mKnownSearchablePackageNames.add(
+                            globalSearchActivity.getComponentInfo().packageName);
+                }
+                if (mCurrentGlobalSearchActivity != null) {
+                    mKnownSearchablePackageNames.add(
+                            mCurrentGlobalSearchActivity.getPackageName());
+                }
+                if (mWebSearchActivity != null) {
+                    mKnownSearchablePackageNames.add(mWebSearchActivity.getPackageName());
+                }
+
+                mRebuildSearchables = false;
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
     }
 
+    synchronized ArraySet<String> getKnownSearchablePackageNames() {
+        return mKnownSearchablePackageNames;
+    }
+
+    synchronized void invalidateSearchableList() {
+        mRebuildSearchables = true;
+
+        // Don't rebuild the searchable list, it will be rebuilt
+        // when the next updateSearchableList gets called.
+    }
+
     /**
      * Returns a sorted list of installed search providers as per
      * the following heuristics:
@@ -532,6 +573,8 @@
                     pw.print("  "); pw.println(info.getSuggestAuthority());
                 }
             }
+
+            pw.println("mRebuildSearchables = " + mRebuildSearchables);
         }
     }
 }
diff --git a/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java b/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java
index bb5a697..7ddb61e 100644
--- a/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java
+++ b/services/core/java/com/android/server/speech/RemoteSpeechRecognitionService.java
@@ -68,12 +68,14 @@
     private final ComponentName mComponentName;
 
     RemoteSpeechRecognitionService(
-            Context context, ComponentName serviceName, int userId, int callingUid) {
+            Context context,
+            ComponentName serviceName,
+            int userId,
+            int callingUid,
+            boolean isPrivileged) {
         super(context,
                 new Intent(RecognitionService.SERVICE_INTERFACE).setComponent(serviceName),
-                Context.BIND_AUTO_CREATE
-                        | Context.BIND_FOREGROUND_SERVICE
-                        | Context.BIND_INCLUDE_CAPABILITIES,
+                getBindingFlags(isPrivileged),
                 userId,
                 IRecognitionService.Stub::asInterface);
 
@@ -85,6 +87,14 @@
         }
     }
 
+    private static int getBindingFlags(boolean isPrivileged) {
+        int bindingFlags = Context.BIND_AUTO_CREATE;
+        if (isPrivileged) {
+            bindingFlags |= Context.BIND_INCLUDE_CAPABILITIES | Context.BIND_FOREGROUND_SERVICE;
+        }
+        return bindingFlags;
+    }
+
     ComponentName getServiceComponentName() {
         return mComponentName;
     }
diff --git a/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java b/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java
index 8e9c889..808504f 100644
--- a/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/speech/SpeechRecognitionManagerServiceImpl.java
@@ -23,6 +23,7 @@
 import android.content.AttributionSource;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
@@ -31,6 +32,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.permission.PermissionManager;
+import android.provider.Settings;
 import android.speech.IModelDownloadListener;
 import android.speech.IRecognitionListener;
 import android.speech.IRecognitionService;
@@ -311,9 +313,22 @@
                 return null;
             }
 
+            final boolean isPrivileged;
+            if (serviceComponent == null) {
+                isPrivileged = false;
+            } else {
+                // Only certain privileged recognition service can obtain process capabilities
+                // from persistent process to hold while-in-use permission in the background.
+                isPrivileged = checkPrivilege(serviceComponent);
+            }
+
             RemoteSpeechRecognitionService service =
                     new RemoteSpeechRecognitionService(
-                            getContext(), serviceComponent, getUserId(), callingUid);
+                            getContext(),
+                            serviceComponent,
+                            getUserId(),
+                            callingUid,
+                            isPrivileged);
 
             Set<RemoteSpeechRecognitionService> valuesByCaller =
                     mRemoteServicesByUid.computeIfAbsent(callingUid, key -> new HashSet<>());
@@ -328,6 +343,53 @@
         }
     }
 
+    /**
+     * Checks if the given service component should have privileged binding flags when created. Only
+     * a service component that matches with any of the following condition would be granted:
+     *
+     * <ul>
+     *     <li>A default recognition service component.</li>
+     *     <li>An on-device recognition service component.</li>
+     *     <li>A pre-installed recognition service component.</li>
+     * </ul>
+     */
+    @GuardedBy("mLock")
+    private boolean checkPrivilege(@NonNull ComponentName serviceComponent) {
+        final ComponentName defaultComponent = getDefaultRecognitionServiceComponent();
+        final ComponentName onDeviceComponent = getOnDeviceComponentNameLocked();
+        final boolean preinstalled = isPreinstalledApp(serviceComponent);
+        return serviceComponent.equals(defaultComponent)
+                || serviceComponent.equals(onDeviceComponent)
+                || preinstalled;
+    }
+
+    private boolean isPreinstalledApp(@NonNull ComponentName serviceComponent) {
+        PackageManager pm = getContext().getPackageManager();
+        if (pm == null) {
+            return false;
+        }
+
+        try {
+            ApplicationInfo info = pm.getApplicationInfoAsUser(serviceComponent.getPackageName(),
+                    PackageManager.MATCH_SYSTEM_ONLY, getUserId());
+            return (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+        } catch (PackageManager.NameNotFoundException e) {
+            return false;
+        }
+    }
+
+    @Nullable
+    private ComponentName getDefaultRecognitionServiceComponent() {
+        String componentName = Settings.Secure.getStringForUser(
+                getContext().getContentResolver(),
+                Settings.Secure.VOICE_RECOGNITION_SERVICE,
+                getUserId());
+        if (componentName == null) {
+            return null;
+        }
+        return ComponentName.unflattenFromString(componentName);
+    }
+
     private boolean componentMapsToRecognitionService(@NonNull ComponentName serviceComponent) {
         List<ResolveInfo> resolveInfos;
 
diff --git a/services/core/java/com/android/server/stats/pull/AggregatedMobileDataStatsPuller.java b/services/core/java/com/android/server/stats/pull/AggregatedMobileDataStatsPuller.java
index b0dcf95..881583a 100644
--- a/services/core/java/com/android/server/stats/pull/AggregatedMobileDataStatsPuller.java
+++ b/services/core/java/com/android/server/stats/pull/AggregatedMobileDataStatsPuller.java
@@ -282,10 +282,7 @@
             Slog.d(TAG,
                     "pullDataBytesTransferLocked() done. results count " + pulledData.size());
         }
-        if (!pulledData.isEmpty()) {
-            return StatsManager.PULL_SUCCESS;
-        }
-        return StatsManager.PULL_SKIP;
+        return StatsManager.PULL_SUCCESS;
     }
 
     private static boolean isEmpty(NetworkStats stats) {
diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
index 17f5e95..7206c03 100644
--- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
+++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
@@ -164,7 +164,6 @@
         registerCarrierPrivilegesCallbacks();
     }
 
-    // TODO(b/221306368): Refactor with the new onCarrierServiceChange in the new CPCallback
     private void registerCarrierPrivilegesCallbacks() {
         final HandlerExecutor executor = new HandlerExecutor(mHandler);
         final int modemCount = mTelephonyManager.getActiveModemCount();
diff --git a/services/core/java/com/android/server/vibrator/VibrationScaler.java b/services/core/java/com/android/server/vibrator/VibrationScaler.java
index 7163319..5d17884 100644
--- a/services/core/java/com/android/server/vibrator/VibrationScaler.java
+++ b/services/core/java/com/android/server/vibrator/VibrationScaler.java
@@ -19,7 +19,7 @@
 import android.annotation.NonNull;
 import android.content.Context;
 import android.hardware.vibrator.V1_0.EffectStrength;
-import android.os.IExternalVibratorService;
+import android.os.ExternalVibrationScale;
 import android.os.VibrationAttributes;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
@@ -37,11 +37,13 @@
 
     // Scale levels. Each level, except MUTE, is defined as the delta between the current setting
     // and the default intensity for that type of vibration (i.e. current - default).
-    private static final int SCALE_VERY_LOW = IExternalVibratorService.SCALE_VERY_LOW; // -2
-    private static final int SCALE_LOW = IExternalVibratorService.SCALE_LOW; // -1
-    private static final int SCALE_NONE = IExternalVibratorService.SCALE_NONE; // 0
-    private static final int SCALE_HIGH = IExternalVibratorService.SCALE_HIGH; // 1
-    private static final int SCALE_VERY_HIGH = IExternalVibratorService.SCALE_VERY_HIGH; // 2
+    private static final int SCALE_VERY_LOW =
+            ExternalVibrationScale.ScaleLevel.SCALE_VERY_LOW; // -2
+    private static final int SCALE_LOW = ExternalVibrationScale.ScaleLevel.SCALE_LOW; // -1
+    private static final int SCALE_NONE = ExternalVibrationScale.ScaleLevel.SCALE_NONE; // 0
+    private static final int SCALE_HIGH = ExternalVibrationScale.ScaleLevel.SCALE_HIGH; // 1
+    private static final int SCALE_VERY_HIGH =
+            ExternalVibrationScale.ScaleLevel.SCALE_VERY_HIGH; // 2
 
     // Scale factors for each level.
     private static final float SCALE_FACTOR_VERY_LOW = 0.6f;
@@ -83,9 +85,9 @@
      * Calculates the scale to be applied to external vibration with given usage.
      *
      * @param usageHint one of VibrationAttributes.USAGE_*
-     * @return one of IExternalVibratorService.SCALE_*
+     * @return one of ExternalVibrationScale.ScaleLevel.SCALE_*
      */
-    public int getExternalVibrationScale(int usageHint) {
+    public int getExternalVibrationScaleLevel(int usageHint) {
         int defaultIntensity = mSettingsController.getDefaultIntensity(usageHint);
         int currentIntensity = mSettingsController.getCurrentIntensity(usageHint);
 
@@ -107,6 +109,22 @@
     }
 
     /**
+     * Returns the adaptive haptics scale that should be applied to the vibrations with
+     * the given usage. When no adaptive scales are available for the usages, then returns 1
+     * indicating no scaling will be applied
+     *
+     * @param usageHint one of VibrationAttributes.USAGE_*
+     * @return The adaptive haptics scale.
+     */
+    public float getAdaptiveHapticsScale(int usageHint) {
+        if (shouldApplyAdaptiveHapticsScale(usageHint)) {
+            return mAdaptiveHapticsScales.get(usageHint);
+        }
+
+        return 1f; // no scaling
+    }
+
+    /**
      * Scale a {@link VibrationEffect} based on the given usage hint for this vibration.
      *
      * @param effect    the effect to be scaled
@@ -152,9 +170,7 @@
             }
 
             // If adaptive haptics scaling is available for this usage, apply it to the segment.
-            if (Flags.adaptiveHapticsEnabled()
-                    && mAdaptiveHapticsScales.size() > 0
-                    && mAdaptiveHapticsScales.contains(usageHint)) {
+            if (shouldApplyAdaptiveHapticsScale(usageHint)) {
                 float adaptiveScale = mAdaptiveHapticsScales.get(usageHint);
                 segment = segment.scaleLinearly(adaptiveScale);
             }
@@ -224,6 +240,10 @@
         mAdaptiveHapticsScales.clear();
     }
 
+    private boolean shouldApplyAdaptiveHapticsScale(int usageHint) {
+        return Flags.adaptiveHapticsEnabled() && mAdaptiveHapticsScales.contains(usageHint);
+    }
+
     /** Mapping of Vibrator.VIBRATION_INTENSITY_* values to {@link EffectStrength}. */
     private static int intensityToEffectStrength(int intensity) {
         switch (intensity) {
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index be5d158..78e0ebb 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.vibrator;
 
+import static android.os.ExternalVibrationScale.ScaleLevel.SCALE_MUTE;
 import static android.os.VibrationEffect.VibrationParameter.targetAmplitude;
 import static android.os.VibrationEffect.VibrationParameter.targetFrequency;
 
@@ -35,6 +36,7 @@
 import android.os.Build;
 import android.os.CombinedVibration;
 import android.os.ExternalVibration;
+import android.os.ExternalVibrationScale;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.IExternalVibratorService;
@@ -277,7 +279,7 @@
         context.registerReceiver(mIntentReceiver, filter, Context.RECEIVER_NOT_EXPORTED);
 
         injector.addService(EXTERNAL_VIBRATOR_SERVICE, new ExternalVibratorService());
-        if (ServiceManager.isDeclared(VIBRATOR_CONTROL_SERVICE)) {
+        if (injector.isServiceDeclared(VIBRATOR_CONTROL_SERVICE)) {
             injector.addService(VIBRATOR_CONTROL_SERVICE, mVibratorControlService);
         }
 
@@ -1427,6 +1429,10 @@
         VibratorControllerHolder createVibratorControllerHolder() {
             return new VibratorControllerHolder();
         }
+
+        boolean isServiceDeclared(String name) {
+            return ServiceManager.isDeclared(name);
+        }
     }
 
     /**
@@ -1594,7 +1600,7 @@
             IBinder.DeathRecipient {
 
         public final ExternalVibration externalVibration;
-        public int scale;
+        public ExternalVibrationScale scale = new ExternalVibrationScale();
 
         private Vibration.Status mStatus;
 
@@ -1605,7 +1611,6 @@
                     // instead of using DEVICE_ID_INVALID here and relying on the UID checks.
                     Context.DEVICE_ID_INVALID, externalVibration.getPackage(), null));
             this.externalVibration = externalVibration;
-            this.scale = IExternalVibratorService.SCALE_NONE;
             mStatus = Vibration.Status.RUNNING;
         }
 
@@ -1658,7 +1663,7 @@
 
         public Vibration.DebugInfo getDebugInfo() {
             return new Vibration.DebugInfo(mStatus, stats, /* playedEffect= */ null,
-                    /* originalEffect= */ null, scale, callerInfo);
+                    /* originalEffect= */ null, scale.scaleLevel, callerInfo);
         }
 
         public VibrationStats.StatsInfo getStatsInfo(long completionUptimeMillis) {
@@ -1988,11 +1993,17 @@
     /** Implementation of {@link IExternalVibratorService} to be triggered on external control. */
     @VisibleForTesting
     final class ExternalVibratorService extends IExternalVibratorService.Stub {
+        private static final ExternalVibrationScale SCALE_MUTE = new ExternalVibrationScale();
+
+        static {
+            SCALE_MUTE.scaleLevel = ExternalVibrationScale.ScaleLevel.SCALE_MUTE;
+        }
 
         @Override
-        public int onExternalVibrationStart(ExternalVibration vib) {
+        public ExternalVibrationScale onExternalVibrationStart(ExternalVibration vib) {
+
             if (!hasExternalControlCapability()) {
-                return IExternalVibratorService.SCALE_MUTE;
+                return SCALE_MUTE;
             }
             if (ActivityManager.checkComponentPermission(android.Manifest.permission.VIBRATE,
                     vib.getUid(), -1 /*owningUid*/, true /*exported*/)
@@ -2000,7 +2011,7 @@
                 Slog.w(TAG, "pkg=" + vib.getPackage() + ", uid=" + vib.getUid()
                         + " tried to play externally controlled vibration"
                         + " without VIBRATE permission, ignoring.");
-                return IExternalVibratorService.SCALE_MUTE;
+                return SCALE_MUTE;
             }
 
             // Create Vibration.Stats as close to the received request as possible, for tracking.
@@ -2033,7 +2044,7 @@
                 }
 
                 if (vibrationEndInfo != null) {
-                    vibHolder.scale = IExternalVibratorService.SCALE_MUTE;
+                    vibHolder.scale = SCALE_MUTE;
                     // Failed to start the vibration, end it and report metrics right away.
                     endVibrationAndWriteStatsLocked(vibHolder, vibrationEndInfo);
                     return vibHolder.scale;
@@ -2074,7 +2085,10 @@
                 }
                 mCurrentExternalVibration = vibHolder;
                 vibHolder.linkToDeath();
-                vibHolder.scale = mVibrationScaler.getExternalVibrationScale(attrs.getUsage());
+                vibHolder.scale.scaleLevel = mVibrationScaler.getExternalVibrationScaleLevel(
+                        attrs.getUsage());
+                vibHolder.scale.adaptiveHapticsScale = mVibrationScaler.getAdaptiveHapticsScale(
+                        attrs.getUsage());
             }
 
             if (waitForCompletion) {
@@ -2086,7 +2100,7 @@
                                 new Vibration.EndInfo(Vibration.Status.IGNORED_ERROR_CANCELLING),
                                 /* continueExternalControl= */ false);
                     }
-                    return IExternalVibratorService.SCALE_MUTE;
+                    return SCALE_MUTE;
                 }
             }
             if (!alreadyUnderExternalControl) {
diff --git a/services/core/java/com/android/server/webkit/SystemImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java
index 3b2e69a..c6e8eb8 100644
--- a/services/core/java/com/android/server/webkit/SystemImpl.java
+++ b/services/core/java/com/android/server/webkit/SystemImpl.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
+import android.content.pm.PackageInstaller;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.UserInfo;
@@ -225,6 +226,21 @@
     }
 
     @Override
+    public void installExistingPackageForAllUsers(Context context, String packageName) {
+        UserManager userManager = context.getSystemService(UserManager.class);
+        for (UserInfo userInfo : userManager.getUsers()) {
+            installPackageForUser(packageName, userInfo.id);
+        }
+    }
+
+    private void installPackageForUser(String packageName, int userId) {
+        final Context context = AppGlobals.getInitialApplication();
+        final Context contextAsUser = context.createContextAsUser(UserHandle.of(userId), 0);
+        final PackageInstaller installer = contextAsUser.getPackageManager().getPackageInstaller();
+        installer.installExistingPackage(packageName, PackageManager.INSTALL_REASON_UNKNOWN, null);
+    }
+
+    @Override
     public boolean systemIsDebuggable() {
         return Build.IS_DEBUGGABLE;
     }
diff --git a/services/core/java/com/android/server/webkit/SystemInterface.java b/services/core/java/com/android/server/webkit/SystemInterface.java
index 5ed2cfe..ad32f62 100644
--- a/services/core/java/com/android/server/webkit/SystemInterface.java
+++ b/services/core/java/com/android/server/webkit/SystemInterface.java
@@ -43,6 +43,7 @@
     public void killPackageDependents(String packageName);
 
     public void enablePackageForAllUsers(Context context, String packageName, boolean enable);
+    public void installExistingPackageForAllUsers(Context context, String packageName);
 
     public boolean systemIsDebuggable();
     public PackageInfo getPackageInfoForProvider(WebViewProviderInfo configInfo)
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java
index 27c80c4..596de68 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl2.java
@@ -211,14 +211,16 @@
             }
 
             if (repairNeeded) {
-                // We didn't find a valid WebView implementation. Try explicitly re-enabling the
-                // default package for all users in case it was disabled, even if we already did the
-                // one-time migration before. If this actually changes the state, we will see the
-                // PackageManager broadcast shortly and try again.
+                // We didn't find a valid WebView implementation. Try explicitly re-installing and
+                // re-enabling the default package for all users in case it was disabled, even if we
+                // already did the one-time migration before. If this actually changes the state, we
+                // will see the PackageManager broadcast shortly and try again.
                 Slog.w(
                         TAG,
-                        "No provider available for all users, trying to enable "
+                        "No provider available for all users, trying to install and enable "
                                 + mDefaultProvider.packageName);
+                mSystemInterface.installExistingPackageForAllUsers(
+                        mContext, mDefaultProvider.packageName);
                 mSystemInterface.enablePackageForAllUsers(
                         mContext, mDefaultProvider.packageName, true);
             }
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 44a0547..d08e272 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -304,9 +304,9 @@
     Surface forceShowMagnifierSurface(int displayId) {
         final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
         if (displayMagnifier != null) {
-            displayMagnifier.mMagnifedViewport.mWindow.setAlpha(DisplayMagnifier.MagnifiedViewport
+            displayMagnifier.mMagnifiedViewport.mWindow.setAlpha(DisplayMagnifier.MagnifiedViewport
                     .ViewportWindow.AnimationController.MAX_ALPHA);
-            return displayMagnifier.mMagnifedViewport.mWindow.mSurface;
+            return displayMagnifier.mMagnifiedViewport.mWindow.mSurface;
         }
         return null;
     }
@@ -463,6 +463,10 @@
     }
 
     void drawMagnifiedRegionBorderIfNeeded(int displayId) {
+        if (Flags.magnificationAlwaysDrawFullscreenBorder()) {
+            return;
+        }
+
         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
             mAccessibilityTracing.logTrace(
                     TAG + ".drawMagnifiedRegionBorderIfNeeded",
@@ -614,7 +618,7 @@
 
         private final Context mDisplayContext;
         private final WindowManagerService mService;
-        private final MagnifiedViewport mMagnifedViewport;
+        private final MagnifiedViewport mMagnifiedViewport;
         private final Handler mHandler;
         private final DisplayContent mDisplayContent;
         private final Display mDisplay;
@@ -649,7 +653,8 @@
             mDisplayContent = displayContent;
             mDisplay = display;
             mHandler = new MyHandler(mService.mH.getLooper());
-            mMagnifedViewport = new MagnifiedViewport();
+            mMagnifiedViewport = Flags.magnificationAlwaysDrawFullscreenBorder()
+                    ? null : new MagnifiedViewport();
             mAccessibilityTracing =
                     AccessibilityController.getAccessibilityControllerInternal(mService);
             mLongAnimationDuration = mDisplayContext.getResources().getInteger(
@@ -692,7 +697,9 @@
                 mMagnificationSpec.clear();
             }
 
-            mMagnifedViewport.setShowMagnifiedBorderIfNeeded();
+            if (!Flags.magnificationAlwaysDrawFullscreenBorder()) {
+                mMagnifiedViewport.setShowMagnifiedBorderIfNeeded();
+            }
         }
 
         void setFullscreenMagnificationActivated(boolean activated) {
@@ -701,8 +708,10 @@
                         FLAGS_MAGNIFICATION_CALLBACK, "activated=" + activated);
             }
             mIsFullscreenMagnificationActivated = activated;
-            mMagnifedViewport.setMagnifiedRegionBorderShown(activated, true);
-            mMagnifedViewport.showMagnificationBoundsIfNeeded();
+            if (!Flags.magnificationAlwaysDrawFullscreenBorder()) {
+                mMagnifiedViewport.setMagnifiedRegionBorderShown(activated, true);
+                mMagnifiedViewport.showMagnificationBoundsIfNeeded();
+            }
         }
 
         boolean isFullscreenMagnificationActivated() {
@@ -737,7 +746,9 @@
             }
 
             recomputeBounds();
-            mMagnifedViewport.onDisplaySizeChanged();
+            if (!Flags.magnificationAlwaysDrawFullscreenBorder()) {
+                mMagnifiedViewport.onDisplaySizeChanged();
+            }
             mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_DISPLAY_SIZE_CHANGED);
         }
 
@@ -901,7 +912,10 @@
             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
                 mAccessibilityTracing.logTrace(LOG_TAG + ".destroy", FLAGS_MAGNIFICATION_CALLBACK);
             }
-            mMagnifedViewport.destroyWindow();
+
+            if (!Flags.magnificationAlwaysDrawFullscreenBorder()) {
+                mMagnifiedViewport.destroyWindow();
+            }
         }
 
         void drawMagnifiedRegionBorderIfNeeded() {
@@ -909,7 +923,10 @@
                 mAccessibilityTracing.logTrace(LOG_TAG + ".drawMagnifiedRegionBorderIfNeeded",
                         FLAGS_MAGNIFICATION_CALLBACK);
             }
-            mMagnifedViewport.drawWindowIfNeeded();
+
+            if (!Flags.magnificationAlwaysDrawFullscreenBorder()) {
+                mMagnifiedViewport.drawWindowIfNeeded();
+            }
         }
 
         void recomputeBounds() {
@@ -1006,14 +1023,16 @@
             }
             visibleWindows.clear();
 
-            mMagnifedViewport.intersectWithDrawBorderInset(screenWidth, screenHeight);
-
+            if (!Flags.magnificationAlwaysDrawFullscreenBorder()) {
+                mMagnifiedViewport.intersectWithDrawBorderInset(screenWidth, screenHeight);
+            }
 
             final boolean magnifiedChanged =
                     !mOldMagnificationRegion.equals(mMagnificationRegion);
             if (magnifiedChanged) {
-                mMagnifedViewport.updateBorderDrawingStatus(screenWidth, screenHeight);
-
+                if (!Flags.magnificationAlwaysDrawFullscreenBorder()) {
+                    mMagnifiedViewport.updateBorderDrawingStatus(screenWidth, screenHeight);
+                }
                 mOldMagnificationRegion.set(mMagnificationRegion);
                 final SomeArgs args = SomeArgs.obtain();
                 args.arg1 = Region.obtain(mMagnificationRegion);
@@ -1070,7 +1089,9 @@
         }
 
         void dump(PrintWriter pw, String prefix) {
-            mMagnifedViewport.dump(pw, prefix);
+            if (!Flags.magnificationAlwaysDrawFullscreenBorder()) {
+                mMagnifiedViewport.dump(pw, prefix);
+            }
         }
 
         private final class MagnifiedViewport {
@@ -1079,7 +1100,7 @@
             private final int mHalfBorderWidth;
             private final int mDrawBorderInset;
 
-            private final ViewportWindow mWindow;
+            @Nullable private final ViewportWindow mWindow;
 
             private boolean mFullRedrawNeeded;
 
@@ -1138,9 +1159,9 @@
             void onDisplaySizeChanged() {
                 // If fullscreen magnification is activated, hide the border immediately so
                 // the user does not see strange artifacts during display size changed caused by
-                // rotation or folding/unfolding the device. In the rotation case, the screenshot
-                // used for rotation already has the border. After the rotation is complete
-                // we will show the border.
+                // rotation or folding/unfolding the device. In the rotation case, the
+                // screenshot used for rotation already has the border. After the rotation is
+                // completed we will show the border.
                 if (isFullscreenMagnificationActivated()) {
                     setMagnifiedRegionBorderShown(false, false);
                     final long delay = (long) (mLongAnimationDuration
@@ -1173,6 +1194,8 @@
                 mWindow.dump(pw, prefix);
             }
 
+            // TODO(291891390): Remove this class when we clean up the flag
+            //  magnificationAlwaysDrawFullscreenBorder
             private final class ViewportWindow implements Runnable {
                 private static final String SURFACE_TITLE = "Magnification Overlay";
 
@@ -1467,6 +1490,9 @@
             public static final int MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED = 1;
             public static final int MESSAGE_NOTIFY_USER_CONTEXT_CHANGED = 3;
             public static final int MESSAGE_NOTIFY_DISPLAY_SIZE_CHANGED = 4;
+
+            // TODO(291891390): Remove this field when we clean up the flag
+            //  magnificationAlwaysDrawFullscreenBorder
             public static final int MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED = 5;
             public static final int MESSAGE_NOTIFY_IME_WINDOW_VISIBILITY_CHANGED = 6;
 
@@ -1495,7 +1521,9 @@
                     case MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED : {
                         synchronized (mService.mGlobalLock) {
                             if (isFullscreenMagnificationActivated()) {
-                                mMagnifedViewport.setMagnifiedRegionBorderShown(true, true);
+                                if (!Flags.magnificationAlwaysDrawFullscreenBorder()) {
+                                    mMagnifiedViewport.setMagnifiedRegionBorderShown(true, true);
+                                }
                                 mService.scheduleAnimationLocked();
                             }
                         }
diff --git a/services/core/java/com/android/server/wm/ActivityAssistInfo.java b/services/core/java/com/android/server/wm/ActivityAssistInfo.java
index 3b91780..2dc0046 100644
--- a/services/core/java/com/android/server/wm/ActivityAssistInfo.java
+++ b/services/core/java/com/android/server/wm/ActivityAssistInfo.java
@@ -30,12 +30,14 @@
     private final IBinder mAssistToken;
     private final int mTaskId;
     private final ComponentName mComponentName;
+    private final int mUserId;
 
     public ActivityAssistInfo(ActivityRecord activityRecord) {
         this.mActivityToken = activityRecord.token;
         this.mAssistToken = activityRecord.assistToken;
         this.mTaskId = activityRecord.getTask().mTaskId;
         this.mComponentName = activityRecord.mActivityComponent;
+        this.mUserId = activityRecord.mUserId;
     }
 
     /** @hide */
@@ -57,4 +59,9 @@
     public ComponentName getComponentName() {
         return mComponentName;
     }
+
+    /** @hide */
+    public int getUserId() {
+        return mUserId;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 2ef34a8..90cff39 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -353,6 +353,7 @@
 import android.view.WindowManager.LayoutParams;
 import android.view.WindowManager.TransitionOldType;
 import android.view.animation.Animation;
+import android.window.ActivityWindowInfo;
 import android.window.ITaskFragmentOrganizer;
 import android.window.RemoteTransition;
 import android.window.SizeConfigurationBuckets;
@@ -519,6 +520,7 @@
     private int mLastReportedDisplayId;
     boolean mLastReportedMultiWindowMode;
     boolean mLastReportedPictureInPictureMode;
+    private final ActivityWindowInfo mLastReportedActivityWindowInfo = new ActivityWindowInfo();
     ActivityRecord resultTo; // who started this entry, so will get our reply
     final String resultWho; // additional identifier for use by resultTo.
     final int requestCode;  // code given by requester (resultTo)
@@ -958,6 +960,7 @@
      */
     private final Configuration mTmpConfig = new Configuration();
     private final Rect mTmpBounds = new Rect();
+    private final ActivityWindowInfo mTmpActivityWindowInfo = new ActivityWindowInfo();
 
     // Token for targeting this activity for assist purposes.
     final Binder assistToken = new Binder();
@@ -1096,6 +1099,12 @@
         pw.println(prefix + "mLastReportedConfigurations:");
         mLastReportedConfiguration.dump(pw, prefix + "  ");
 
+        if (Flags.activityWindowInfoFlag()) {
+            pw.print(prefix);
+            pw.print("mLastReportedActivityWindowInfo=");
+            pw.println(mLastReportedActivityWindowInfo);
+        }
+
         pw.print(prefix); pw.print("CurrentConfiguration="); pw.println(getConfiguration());
         if (!getRequestedOverrideConfiguration().equals(EMPTY)) {
             pw.println(prefix + "RequestedOverrideConfiguration="
@@ -1447,7 +1456,8 @@
         mSizeConfigurations = sizeConfigurations;
     }
 
-    private void scheduleActivityMovedToDisplay(int displayId, Configuration config) {
+    private void scheduleActivityMovedToDisplay(int displayId, @NonNull Configuration config,
+            @NonNull ActivityWindowInfo activityWindowInfo) {
         if (!attachedToProcess()) {
             ProtoLog.w(WM_DEBUG_SWITCH, "Can't report activity moved "
                     + "to display - client not running, activityRecord=%s, displayId=%d",
@@ -1460,7 +1470,7 @@
                     config);
 
             mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(),
-                    MoveToDisplayItem.obtain(token, displayId, config));
+                    MoveToDisplayItem.obtain(token, displayId, config, activityWindowInfo));
         } catch (RemoteException e) {
             // If process died, whatever.
         }
@@ -3150,6 +3160,30 @@
         }
     }
 
+    /**
+     * This is different from {@link #isEmbedded()}.
+     * {@link #isEmbedded()} is {@code true} when any of the parent {@link TaskFragment} is created
+     * by a {@link android.window.TaskFragmentOrganizer}, while this method is {@code true} when
+     * the parent {@link TaskFragment} is embedded and has bounds override that does not fill the
+     * leaf {@link Task}.
+     */
+    boolean isEmbeddedInHostContainer() {
+        final TaskFragment taskFragment = getOrganizedTaskFragment();
+        return taskFragment != null && taskFragment.isEmbeddedWithBoundsOverride();
+    }
+
+    @NonNull
+    ActivityWindowInfo getActivityWindowInfo() {
+        if (!Flags.activityWindowInfoFlag() || !isAttached()) {
+            return mTmpActivityWindowInfo;
+        }
+        mTmpActivityWindowInfo.set(
+                isEmbeddedInHostContainer(),
+                getTask().getBounds(),
+                getTaskFragment().getBounds());
+        return mTmpActivityWindowInfo;
+    }
+
     @Override
     @Nullable
     TaskDisplayArea getDisplayArea() {
@@ -3550,7 +3584,7 @@
             IBinder callerToken = new Binder();
             if (android.security.Flags.contentUriPermissionApis()) {
                 try {
-                    resultTo.computeCallerInfo(callerToken, intent, this.getUid(),
+                    resultTo.computeCallerInfo(callerToken, resultData, this.getUid(),
                             mAtmService.getPackageManager().getNameForUid(this.getUid()),
                             /* isShareIdentityEnabled */ false);
                     // Result callers cannot share their identity via
@@ -8213,6 +8247,12 @@
         mLastReportedConfiguration.setConfiguration(global, override);
     }
 
+    void setLastReportedActivityWindowInfo(@NonNull ActivityWindowInfo activityWindowInfo) {
+        if (Flags.activityWindowInfoFlag()) {
+            mLastReportedActivityWindowInfo.set(activityWindowInfo);
+        }
+    }
+
     @Nullable
     CompatDisplayInsets getCompatDisplayInsets() {
         if (mLetterboxUiController.hasInheritedLetterboxBehavior()) {
@@ -9760,8 +9800,10 @@
 
         // Update last reported values.
         final Configuration newMergedOverrideConfig = getMergedOverrideConfiguration();
+        final ActivityWindowInfo newActivityWindowInfo = getActivityWindowInfo();
 
         setLastReportedConfiguration(getProcessGlobalConfiguration(), newMergedOverrideConfig);
+        setLastReportedActivityWindowInfo(newActivityWindowInfo);
 
         if (mState == INITIALIZING) {
             // No need to relaunch or schedule new config for activity that hasn't been launched
@@ -9778,7 +9820,8 @@
             // There are no significant differences, so we won't relaunch but should still deliver
             // the new configuration to the client process.
             if (displayChanged) {
-                scheduleActivityMovedToDisplay(newDisplayId, newMergedOverrideConfig);
+                scheduleActivityMovedToDisplay(newDisplayId, newMergedOverrideConfig,
+                        newActivityWindowInfo);
             } else {
                 scheduleConfigurationChanged(newMergedOverrideConfig);
             }
@@ -9845,7 +9888,8 @@
         // changes is always sent to all processes when they happen so it can just use whatever
         // system level configuration it last got.
         if (displayChanged) {
-            scheduleActivityMovedToDisplay(newDisplayId, newMergedOverrideConfig);
+            scheduleActivityMovedToDisplay(newDisplayId, newMergedOverrideConfig,
+                    newActivityWindowInfo);
         } else {
             scheduleConfigurationChanged(newMergedOverrideConfig);
         }
@@ -10020,7 +10064,7 @@
                     pendingResults, pendingNewIntents, configChangeFlags,
                     new MergedConfiguration(getProcessGlobalConfiguration(),
                             getMergedOverrideConfiguration()),
-                    preserveWindow);
+                    preserveWindow, getActivityWindowInfo());
             final ActivityLifecycleItem lifecycleItem;
             if (andResume) {
                 lifecycleItem = ResumeActivityItem.obtain(token, isTransitionForward(),
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 066d262..c137c54 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1548,6 +1548,8 @@
                 result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
                         startFlags, options, inTask, inTaskFragment, balVerdict,
                         intentGrants, realCallingUid);
+            } catch (Exception ex) {
+                Slog.e(TAG, "Exception on startActivityInner", ex);
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
                 startedActivityRootTask = handleStartResult(r, options, result, newTransition,
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 4a5b221..c088118 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -822,4 +822,7 @@
      */
     public abstract void unregisterCompatScaleProvider(
             @CompatScaleProvider.CompatScaleModeOrderId int id);
+
+    /** Returns whether assist data is allowed. */
+    public abstract boolean isAssistDataAllowed();
 }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 24c8ebb..218b751 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -2505,6 +2505,11 @@
         userId = handleIncomingUser(Binder.getCallingPid(), callingUid, userId, "getRecentTasks");
         final boolean allowed = isGetTasksAllowed("getRecentTasks", Binder.getCallingPid(),
                 callingUid);
+        if (!mAmInternal.isUserRunning(userId, ActivityManager.FLAG_AND_UNLOCKED)) {
+            Slog.i(TAG, "User " + userId + " is locked. Cannot load recents");
+            return ParceledListSlice.emptyList();
+        }
+        mRecentTasks.loadRecentTasksIfNeeded(userId);
         synchronized (mGlobalLock) {
             return mRecentTasks.getRecentTasks(maxNum, flags, allowed, userId, callingUid);
         }
@@ -6018,6 +6023,10 @@
         public int startActivityWithScreenshot(@NonNull Intent intent,
                 @NonNull String callingPackage, int callingUid, int callingPid,
                 @Nullable IBinder resultTo, @Nullable Bundle options, int userId) {
+            userId = getActivityStartController().checkTargetUser(userId,
+                    false /* validateIncomingUser */, Binder.getCallingPid(),
+                    Binder.getCallingUid(), "startActivityWithScreenshot");
+
             return getActivityStartController()
                     .obtainStarter(intent, "startActivityWithScreenshot")
                     .setCallingUid(callingUid)
@@ -7056,11 +7065,9 @@
 
         @Override
         public void loadRecentTasksForUser(int userId) {
-            synchronized (mGlobalLock) {
-                mRecentTasks.loadUserRecentsLocked(userId);
-                // TODO renaming the methods(?)
-                mPackageConfigPersister.loadUserPackages(userId);
-            }
+            // This runs on android.fg thread when the user is unlocking.
+            mRecentTasks.loadRecentTasksIfNeeded(userId);
+            mPackageConfigPersister.loadUserPackages(userId);
         }
 
         @Override
@@ -7344,6 +7351,11 @@
                 @CompatScaleProvider.CompatScaleModeOrderId int id) {
             ActivityTaskManagerService.this.unregisterCompatScaleProvider(id);
         }
+
+        @Override
+        public boolean isAssistDataAllowed() {
+            return ActivityTaskManagerService.this.isAssistDataAllowed();
+        }
     }
 
     static boolean isPip2ExperimentEnabled() {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 09f5eda..aefa777 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -138,6 +138,7 @@
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 import android.view.Display;
+import android.window.ActivityWindowInfo;
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
@@ -909,6 +910,9 @@
                 final Configuration overrideConfig = r.getMergedOverrideConfiguration();
                 r.setLastReportedConfiguration(procConfig, overrideConfig);
 
+                final ActivityWindowInfo activityWindowInfo = r.getActivityWindowInfo();
+                r.setLastReportedActivityWindowInfo(activityWindowInfo);
+
                 logIfTransactionTooLarge(r.intent, r.getSavedState());
 
                 final TaskFragment organizedTaskFragment = r.getOrganizedTaskFragment();
@@ -931,7 +935,7 @@
                         results, newIntents, r.takeSceneTransitionInfo(), isTransitionForward,
                         proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController,
                         r.shareableActivityToken, r.getLaunchedFromBubble(), fragmentToken,
-                        r.initialCallerInfoAccessToken);
+                        r.initialCallerInfoAccessToken, activityWindowInfo);
 
                 // Set desired final state.
                 final ActivityLifecycleItem lifecycleItem;
@@ -1889,7 +1893,7 @@
         // Check that we aren't reparenting to the same root task that the task is already in
         if (prevRootTask != null && prevRootTask.mTaskId == rootTaskId) {
             Slog.w(TAG, "Can not reparent to same root task, task=" + task
-                    + " already in rootTaskId=" + rootTaskId);
+                    + " already in rootTaskId=" + rootTaskId + " by " + Debug.getCallers(8));
             return prevRootTask;
         }
 
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 939cf1a..1a63f14 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -137,7 +137,6 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.policy.TransitionAnimation;
-import com.android.internal.protolog.ProtoLogImpl;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.DumpUtils.Dump;
 import com.android.internal.util.function.pooled.PooledLambda;
@@ -248,7 +247,7 @@
         mHandler = new Handler(service.mH.getLooper());
         mDisplayContent = displayContent;
         mTransitionAnimation = new TransitionAnimation(
-                context, ProtoLogImpl.isEnabled(WM_DEBUG_ANIM), TAG);
+                context, ProtoLog.isEnabled(WM_DEBUG_ANIM), TAG);
 
         mGridLayoutRecentsEnabled = SystemProperties.getBoolean("ro.recents.grid", false);
 
diff --git a/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java b/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java
index 1dc9493..f11d6ec 100644
--- a/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java
@@ -16,8 +16,6 @@
 
 package com.android.server.wm;
 
-import static android.util.DisplayMetrics.DENSITY_DEFAULT;
-
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
 
@@ -30,7 +28,6 @@
 
 import com.android.server.wm.LaunchParamsController.LaunchParamsModifier;
 import com.android.wm.shell.Flags;
-
 /**
  * The class that defines default launch params for tasks in desktop mode
  */
@@ -44,12 +41,9 @@
     private static final boolean ENABLE_DESKTOP_WINDOWING = Flags.enableDesktopWindowing();
     private static final boolean DESKTOP_MODE_PROTO2_SUPPORTED =
             SystemProperties.getBoolean("persist.wm.debug.desktop_mode_2", false);
-    // Override default freeform task width when desktop mode is enabled. In dips.
-    private static final int DESKTOP_MODE_DEFAULT_WIDTH_DP = SystemProperties.getInt(
-            "persist.wm.debug.desktop_mode.default_width", 840);
-    // Override default freeform task height when desktop mode is enabled. In dips.
-    private static final int DESKTOP_MODE_DEFAULT_HEIGHT_DP = SystemProperties.getInt(
-            "persist.wm.debug.desktop_mode.default_height", 630);
+    public static final float DESKTOP_MODE_INITIAL_BOUNDS_SCALE =
+            SystemProperties
+                    .getInt("persist.wm.debug.desktop_mode_initial_bounds_scale", 75) / 100f;
 
     private StringBuilder mLogBuilder;
 
@@ -108,23 +102,29 @@
             return RESULT_SKIP;
         }
 
-        // Update width and height with default desktop mode values
-        float density = (float) task.getConfiguration().densityDpi / DENSITY_DEFAULT;
-        final int width = (int) (DESKTOP_MODE_DEFAULT_WIDTH_DP * density + 0.5f);
-        final int height = (int) (DESKTOP_MODE_DEFAULT_HEIGHT_DP * density + 0.5f);
-        outParams.mBounds.right = width;
-        outParams.mBounds.bottom = height;
-
-        // Center the task in window bounds
-        Rect windowBounds = task.getWindowConfiguration().getBounds();
-        outParams.mBounds.offset(windowBounds.centerX() - outParams.mBounds.centerX(),
-                windowBounds.centerY() - outParams.mBounds.centerY());
+        calculateAndCentreInitialBounds(task, outParams);
 
         appendLog("setting desktop mode task bounds to %s", outParams.mBounds);
 
         return RESULT_DONE;
     }
 
+    /**
+     * Calculates the initial height and width of a task in desktop mode and centers it within the
+     * window bounds.
+     */
+    private void calculateAndCentreInitialBounds(Task task,
+            LaunchParamsController.LaunchParams outParams) {
+        // TODO(b/319819547): Account for app constraints so apps do not become letterboxed
+        final Rect windowBounds = task.getDisplayArea().getBounds();
+        final int width = (int) (windowBounds.width() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
+        final int height = (int) (windowBounds.height() * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
+        outParams.mBounds.right = width;
+        outParams.mBounds.bottom = height;
+        outParams.mBounds.offset(windowBounds.centerX() - outParams.mBounds.centerX(),
+                windowBounds.centerY() - outParams.mBounds.centerY());
+    }
+
     private void initLogBuilder(Task task, ActivityRecord activity) {
         if (DEBUG) {
             mLogBuilder = new StringBuilder(
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 5cf9acd..7f3df95 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -47,6 +47,7 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_UNRESTRICTED_GESTURE_EXCLUSION;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
@@ -1533,9 +1534,19 @@
         // Check the windows that overlap with system bars to determine system bars' appearance.
         if ((appWindow && attached == null && attrs.isFullscreen())
                 || attrs.type == TYPE_VOICE_INTERACTION) {
-            // Record the top-fullscreen-app-window which will be used to determine system UI
+
+            // If this is the exiting starting window, don't let it control the system bars.
+            // The app window behind it should be the controlling window instead. Reason: when an
+            // activity starts another activity behind a starting window, the app window of the
+            // first activity will lose the window focus. And then mTopFullscreenOpaqueWindowState
+            // will control the system bars. The logic here is to let first app window keep
+            // controlling system bars until the second app window is ready.
+            final boolean exitingStartingWindow =
+                    attrs.type == TYPE_APPLICATION_STARTING && win.mAnimatingExit;
+
+            // Record the top-fullscreen-app-window which will be used to determine the system UI
             // controlling window.
-            if (mTopFullscreenOpaqueWindowState == null) {
+            if (mTopFullscreenOpaqueWindowState == null && !exitingStartingWindow) {
                 mTopFullscreenOpaqueWindowState = win;
             }
 
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index b68e67e..34ea4ac 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -18,6 +18,7 @@
 
 import static android.view.View.DRAG_FLAG_GLOBAL;
 import static android.view.View.DRAG_FLAG_GLOBAL_SAME_APPLICATION;
+import static android.view.View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG;
 
 import static com.android.input.flags.Flags.enablePointerChoreographer;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
@@ -373,8 +374,11 @@
     boolean notifyUnhandledDrop(DragEvent dropEvent, String reason) {
         final boolean isLocalDrag =
                 (mDragState.mFlags & (DRAG_FLAG_GLOBAL_SAME_APPLICATION | DRAG_FLAG_GLOBAL)) == 0;
+        final boolean shouldDelegateUnhandledDrag =
+                (mDragState.mFlags & DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG) != 0;
         if (!com.android.window.flags.Flags.delegateUnhandledDrags()
                 || mGlobalDragListener == null
+                || !shouldDelegateUnhandledDrag
                 || isLocalDrag) {
             // Skip if the flag is disabled, there is no unhandled-drag listener, or if this is a
             // purely local drag
diff --git a/services/core/java/com/android/server/wm/OWNERS b/services/core/java/com/android/server/wm/OWNERS
index e06f215..79eb0dc 100644
--- a/services/core/java/com/android/server/wm/OWNERS
+++ b/services/core/java/com/android/server/wm/OWNERS
@@ -24,3 +24,5 @@
 per-file Background*Start* = file:/BAL_OWNERS
 per-file Background*Start* = ogunwale@google.com, louischang@google.com
 
+# File related to activity callers
+per-file ActivityCallerState.java = file:/core/java/android/app/COMPONENT_CALLER_OWNERS
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index e027eb6..dd14642 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -16,7 +16,6 @@
 
 package com.android.server.wm;
 
-import static android.app.ActivityManager.FLAG_AND_UNLOCKED;
 import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
 import static android.app.ActivityManager.RECENT_WITH_EXCLUDED;
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
@@ -69,6 +68,7 @@
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.ArraySet;
+import android.util.IntArray;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -89,9 +89,9 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * Class for managing the recent tasks list. The list is ordered by most recent (index 0) to the
@@ -167,8 +167,9 @@
 
     /**
      * Mapping of user id -> whether recent tasks have been loaded for that user.
+     * The AtomicBoolean per user will be locked when reading persisted task from storage.
      */
-    private final SparseBooleanArray mUsersWithRecentsLoaded = new SparseBooleanArray(
+    private final SparseArray<AtomicBoolean> mUsersWithRecentsLoaded = new SparseArray<>(
             DEFAULT_INITIAL_CAPACITY);
 
     /**
@@ -481,29 +482,49 @@
 
     /**
      * Loads the persistent recentTasks for {@code userId} into this list from persistent storage.
-     * Does nothing if they are already loaded.
-     *
-     * @param userId the user Id
+     * Does nothing if they are already loaded. This may perform IO operation, so the caller should
+     * not hold a lock.
      */
-    void loadUserRecentsLocked(int userId) {
-        if (mUsersWithRecentsLoaded.get(userId)) {
-            // User already loaded, return early
-            return;
-        }
-
-        // Load the task ids if not loaded.
-        loadPersistedTaskIdsForUserLocked(userId);
-
-        // Check if any tasks are added before recents is loaded
-        final SparseBooleanArray preaddedTasks = new SparseBooleanArray();
-        for (final Task task : mTasks) {
-            if (task.mUserId == userId && shouldPersistTaskLocked(task)) {
-                preaddedTasks.put(task.mTaskId, true);
+    void loadRecentTasksIfNeeded(int userId) {
+        AtomicBoolean userLoaded;
+        synchronized (mService.mGlobalLock) {
+            userLoaded = mUsersWithRecentsLoaded.get(userId);
+            if (userLoaded == null) {
+                mUsersWithRecentsLoaded.append(userId, userLoaded = new AtomicBoolean());
             }
         }
+        synchronized (userLoaded) {
+            if (userLoaded.get()) {
+                // The recent tasks of the user are already loaded.
+                return;
+            }
+            // Read task files from storage.
+            final SparseBooleanArray persistedTaskIds =
+                    mTaskPersister.readPersistedTaskIdsFromFileForUser(userId);
+            final TaskPersister.RecentTaskFiles taskFiles = TaskPersister.loadTasksForUser(userId);
+            synchronized (mService.mGlobalLock) {
+                restoreRecentTasksLocked(userId, persistedTaskIds, taskFiles);
+            }
+            userLoaded.set(true);
+        }
+    }
 
-        Slog.i(TAG, "Loading recents for user " + userId + " into memory.");
-        List<Task> tasks = mTaskPersister.restoreTasksForUserLocked(userId, preaddedTasks);
+    /** Restores recent tasks from raw data (the files are already read into memory). */
+    private void restoreRecentTasksLocked(int userId, SparseBooleanArray persistedTaskIds,
+            TaskPersister.RecentTaskFiles taskFiles) {
+        mTaskPersister.setPersistedTaskIds(userId, persistedTaskIds);
+        mPersistedTaskIds.put(userId, persistedTaskIds.clone());
+        // Check if any tasks are added before recents is loaded.
+        final IntArray existedTaskIds = new IntArray();
+        for (int i = mTasks.size() - 1; i >= 0; i--) {
+            final Task task = mTasks.get(i);
+            if (task.mUserId == userId && shouldPersistTaskLocked(task)) {
+                existedTaskIds.add(task.mTaskId);
+            }
+        }
+        Slog.i(TAG, "Restoring recents for user " + userId);
+        final ArrayList<Task> tasks = mTaskPersister.restoreTasksForUserLocked(userId, taskFiles,
+                existedTaskIds);
 
         // Tasks are ordered from most recent to least recent. Update the last active time to be
         // in sync with task recency when device reboots, so the most recent task has the
@@ -516,37 +537,34 @@
 
         mTasks.addAll(tasks);
         cleanupLocked(userId);
-        mUsersWithRecentsLoaded.put(userId, true);
 
         // If we have tasks added before loading recents, we need to update persistent task IDs.
-        if (preaddedTasks.size() > 0) {
+        if (existedTaskIds.size() > 0) {
             syncPersistentTaskIdsLocked();
         }
     }
 
-    private void loadPersistedTaskIdsForUserLocked(int userId) {
-        // An empty instead of a null set here means that no persistent taskIds were present
-        // on file when we loaded them.
-        if (mPersistedTaskIds.get(userId) == null) {
-            mPersistedTaskIds.put(userId, mTaskPersister.loadPersistedTaskIdsForUser(userId));
-            Slog.i(TAG, "Loaded persisted task ids for user " + userId);
-        }
+    private boolean isRecentTasksLoaded(int userId) {
+        final AtomicBoolean userLoaded = mUsersWithRecentsLoaded.get(userId);
+        return userLoaded != null && userLoaded.get();
     }
 
     /**
      * @return whether the {@param taskId} is currently in use for the given user.
      */
     boolean containsTaskId(int taskId, int userId) {
-        loadPersistedTaskIdsForUserLocked(userId);
-        return mPersistedTaskIds.get(userId).get(taskId);
+        final SparseBooleanArray taskIds = mPersistedTaskIds.get(userId);
+        return taskIds != null && taskIds.get(taskId);
     }
 
-    /**
-     * @return all the task ids for the user with the given {@param userId}.
-     */
-    SparseBooleanArray getTaskIdsForUser(int userId) {
-        loadPersistedTaskIdsForUserLocked(userId);
-        return mPersistedTaskIds.get(userId);
+    /** Returns all the task ids for the user from {@link #usersWithRecentsLoadedLocked}. */
+    SparseBooleanArray getTaskIdsForLoadedUser(int loadedUserId) {
+        final SparseBooleanArray taskIds = mPersistedTaskIds.get(loadedUserId);
+        if (taskIds == null) {
+            Slog.wtf(TAG, "Loaded user without loaded tasks, userId=" + loadedUserId);
+            return new SparseBooleanArray();
+        }
+        return taskIds;
     }
 
     /**
@@ -565,7 +583,7 @@
     private void syncPersistentTaskIdsLocked() {
         for (int i = mPersistedTaskIds.size() - 1; i >= 0; i--) {
             int userId = mPersistedTaskIds.keyAt(i);
-            if (mUsersWithRecentsLoaded.get(userId)) {
+            if (isRecentTasksLoaded(userId)) {
                 // Recents are loaded only after task ids are loaded. Therefore, the set of taskids
                 // referenced here should not be null.
                 mPersistedTaskIds.valueAt(i).clear();
@@ -621,7 +639,7 @@
         int len = 0;
         for (int i = 0; i < usersWithRecentsLoaded.length; i++) {
             int userId = mUsersWithRecentsLoaded.keyAt(i);
-            if (mUsersWithRecentsLoaded.valueAt(i)) {
+            if (mUsersWithRecentsLoaded.valueAt(i).get()) {
                 usersWithRecentsLoaded[len++] = userId;
             }
         }
@@ -639,7 +657,7 @@
      * @param userId the id of the user
      */
     void unloadUserDataFromMemoryLocked(int userId) {
-        if (mUsersWithRecentsLoaded.get(userId)) {
+        if (isRecentTasksLoaded(userId)) {
             Slog.i(TAG, "Unloading recents for user " + userId + " from memory.");
             mUsersWithRecentsLoaded.delete(userId);
             removeTasksForUserLocked(userId);
@@ -922,11 +940,6 @@
         return mService.mAmInternal.getCurrentProfileIds();
     }
 
-    @VisibleForTesting
-    boolean isUserRunning(int userId, int flags) {
-        return mService.mAmInternal.isUserRunning(userId, flags);
-    }
-
     /**
      * @return the list of recent tasks for presentation.
      */
@@ -942,13 +955,6 @@
     private ArrayList<ActivityManager.RecentTaskInfo> getRecentTasksImpl(int maxNum, int flags,
             boolean getTasksAllowed, int userId, int callingUid) {
         final boolean withExcluded = (flags & RECENT_WITH_EXCLUDED) != 0;
-
-        if (!isUserRunning(userId, FLAG_AND_UNLOCKED)) {
-            Slog.i(TAG, "user " + userId + " is still locked. Cannot load recents");
-            return new ArrayList<>();
-        }
-        loadUserRecentsLocked(userId);
-
         final Set<Integer> includedUsers = getProfileIds(userId);
         includedUsers.add(Integer.valueOf(userId));
 
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index a98b9f7..3ef6eeb 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -44,7 +44,6 @@
 import android.view.WindowManager;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.ProtoLogImpl;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.FastPrintWriter;
 import com.android.server.wm.SurfaceAnimator.AnimationType;
@@ -210,7 +209,7 @@
                 Slog.e(TAG, "Failed to start remote animation", e);
                 onAnimationFinished();
             }
-            if (ProtoLogImpl.isEnabled(WM_DEBUG_REMOTE_ANIMATIONS)) {
+            if (ProtoLog.isEnabled(WM_DEBUG_REMOTE_ANIMATIONS)) {
                 ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation(): Notify animation start:");
                 writeStartDebugStatement();
             }
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index b562ccf..07a03eb 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2158,7 +2158,11 @@
                     organizedTf.mClearedTaskFragmentForPip = true;
                 }
 
-                transitionController.collect(rootTask);
+                if (isPip2ExperimentEnabled()) {
+                    transitionController.collectExistenceChange(rootTask);
+                } else {
+                    transitionController.collect(rootTask);
+                }
 
                 if (transitionController.isShellTransitionsEnabled()) {
                     // set mode NOW so that when we reparent the activity, it won't be resumed.
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index c3de4d5..d67684c 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -32,7 +32,6 @@
 import android.view.SurfaceControl.Transaction;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.ProtoLogImpl;
 import com.android.internal.protolog.common.ProtoLog;
 
 import java.io.PrintWriter;
@@ -193,7 +192,7 @@
             return;
         }
         mAnimation.startAnimation(mLeash, t, type, mInnerAnimationFinishedCallback);
-        if (ProtoLogImpl.isEnabled(WM_DEBUG_ANIM)) {
+        if (ProtoLog.isEnabled(WM_DEBUG_ANIM)) {
             StringWriter sw = new StringWriter();
             PrintWriter pw = new PrintWriter(sw);
             mAnimation.dump(pw, "");
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 2bee095..1353ff0 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3750,8 +3750,7 @@
 
                 // Boost the adjacent TaskFragment for dimmer if needed.
                 final TaskFragment taskFragment = wc.asTaskFragment();
-                if (taskFragment != null && taskFragment.isEmbedded()
-                        && taskFragment.isVisibleRequested()) {
+                if (taskFragment != null && taskFragment.isEmbedded()) {
                     final TaskFragment adjacentTf = taskFragment.getAdjacentTaskFragment();
                     if (adjacentTf != null && adjacentTf.shouldBoostDimmer()) {
                         adjacentTf.assignLayer(t, layer++);
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index 8d054db..24b533a 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -1197,16 +1197,13 @@
         }
     }
 
-    // TODO(b/204399167): change to push the embedded state to the client side
     @Override
     public boolean isActivityEmbedded(IBinder activityToken) {
         synchronized (mGlobalLock) {
             final ActivityRecord activity = ActivityRecord.forTokenLocked(activityToken);
-            if (activity == null) {
-                return false;
-            }
-            final TaskFragment taskFragment = activity.getOrganizedTaskFragment();
-            return taskFragment != null && taskFragment.isEmbeddedWithBoundsOverride();
+            return activity != null
+                    ? activity.isEmbeddedInHostContainer()
+                    : false;
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/TaskPersister.java b/services/core/java/com/android/server/wm/TaskPersister.java
index 5ec0119..d89dc0b 100644
--- a/services/core/java/com/android/server/wm/TaskPersister.java
+++ b/services/core/java/com/android/server/wm/TaskPersister.java
@@ -27,6 +27,7 @@
 import android.os.SystemClock;
 import android.util.ArraySet;
 import android.util.AtomicFile;
+import android.util.IntArray;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -43,20 +44,20 @@
 
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.file.Files;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.List;
 
 /**
  * Persister that saves recent tasks into disk.
@@ -129,11 +130,9 @@
                 ImageWriteQueueItem.class);
     }
 
+    /** Reads task ids from file. This should not be called in lock. */
     @NonNull
-    SparseBooleanArray loadPersistedTaskIdsForUser(int userId) {
-        if (mTaskIdsInFile.get(userId) != null) {
-            return mTaskIdsInFile.get(userId).clone();
-        }
+    SparseBooleanArray readPersistedTaskIdsFromFileForUser(int userId) {
         final SparseBooleanArray persistedTaskIds = new SparseBooleanArray();
         synchronized (mIoLock) {
             BufferedReader reader = null;
@@ -154,11 +153,10 @@
                 IoUtils.closeQuietly(reader);
             }
         }
-        mTaskIdsInFile.put(userId, persistedTaskIds);
-        return persistedTaskIds.clone();
+        Slog.i(TAG, "Loaded persisted task ids for user " + userId);
+        return persistedTaskIds;
     }
 
-
     @VisibleForTesting
     void writePersistedTaskIdsForUser(@NonNull SparseBooleanArray taskIds, int userId) {
         if (userId < 0) {
@@ -183,6 +181,10 @@
         }
     }
 
+    void setPersistedTaskIds(int userId, @NonNull SparseBooleanArray taskIds) {
+        mTaskIdsInFile.put(userId, taskIds);
+    }
+
     void unloadUserDataFromMemory(int userId) {
         mTaskIdsInFile.delete(userId);
     }
@@ -241,7 +243,7 @@
         return item != null ? item.mImage : null;
     }
 
-    private String fileToString(File file) {
+    private static String fileToString(File file) {
         final String newline = System.lineSeparator();
         try {
             BufferedReader reader = new BufferedReader(new FileReader(file));
@@ -272,44 +274,64 @@
         return null;
     }
 
-    List<Task> restoreTasksForUserLocked(final int userId, SparseBooleanArray preaddedTasks) {
-        final ArrayList<Task> tasks = new ArrayList<Task>();
-        ArraySet<Integer> recoveredTaskIds = new ArraySet<Integer>();
-
-        File userTasksDir = getUserTasksDir(userId);
-
-        File[] recentFiles = userTasksDir.listFiles();
+    /** Loads task files from disk. This should not be called in lock. */
+    static RecentTaskFiles loadTasksForUser(int userId) {
+        final ArrayList<RecentTaskFile> taskFiles = new ArrayList<>();
+        final File userTasksDir = getUserTasksDir(userId);
+        final File[] recentFiles = userTasksDir.listFiles();
         if (recentFiles == null) {
-            Slog.e(TAG, "restoreTasksForUserLocked: Unable to list files from " + userTasksDir);
+            Slog.i(TAG, "loadTasksForUser: Unable to list files from " + userTasksDir
+                    + " exists=" + userTasksDir.exists());
+            return new RecentTaskFiles(new File[0], taskFiles);
+        }
+        for (File taskFile : recentFiles) {
+            if (!taskFile.getName().endsWith(TASK_FILENAME_SUFFIX)) {
+                continue;
+            }
+            final int taskId;
+            try {
+                taskId = Integer.parseInt(taskFile.getName().substring(
+                        0 /* beginIndex */,
+                        taskFile.getName().length() - TASK_FILENAME_SUFFIX.length()));
+            } catch (NumberFormatException e) {
+                Slog.w(TAG, "Unexpected task file name", e);
+                continue;
+            }
+            try {
+                taskFiles.add(new RecentTaskFile(taskId, taskFile));
+            } catch (IOException e) {
+                Slog.w(TAG, "Failed to read file: " + fileToString(taskFile), e);
+                taskFile.delete();
+            }
+        }
+        return new RecentTaskFiles(recentFiles, taskFiles);
+    }
+
+    /** Restores tasks from raw bytes (no read storage operation). */
+    ArrayList<Task> restoreTasksForUserLocked(int userId, RecentTaskFiles recentTaskFiles,
+            IntArray existedTaskIds) {
+        final ArrayList<Task> tasks = new ArrayList<>();
+        final ArrayList<RecentTaskFile> taskFiles = recentTaskFiles.mLoadedFiles;
+        if (taskFiles.isEmpty()) {
             return tasks;
         }
 
-        for (int taskNdx = 0; taskNdx < recentFiles.length; ++taskNdx) {
-            File taskFile = recentFiles[taskNdx];
+        final ArraySet<Integer> recoveredTaskIds = new ArraySet<>();
+        for (int taskNdx = 0; taskNdx < taskFiles.size(); ++taskNdx) {
+            final RecentTaskFile recentTask = taskFiles.get(taskNdx);
+            if (existedTaskIds.contains(recentTask.mTaskId)) {
+                Slog.w(TAG, "Task #" + recentTask.mTaskId
+                        + " has already been created, so skip restoring");
+                continue;
+            }
+            final File taskFile = recentTask.mFile;
             if (DEBUG) {
                 Slog.d(TAG, "restoreTasksForUserLocked: userId=" + userId
                         + ", taskFile=" + taskFile.getName());
             }
 
-            if (!taskFile.getName().endsWith(TASK_FILENAME_SUFFIX)) {
-                continue;
-            }
-            try {
-                final int taskId = Integer.parseInt(taskFile.getName().substring(
-                        0 /* beginIndex */,
-                        taskFile.getName().length() - TASK_FILENAME_SUFFIX.length()));
-                if (preaddedTasks.get(taskId, false)) {
-                    Slog.w(TAG, "Task #" + taskId +
-                            " has already been created so we don't restore again");
-                    continue;
-                }
-            } catch (NumberFormatException e) {
-                Slog.w(TAG, "Unexpected task file name", e);
-                continue;
-            }
-
             boolean deleteFile = false;
-            try (InputStream is = new FileInputStream(taskFile)) {
+            try (InputStream is = recentTask.mXmlContent) {
                 final TypedXmlPullParser in = Xml.resolvePullParser(is);
 
                 int event;
@@ -345,7 +367,7 @@
                                 } else if (userId != task.mUserId) {
                                     // Should not happen.
                                     Slog.wtf(TAG, "Task with userId " + task.mUserId + " found in "
-                                            + userTasksDir.getAbsolutePath());
+                                            + taskFile.getAbsolutePath());
                                 } else {
                                     // Looks fine.
                                     mTaskSupervisor.setNextTaskIdForUser(taskId, userId);
@@ -377,7 +399,7 @@
         }
 
         if (!DEBUG) {
-            removeObsoleteFiles(recoveredTaskIds, userTasksDir.listFiles());
+            removeObsoleteFiles(recoveredTaskIds, recentTaskFiles.mUserTaskFiles);
         }
 
         // Fix up task affiliation from taskIds
@@ -456,7 +478,7 @@
         SparseArray<SparseBooleanArray> changedTaskIdsPerUser = new SparseArray<>();
         synchronized (mService.mGlobalLock) {
             for (int userId : mRecentTasks.usersWithRecentsLoadedLocked()) {
-                SparseBooleanArray taskIdsToSave = mRecentTasks.getTaskIdsForUser(userId);
+                SparseBooleanArray taskIdsToSave = mRecentTasks.getTaskIdsForLoadedUser(userId);
                 SparseBooleanArray persistedIdsInFile = mTaskIdsInFile.get(userId);
                 if (persistedIdsInFile != null && persistedIdsInFile.equals(taskIdsToSave)) {
                     continue;
@@ -512,6 +534,30 @@
         return parentDir.isDirectory() || parentDir.mkdir();
     }
 
+    private static class RecentTaskFile {
+        final int mTaskId;
+        final File mFile;
+        final ByteArrayInputStream mXmlContent;
+
+        RecentTaskFile(int taskId, File file) throws IOException {
+            mTaskId = taskId;
+            mFile = file;
+            mXmlContent = new ByteArrayInputStream(Files.readAllBytes(file.toPath()));
+        }
+    }
+
+    static class RecentTaskFiles {
+        /** All files under the user task directory. */
+        final File[] mUserTaskFiles;
+        /** The successfully loaded files. */
+        final ArrayList<RecentTaskFile> mLoadedFiles;
+
+        RecentTaskFiles(File[] userFiles, ArrayList<RecentTaskFile> loadedFiles) {
+            mUserTaskFiles = userFiles;
+            mLoadedFiles = loadedFiles;
+        }
+    }
+
     private static class TaskWriteQueueItem implements PersisterQueue.WriteQueueItem {
         private final ActivityTaskManagerService mService;
         private final Task mTask;
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 001f46d..594043d 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -58,7 +58,6 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.ProtoLogImpl;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.ToBooleanFunction;
 import com.android.server.wallpaper.WallpaperCropper.WallpaperCropUtils;
@@ -336,7 +335,7 @@
         for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
             final WallpaperWindowToken token = mWallpaperTokens.get(i);
             token.setVisibility(false);
-            if (ProtoLogImpl.isEnabled(WM_DEBUG_WALLPAPER) && token.isVisible()) {
+            if (ProtoLog.isEnabled(WM_DEBUG_WALLPAPER) && token.isVisible()) {
                 ProtoLog.d(WM_DEBUG_WALLPAPER,
                         "Hiding wallpaper %s from %s target=%s prev=%s callers=%s",
                         token, winGoingAway, mWallpaperTarget, mPrevWallpaperTarget,
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 61fde5e..fd0289e 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -113,7 +113,6 @@
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.graphics.ColorUtils;
-import com.android.internal.protolog.ProtoLogImpl;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.ToBooleanFunction;
 import com.android.server.wm.SurfaceAnimator.Animatable;
@@ -3410,7 +3409,7 @@
                 // ActivityOption#makeCustomAnimation or WindowManager#overridePendingTransition.
                 a.restrictDuration(MAX_APP_TRANSITION_DURATION);
             }
-            if (ProtoLogImpl.isEnabled(WM_DEBUG_ANIM)) {
+            if (ProtoLog.isEnabled(WM_DEBUG_ANIM)) {
                 ProtoLog.i(WM_DEBUG_ANIM, "Loaded animation %s for %s, duration: %d, stack=%s",
                         a, this, ((a != null) ? a.getDuration() : 0), Debug.getCallers(20));
             }
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 4698b6b..5df2edc 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -1079,4 +1079,10 @@
      * Moves the current focus to the top activity window if the top activity is embedded.
      */
     public abstract boolean moveFocusToTopEmbeddedWindowIfNeeded();
+
+    /**
+     * Returns an instance of {@link ScreenCapture.ScreenshotHardwareBuffer} containing the current
+     * screenshot.
+     */
+    public abstract ScreenCapture.ScreenshotHardwareBuffer takeAssistScreenshot();
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 9b7bc43..c93cc07 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -327,8 +327,8 @@
 import com.android.internal.policy.IKeyguardLockedStateListener;
 import com.android.internal.policy.IShortcutService;
 import com.android.internal.policy.KeyInterceptionInfo;
+import com.android.internal.protolog.LegacyProtoLogImpl;
 import com.android.internal.protolog.ProtoLogGroup;
-import com.android.internal.protolog.ProtoLogImpl;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FastPrintWriter;
@@ -4081,13 +4081,8 @@
         }
     }
 
-    /**
-     * Takes a snapshot of the screen.  In landscape mode this grabs the whole screen.
-     * In portrait mode, it grabs the upper region of the screen based on the vertical dimension
-     * of the target image.
-     */
-    @Override
-    public boolean requestAssistScreenshot(final IAssistDataReceiver receiver) {
+    @Nullable
+    private ScreenCapture.ScreenshotHardwareBuffer takeAssistScreenshot() {
         if (!checkCallingPermission(READ_FRAME_BUFFER, "requestAssistScreenshot()")) {
             throw new SecurityException("Requires READ_FRAME_BUFFER permission");
         }
@@ -4106,24 +4101,34 @@
             }
         }
 
-        final Bitmap bm;
+        final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer;
         if (captureArgs != null) {
             ScreenCapture.SynchronousScreenCaptureListener syncScreenCapture =
                     ScreenCapture.createSyncCaptureListener();
 
             ScreenCapture.captureLayers(captureArgs, syncScreenCapture);
 
-            final ScreenCapture.ScreenshotHardwareBuffer screenshotBuffer =
-                    syncScreenCapture.getBuffer();
-            bm = screenshotBuffer == null ? null : screenshotBuffer.asBitmap();
+            screenshotBuffer = syncScreenCapture.getBuffer();
         } else {
-            bm = null;
+            screenshotBuffer = null;
         }
 
-        if (bm == null) {
+        if (screenshotBuffer == null) {
             Slog.w(TAG_WM, "Failed to take screenshot");
         }
 
+        return screenshotBuffer;
+    }
+
+    /**
+     * Takes a snapshot of the screen.  In landscape mode this grabs the whole screen.
+     * In portrait mode, it grabs the upper region of the screen based on the vertical dimension
+     * of the target image.
+     */
+    @Override
+    public boolean requestAssistScreenshot(final IAssistDataReceiver receiver) {
+        final ScreenCapture.ScreenshotHardwareBuffer shb = takeAssistScreenshot();
+        final Bitmap bm = shb != null ? shb.asBitmap() : null;
         FgThread.getHandler().post(() -> {
             try {
                 receiver.onHandleAssistScreenshot(bm);
@@ -6701,7 +6706,11 @@
 
     private void dumpLogStatus(PrintWriter pw) {
         pw.println("WINDOW MANAGER LOGGING (dumpsys window logging)");
-        pw.println(ProtoLogImpl.getSingleInstance().getStatus());
+        if (android.tracing.Flags.perfettoProtolog()) {
+            pw.println("Deprecated legacy command. Use Perfetto commands instead.");
+            return;
+        }
+        ((LegacyProtoLogImpl) ProtoLog.getSingleInstance()).getStatus();
     }
 
     private void dumpSessionsLocked(PrintWriter pw) {
@@ -8684,6 +8693,12 @@
                 return false;
             }
         }
+
+        @Override
+        public ScreenCapture.ScreenshotHardwareBuffer takeAssistScreenshot() {
+            // WMS.takeAssistScreenshot takes care of the locking.
+            return WindowManagerService.this.takeAssistScreenshot();
+        }
     }
 
     private final class ImeTargetVisibilityPolicyImpl extends ImeTargetVisibilityPolicy {
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index 8fad950..0b29f96 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -48,7 +48,9 @@
 import android.view.ViewDebug;
 
 import com.android.internal.os.ByteTransferPipe;
-import com.android.internal.protolog.ProtoLogImpl;
+import com.android.internal.protolog.LegacyProtoLogImpl;
+import com.android.internal.protolog.common.IProtoLog;
+import com.android.internal.protolog.common.ProtoLog;
 import com.android.server.IoThread;
 import com.android.server.wm.LetterboxConfiguration.LetterboxBackgroundType;
 import com.android.server.wm.LetterboxConfiguration.LetterboxHorizontalReachabilityPosition;
@@ -107,11 +109,19 @@
                     // trace files can be written.
                     return mInternal.mWindowTracing.onShellCommand(this);
                 case "logging":
-                    int result = ProtoLogImpl.getSingleInstance().onShellCommand(this);
-                    if (result != 0) {
-                        pw.println("Not handled, please use "
-                                + "`adb shell dumpsys activity service SystemUIService WMShell` "
-                                + "if you are looking for ProtoLog in WMShell");
+                    IProtoLog instance = ProtoLog.getSingleInstance();
+                    int result = 0;
+                    if (instance instanceof LegacyProtoLogImpl) {
+                        result = ((LegacyProtoLogImpl) instance).onShellCommand(this);
+                        if (result != 0) {
+                            pw.println("Not handled, please use "
+                                    + "`adb shell dumpsys activity service SystemUIService "
+                                    + "WMShell` if you are looking for ProtoLog in WMShell");
+                        }
+                    } else {
+                        result = -1;
+                        pw.println("Command not supported. "
+                                + "Only supported when using legacy ProtoLog.");
                     }
                     return result;
                 case "user-rotation":
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 90f5b62..a7a28c2 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -245,7 +245,6 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.policy.KeyInterceptionInfo;
-import com.android.internal.protolog.ProtoLogImpl;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.FrameworkStatsLog;
 import com.android.internal.util.ToBooleanFunction;
@@ -4681,7 +4680,7 @@
     }
 
     void onExitAnimationDone() {
-        if (ProtoLogImpl.isEnabled(WM_DEBUG_ANIM)) {
+        if (ProtoLog.isEnabled(WM_DEBUG_ANIM)) {
             final AnimationAdapter animationAdapter = mSurfaceAnimator.getAnimation();
             StringWriter sw = new StringWriter();
             if (animationAdapter != null) {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 6428591..7f7c249 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -60,7 +60,6 @@
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
 
-import com.android.internal.protolog.ProtoLogImpl;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.server.policy.WindowManagerPolicy;
 
@@ -584,7 +583,7 @@
                             mWin.mAttrs, attr, TRANSIT_OLD_NONE);
                 }
             }
-            if (ProtoLogImpl.isEnabled(WM_DEBUG_ANIM)) {
+            if (ProtoLog.isEnabled(WM_DEBUG_ANIM)) {
                 ProtoLog.v(WM_DEBUG_ANIM, "applyAnimation: win=%s"
                         + " anim=%d attr=0x%x a=%s transit=%d type=%d isEntrance=%b Callers %s",
                         this, anim, attr, a, transit, mAttrType, isEntrance, Debug.getCallers(20));
diff --git a/services/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java
index 416d042..424d504 100644
--- a/services/core/java/com/android/server/wm/WindowTracing.java
+++ b/services/core/java/com/android/server/wm/WindowTracing.java
@@ -35,7 +35,9 @@
 import android.util.proto.ProtoOutputStream;
 import android.view.Choreographer;
 
-import com.android.internal.protolog.ProtoLogImpl;
+import com.android.internal.protolog.LegacyProtoLogImpl;
+import com.android.internal.protolog.common.IProtoLog;
+import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.util.TraceBuffer;
 
 import java.io.File;
@@ -77,6 +79,8 @@
     private volatile boolean mEnabledLockFree;
     private boolean mScheduled;
 
+    private final IProtoLog mProtoLog;
+
     static WindowTracing createDefaultAndStartLooper(WindowManagerService service,
             Choreographer choreographer) {
         File file = new File(TRACE_FILENAME);
@@ -96,6 +100,7 @@
         mTraceFile = file;
         mBuffer = new TraceBuffer(bufferCapacity);
         setLogLevel(WindowTraceLogLevel.TRIM, null /* pw */);
+        mProtoLog = ProtoLog.getSingleInstance();
     }
 
     void startTrace(@Nullable PrintWriter pw) {
@@ -104,7 +109,6 @@
             return;
         }
         synchronized (mEnabledLock) {
-            ProtoLogImpl.getSingleInstance().startProtoLog(pw);
             logAndPrintln(pw, "Start tracing to " + mTraceFile + ".");
             mBuffer.resetBuffer();
             mEnabled = mEnabledLockFree = true;
@@ -132,7 +136,6 @@
             writeTraceToFileLocked();
             logAndPrintln(pw, "Trace written to " + mTraceFile + ".");
         }
-        ProtoLogImpl.getSingleInstance().stopProtoLog(pw, true);
     }
 
     /**
@@ -152,11 +155,15 @@
             logAndPrintln(pw, "Stop tracing to " + mTraceFile + ". Waiting for traces to flush.");
             writeTraceToFileLocked();
             logAndPrintln(pw, "Trace written to " + mTraceFile + ".");
-            ProtoLogImpl.getSingleInstance().stopProtoLog(pw, true);
+            if (!android.tracing.Flags.perfettoProtolog()) {
+                ((LegacyProtoLogImpl) mProtoLog).stopProtoLog(pw, true);
+            }
             logAndPrintln(pw, "Start tracing to " + mTraceFile + ".");
             mBuffer.resetBuffer();
             mEnabled = mEnabledLockFree = true;
-            ProtoLogImpl.getSingleInstance().startProtoLog(pw);
+            if (!android.tracing.Flags.perfettoProtolog()) {
+                ((LegacyProtoLogImpl) mProtoLog).startProtoLog(pw);
+            }
         }
     }
 
diff --git a/services/core/jni/com_android_server_vibrator_VibratorController.cpp b/services/core/jni/com_android_server_vibrator_VibratorController.cpp
index f5e6c45..f47a59d 100644
--- a/services/core/jni/com_android_server_vibrator_VibratorController.cpp
+++ b/services/core/jni/com_android_server_vibrator_VibratorController.cpp
@@ -370,6 +370,7 @@
         return JNI_FALSE;
     }
     vibrator::Info info = wrapper->getVibratorInfo();
+    info.logFailures();
 
     if (info.capabilities.isOk()) {
         env->CallObjectMethod(vibratorInfoBuilder, sVibratorInfoBuilderClassInfo.setCapabilities,
@@ -443,7 +444,7 @@
     env->CallObjectMethod(vibratorInfoBuilder, sVibratorInfoBuilderClassInfo.setFrequencyProfile,
                           frequencyProfile);
 
-    return info.isFailedLogged("vibratorGetInfo") ? JNI_FALSE : JNI_TRUE;
+    return info.shouldRetry() ? JNI_FALSE : JNI_TRUE;
 }
 
 static const JNINativeMethod method_table[] = {
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
index 9d45cfb..027337f 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerUi.java
@@ -18,7 +18,6 @@
 import static android.credentials.selection.Constants.EXTRA_FINAL_RESPONSE_RECEIVER;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
@@ -161,26 +160,6 @@
      */
     public PendingIntent createPendingIntent(
             RequestInfo requestInfo, ArrayList<ProviderData> providerDataList) {
-        return createPendingIntent(requestInfo, providerDataList, /*forAutofill=*/ false);
-    }
-
-    /**
-     * Creates a {@link PendingIntent} to be used to invoke the credential manager selector UI,
-     * by the calling app process. This intent is invoked from the Autofill flow, when the user
-     * requests to bring up the 'All Options' page of the credential bottom-sheet. When the user
-     * clicks on the pinned entry, the intent will bring up the 'All Options' page of the
-     * bottom-sheet. The provider data list is processed by the credential autofill service for
-     * each autofill id and passed in as an auth extra.
-     *
-     * @param requestInfo            the information about the request
-     */
-    public PendingIntent createPendingIntentForAutofill(RequestInfo requestInfo) {
-        return createPendingIntent(requestInfo, /*providerDataList=*/ null, /*forAutofill=*/ true);
-    }
-
-    private PendingIntent createPendingIntent(
-            RequestInfo requestInfo, @Nullable ArrayList<ProviderData> providerDataList,
-            boolean forAutofill) {
         List<CredentialProviderInfo> allProviders =
                 CredentialProviderInfoFactory.getCredentialProviderServices(
                         mContext,
@@ -196,15 +175,9 @@
                         disabledProvider.getComponentName().flattenToString())).toList();
 
         Intent intent;
-        if (forAutofill) {
-            intent = IntentFactory.createCredentialSelectorIntentForAutofill(
-                    mContext, requestInfo, new ArrayList<>(disabledProviderDataList),
-                    mResultReceiver);
-        } else {
-            intent = IntentFactory.createCredentialSelectorIntent(
-                    mContext, requestInfo, providerDataList,
-                    new ArrayList<>(disabledProviderDataList), mResultReceiver);
-        }
+        intent = IntentFactory.createCredentialSelectorIntent(
+                mContext, requestInfo, providerDataList,
+                new ArrayList<>(disabledProviderDataList), mResultReceiver);
         intent.setAction(UUID.randomUUID().toString());
         //TODO: Create unique pending intent using request code and cancel any pre-existing pending
         // intents
@@ -213,4 +186,21 @@
                 PendingIntent.FLAG_MUTABLE, /*options=*/null,
                 UserHandle.of(mUserId));
     }
+
+    /**
+     * Creates an {@link Intent} to be used to invoke the credential manager selector UI,
+     * by the calling app process. This intent is invoked from the Autofill flow, when the user
+     * requests to bring up the 'All Options' page of the credential bottom-sheet. When the user
+     * clicks on the pinned entry, the intent will bring up the 'All Options' page of the
+     * bottom-sheet. The provider data list is processed by the credential autofill service for
+     * each autofill id and passed in as extras in the pending intent set as authentication
+     * of the pinned entry.
+     *
+     * @param requestInfo            the information about the request
+     */
+    public Intent createIntentForAutofill(RequestInfo requestInfo) {
+        return IntentFactory.createCredentialSelectorIntentForAutofill(
+                mContext, requestInfo, new ArrayList<>(),
+                mResultReceiver);
+    }
 }
diff --git a/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
index 723c52f..3cb98eb 100644
--- a/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.credentials.Constants;
 import android.credentials.CredentialProviderInfo;
 import android.credentials.GetCandidateCredentialsException;
@@ -114,8 +115,7 @@
             return;
         }
 
-        cancelExistingPendingIntent();
-        mPendingIntent = mCredentialManagerUi.createPendingIntentForAutofill(
+        Intent intent = mCredentialManagerUi.createIntentForAutofill(
                 RequestInfo.newGetRequestInfo(
                         mRequestId, mClientRequest, mClientAppInfo.getPackageName(),
                         PermissionUtils.hasPermission(mContext, mClientAppInfo.getPackageName(),
@@ -129,7 +129,7 @@
 
         try {
             invokeClientCallbackSuccess(new GetCandidateCredentialsResponse(
-                    candidateProviderDataList, mPendingIntent));
+                    candidateProviderDataList, intent));
         } catch (RemoteException e) {
             Slog.e(TAG, "Issue while responding to client with error : " + e);
         }
@@ -150,7 +150,8 @@
     @Override
     public void onFinalErrorReceived(ComponentName componentName, String errorType,
             String message) {
-        respondToClientWithErrorAndFinish(errorType, message);
+        Slog.d(TAG, "onFinalErrorReceived");
+        respondToFinalReceiverWithFailureAndFinish(this.mFinalResponseReceiver, errorType, message);
     }
 
     @Override
@@ -163,6 +164,13 @@
             message = "The UI was interrupted - please try again.";
         }
         mRequestSessionMetric.collectFrameworkException(exception);
+        respondToFinalReceiverWithFailureAndFinish(finalResponseReceiver, exception, message);
+    }
+
+    private void respondToFinalReceiverWithFailureAndFinish(
+            ResultReceiver finalResponseReceiver,
+            String exception, String message
+    ) {
         if (finalResponseReceiver != null) {
             Bundle resultData = new Bundle();
             resultData.putStringArray(
@@ -170,16 +178,16 @@
                     new String[] {exception, message});
             finalResponseReceiver.send(Constants.FAILURE_CREDMAN_SELECTOR, resultData);
         } else {
-            respondToClientWithErrorAndFinish(exception, message);
+            Slog.w(TAG, "onUiCancellation called but finalResponseReceiver not found");
         }
+        finishSession(/*propagateCancellation=*/false);
     }
 
     @Override
     public void onUiSelectorInvocationFailure() {
         String exception = GetCandidateCredentialsException.TYPE_NO_CREDENTIAL;
         mRequestSessionMetric.collectFrameworkException(exception);
-        respondToClientWithErrorAndFinish(exception,
-                "No credentials available.");
+        // TODO(): Propagate through final receiver
     }
 
     @Override
diff --git a/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java b/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java
index 21ac9e4..bc8c2b0 100644
--- a/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java
+++ b/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java
@@ -82,7 +82,7 @@
         if (resultData == null) {
             return null;
         }
-        return resultData.getParcelableExtra(
+        return resultData.getSerializableExtra(
                 CredentialProviderService.EXTRA_CREATE_CREDENTIAL_EXCEPTION,
                 CreateCredentialException.class);
     }
@@ -94,7 +94,7 @@
         if (resultData == null) {
             return null;
         }
-        return resultData.getParcelableExtra(
+        return resultData.getSerializableExtra(
                 CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION,
                 GetCredentialException.class);
     }
diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
index fa63bc8..cad9a09 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
@@ -93,7 +93,7 @@
         android.credentials.GetCredentialRequest filteredRequest =
                 filterOptions(providerInfo.getCapabilities(),
                         getRequestSession.mClientRequest,
-                        providerInfo);
+                        providerInfo, getRequestSession.mHybridService);
         if (filteredRequest != null) {
             Map<String, CredentialOption> beginGetOptionToCredentialOptionMap =
                     new HashMap<>();
@@ -129,7 +129,7 @@
         android.credentials.GetCredentialRequest filteredRequest =
                 filterOptions(providerInfo.getCapabilities(),
                         getRequestSession.mClientRequest,
-                        providerInfo);
+                        providerInfo, getRequestSession.mHybridService);
         if (filteredRequest != null) {
             Map<String, CredentialOption> beginGetOptionToCredentialOptionMap =
                     new HashMap<>();
@@ -179,9 +179,19 @@
     private static android.credentials.GetCredentialRequest filterOptions(
             List<String> providerCapabilities,
             android.credentials.GetCredentialRequest clientRequest,
-            CredentialProviderInfo info
-    ) {
+            CredentialProviderInfo info,
+            String hybridService) {
         Slog.i(TAG, "Filtering request options for: " + info.getComponentName());
+        if (android.credentials.flags.Flags.hybridFilterFixEnabled()) {
+            ComponentName hybridComponentName = ComponentName.unflattenFromString(hybridService);
+            if (hybridComponentName != null && hybridComponentName
+                    .equals(info.getComponentName())) {
+                Slog.i(TAG, "Skipping filtering of options for hybrid service");
+                return clientRequest;
+            }
+            Slog.w(TAG, "Could not parse hybrid service while filtering options");
+        }
+
         List<CredentialOption> filteredOptions = new ArrayList<>();
         for (CredentialOption option : clientRequest.getCredentialOptions()) {
             if (providerCapabilities.contains(option.getType())
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java
index e7855bc..c4e2dc8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java
@@ -15,6 +15,10 @@
  */
 package com.android.server.devicepolicy;
 
+import static android.app.admin.DevicePolicyManager.CONTENT_PROTECTION_DISABLED;
+import static android.app.admin.DevicePolicyManager.ContentProtectionPolicy;
+
+import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.admin.DevicePolicyCache;
 import android.app.admin.DevicePolicyManager;
@@ -70,10 +74,14 @@
     /** Maps to {@code ActiveAdmin.mAdminCanGrantSensorsPermissions}. */
     private final AtomicBoolean mCanGrantSensorsPermissions = new AtomicBoolean(false);
 
+    @GuardedBy("mLock")
+    private final SparseIntArray mContentProtectionPolicy = new SparseIntArray();
+
     public void onUserRemoved(int userHandle) {
         synchronized (mLock) {
             mPasswordQuality.delete(userHandle);
             mPermissionPolicy.delete(userHandle);
+            mContentProtectionPolicy.delete(userHandle);
         }
     }
 
@@ -143,6 +151,24 @@
     }
 
     @Override
+    public @ContentProtectionPolicy int getContentProtectionPolicy(@UserIdInt int userId) {
+        synchronized (mLock) {
+            return mContentProtectionPolicy.get(userId, CONTENT_PROTECTION_DISABLED);
+        }
+    }
+
+    /** Update the content protection policy for the given user. */
+    public void setContentProtectionPolicy(@UserIdInt int userId, @Nullable Integer value) {
+        synchronized (mLock) {
+            if (value == null) {
+                mContentProtectionPolicy.delete(userId);
+            } else {
+                mContentProtectionPolicy.put(userId, value);
+            }
+        }
+    }
+
+    @Override
     public boolean canAdminGrantSensorsPermissions() {
         return mCanGrantSensorsPermissions.get();
     }
@@ -178,6 +204,7 @@
             pw.println("Screen capture disallowed users: " + mScreenCaptureDisallowedUsers);
             pw.println("Password quality: " + mPasswordQuality);
             pw.println("Permission policy: " + mPermissionPolicy);
+            pw.println("Content protection policy: " + mContentProtectionPolicy);
             pw.println("Admin can grant sensors permission: " + mCanGrantSensorsPermissions.get());
             pw.print("Shortcuts overrides: ");
             pw.println(mLauncherShortcutOverrides);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 9c48f29..0f97f4a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3633,6 +3633,7 @@
                 userId == UserHandle.USER_SYSTEM ? UserHandle.USER_ALL : userId);
         updatePermissionPolicyCache(userId);
         updateAdminCanGrantSensorsPermissionCache(userId);
+        updateContentProtectionPolicyCache(userId);
 
         final List<PreferentialNetworkServiceConfig> preferentialNetworkServiceConfigs;
         synchronized (getLockObject()) {
@@ -23534,6 +23535,12 @@
         }
     }
 
+    private void updateContentProtectionPolicyCache(@UserIdInt int userId) {
+        mPolicyCache.setContentProtectionPolicy(
+                userId,
+                mDevicePolicyEngine.getResolvedPolicy(PolicyDefinition.CONTENT_PROTECTION, userId));
+    }
+
     @Override
     public ManagedSubscriptionsPolicy getManagedSubscriptionsPolicy() {
         synchronized (getLockObject()) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java b/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java
index df7f308..1000bfa 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/EnterpriseSpecificIdCalculator.java
@@ -53,7 +53,17 @@
         TelephonyManager telephonyService = context.getSystemService(TelephonyManager.class);
         Preconditions.checkState(telephonyService != null, "Unable to access telephony service");
         mImei = telephonyService.getImei(0);
-        mMeid = telephonyService.getMeid(0);
+        String meid;
+        try {
+            meid = telephonyService.getMeid(0);
+        } catch (UnsupportedOperationException doesNotSupportCdma) {
+            // Instead of catching the exception, we could check for FEATURE_TELEPHONY_CDMA.
+            // However that runs the risk of changing a device's existing ESID if on these devices
+            // telephonyService.getMeid() actually returns non-null even when the device does not
+            // declare FEATURE_TELEPHONY_CDMA.
+            meid = null;
+        }
+        mMeid = meid;
         mSerialNumber = Build.getSerial();
         WifiManager wifiManager = context.getSystemService(WifiManager.class);
         Preconditions.checkState(wifiManager != null, "Unable to access WiFi service");
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
index 1247f9002..71facab 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
@@ -359,7 +359,7 @@
             new NoArgsPolicyKey(DevicePolicyIdentifiers.CONTENT_PROTECTION_POLICY),
             new MostRecent<>(),
             POLICY_FLAG_LOCAL_ONLY_POLICY,
-            (Integer value, Context context, Integer userId, PolicyKey policyKey) -> true,
+            PolicyEnforcerCallbacks::setContentProtectionPolicy,
             new IntegerPolicySerializer());
 
     private static final Map<String, PolicyDefinition<?>> POLICY_DEFINITIONS = new HashMap<>();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
index 54242ab..c108deaf 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.AppGlobals;
 import android.app.admin.DevicePolicyCache;
 import android.app.admin.DevicePolicyManager;
@@ -282,6 +283,21 @@
         return true;
     }
 
+    static boolean setContentProtectionPolicy(
+            @Nullable Integer value,
+            @NonNull Context context,
+            @UserIdInt Integer userId,
+            @NonNull PolicyKey policyKey) {
+        Binder.withCleanCallingIdentity(
+                () -> {
+                    DevicePolicyCache cache = DevicePolicyCache.getInstance();
+                    if (cache instanceof DevicePolicyCacheImpl cacheImpl) {
+                        cacheImpl.setContentProtectionPolicy(userId, value);
+                    }
+                });
+        return true;
+    }
+
     private static void updateScreenCaptureDisabled() {
         BackgroundThread.getHandler().post(() -> {
             try {
diff --git a/services/fakes/Android.bp b/services/fakes/Android.bp
new file mode 100644
index 0000000..148054b
--- /dev/null
+++ b/services/fakes/Android.bp
@@ -0,0 +1,20 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+// NOTE: These "fake" services are intended for use under the Ravenwood
+// deviceless test environment, and should *not* be included in the build
+// artifacts for physical devices, as they already supply "real" services
+filegroup {
+    name: "services.fakes-sources",
+    srcs: [
+        "java/**/*.java",
+    ],
+    path: "java",
+    visibility: ["//frameworks/base"],
+}
diff --git a/services/fakes/java/com/android/server/FakeClipboardService.java b/services/fakes/java/com/android/server/FakeClipboardService.java
new file mode 100644
index 0000000..0101621
--- /dev/null
+++ b/services/fakes/java/com/android/server/FakeClipboardService.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2024 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.server;
+
+import android.content.ClipData;
+import android.content.ClipDescription;
+import android.content.Context;
+import android.content.IClipboard;
+import android.content.IOnPrimaryClipChangedListener;
+import android.os.PermissionEnforcer;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.os.UserHandle;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Fake implementation of {@code ClipboardManager} since the real implementation is tightly
+ * coupled with many other internal services.
+ */
+public class FakeClipboardService extends IClipboard.Stub {
+    private final RemoteCallbackList<IOnPrimaryClipChangedListener> mListeners =
+            new RemoteCallbackList<>();
+
+    private ClipData mPrimaryClip;
+    private String mPrimaryClipSource;
+
+    public FakeClipboardService(Context context) {
+        super(PermissionEnforcer.fromContext(context));
+    }
+
+    public static class Lifecycle extends SystemService {
+        private FakeClipboardService mService;
+
+        public Lifecycle(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void onStart() {
+            mService = new FakeClipboardService(getContext());
+            publishBinderService(Context.CLIPBOARD_SERVICE, mService);
+        }
+    }
+
+    private static void checkArguments(int userId, int deviceId) {
+        Preconditions.checkArgument(userId == UserHandle.USER_SYSTEM,
+                "Fake only supports USER_SYSTEM user");
+        Preconditions.checkArgument(deviceId == Context.DEVICE_ID_DEFAULT,
+                "Fake only supports DEVICE_ID_DEFAULT device");
+    }
+
+    private void dispatchPrimaryClipChanged() {
+        mListeners.broadcast((listener) -> {
+            try {
+                listener.dispatchPrimaryClipChanged();
+            } catch (RemoteException ignored) {
+            }
+        });
+    }
+
+    @Override
+    public void setPrimaryClip(ClipData clip, String callingPackage, String attributionTag,
+            int userId, int deviceId) {
+        checkArguments(userId, deviceId);
+        mPrimaryClip = clip;
+        mPrimaryClipSource = callingPackage;
+        dispatchPrimaryClipChanged();
+    }
+
+    @Override
+    @android.annotation.EnforcePermission(android.Manifest.permission.SET_CLIP_SOURCE)
+    public void setPrimaryClipAsPackage(ClipData clip, String callingPackage, String attributionTag,
+            int userId, int deviceId, String sourcePackage) {
+        setPrimaryClipAsPackage_enforcePermission();
+        checkArguments(userId, deviceId);
+        mPrimaryClip = clip;
+        mPrimaryClipSource = sourcePackage;
+        dispatchPrimaryClipChanged();
+    }
+
+    @Override
+    public void clearPrimaryClip(String callingPackage, String attributionTag, int userId,
+            int deviceId) {
+        checkArguments(userId, deviceId);
+        mPrimaryClip = null;
+        mPrimaryClipSource = null;
+        dispatchPrimaryClipChanged();
+    }
+
+    @Override
+    public ClipData getPrimaryClip(String pkg, String attributionTag, int userId, int deviceId) {
+        checkArguments(userId, deviceId);
+        return mPrimaryClip;
+    }
+
+    @Override
+    public ClipDescription getPrimaryClipDescription(String callingPackage, String attributionTag,
+            int userId, int deviceId) {
+        checkArguments(userId, deviceId);
+        return (mPrimaryClip != null) ? mPrimaryClip.getDescription() : null;
+    }
+
+    @Override
+    public boolean hasPrimaryClip(String callingPackage, String attributionTag, int userId,
+            int deviceId) {
+        checkArguments(userId, deviceId);
+        return mPrimaryClip != null;
+    }
+
+    @Override
+    public void addPrimaryClipChangedListener(IOnPrimaryClipChangedListener listener,
+            String callingPackage, String attributionTag, int userId, int deviceId) {
+        checkArguments(userId, deviceId);
+        mListeners.register(listener);
+    }
+
+    @Override
+    public void removePrimaryClipChangedListener(IOnPrimaryClipChangedListener listener,
+            String callingPackage, String attributionTag, int userId, int deviceId) {
+        checkArguments(userId, deviceId);
+        mListeners.unregister(listener);
+    }
+
+    @Override
+    public boolean hasClipboardText(String callingPackage, String attributionTag, int userId,
+            int deviceId) {
+        checkArguments(userId, deviceId);
+        return (mPrimaryClip != null) && (mPrimaryClip.getItemCount() > 0)
+                && (mPrimaryClip.getItemAt(0).getText() != null);
+    }
+
+    @Override
+    @android.annotation.EnforcePermission(android.Manifest.permission.SET_CLIP_SOURCE)
+    public String getPrimaryClipSource(String callingPackage, String attributionTag, int userId,
+            int deviceId) {
+        getPrimaryClipSource_enforcePermission();
+        checkArguments(userId, deviceId);
+        return mPrimaryClipSource;
+    }
+
+    @Override
+    public boolean areClipboardAccessNotificationsEnabledForUser(int userId) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setClipboardAccessNotificationsEnabledForUser(boolean enable, int userId) {
+        throw new UnsupportedOperationException();
+    }
+}
diff --git a/services/tests/InputMethodSystemServerTests/Android.bp b/services/tests/InputMethodSystemServerTests/Android.bp
index b7af58c..3bce9b5 100644
--- a/services/tests/InputMethodSystemServerTests/Android.bp
+++ b/services/tests/InputMethodSystemServerTests/Android.bp
@@ -69,7 +69,7 @@
 }
 
 android_ravenwood_test {
-    name: "FrameworksInputMethodSystemServerTests_host",
+    name: "FrameworksInputMethodSystemServerTestsRavenwood",
     static_libs: [
         "androidx.annotation_annotation",
         "androidx.test.rules",
diff --git a/services/tests/PackageManagerServiceTests/preverifieddomains/Android.bp b/services/tests/PackageManagerServiceTests/preverifieddomains/Android.bp
new file mode 100644
index 0000000..39ef501
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/preverifieddomains/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2024 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 {
+    default_team: "trendy_team_framework_android_packages",
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+    name: "PreVerifiedDomainsTests",
+    srcs: [
+        "src/**/*.kt",
+    ],
+    static_libs: [
+        "compatibility-device-util-axt",
+        "androidx.test.runner",
+        "truth",
+    ],
+    platform_apis: true,
+    certificate: "platform",
+    test_suites: ["device-tests"],
+}
diff --git a/services/tests/PackageManagerServiceTests/preverifieddomains/AndroidManifest.xml b/services/tests/PackageManagerServiceTests/preverifieddomains/AndroidManifest.xml
new file mode 100644
index 0000000..ad731fc
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/preverifieddomains/AndroidManifest.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:tools="http://schemas.android.com/tools"
+          package="com.android.server.pm.test.preverifieddomains">
+
+    <application android:label="PreVerified Domains Tests">
+        <activity
+            android:name="com.android.server.pm.test.preverifieddomains.FakeInstantAppInstallerActivity"
+            android:enabled="true"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.INSTALL_INSTANT_APP_PACKAGE_TEST" />
+                <category android:name="android.intent.category.DEFAULT"/>
+                <data android:scheme="file"/>
+                <data android:mimeType="application/vnd.android.package-archive"/>
+            </intent-filter>
+        </activity>
+    </application>
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.server.pm.test.preverifieddomains"
+                     android:label="Package Manager Service Tests for pre-verified domains">
+    </instrumentation>
+
+</manifest>
+
diff --git a/services/tests/PackageManagerServiceTests/preverifieddomains/AndroidTest.xml b/services/tests/PackageManagerServiceTests/preverifieddomains/AndroidTest.xml
new file mode 100644
index 0000000..45e193b
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/preverifieddomains/AndroidTest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 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.
+  -->
+
+<configuration description="Runs Package Manager Service Pre-Verified Domains Tests.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-instrumentation" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="PreVerifiedDomainsTests.apk" />
+    </target_preparer>
+
+    <option name="test-tag" value="PreVerifiedDomainsTests" />
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+        <option name="package" value="com.android.server.pm.test.preverifieddomains" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+        <option name="hidden-api-checks" value="false" />
+    </test>
+</configuration>
diff --git a/services/tests/PackageManagerServiceTests/preverifieddomains/src/com/android/server/pm/test/preverifieddomains/FakeInstantAppInstallerActivity.kt b/services/tests/PackageManagerServiceTests/preverifieddomains/src/com/android/server/pm/test/preverifieddomains/FakeInstantAppInstallerActivity.kt
new file mode 100644
index 0000000..d330490
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/preverifieddomains/src/com/android/server/pm/test/preverifieddomains/FakeInstantAppInstallerActivity.kt
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2024 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.server.pm.test.preverifieddomains
+
+import android.app.Activity
+
+class FakeInstantAppInstallerActivity : Activity()
diff --git a/services/tests/PackageManagerServiceTests/preverifieddomains/src/com/android/server/pm/test/preverifieddomains/PreVerifiedDomainsTests.kt b/services/tests/PackageManagerServiceTests/preverifieddomains/src/com/android/server/pm/test/preverifieddomains/PreVerifiedDomainsTests.kt
new file mode 100644
index 0000000..7043216
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/preverifieddomains/src/com/android/server/pm/test/preverifieddomains/PreVerifiedDomainsTests.kt
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2024 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.server.pm.test.preverifieddomains
+
+import android.app.UiAutomation
+import android.content.ComponentName
+import android.content.Context
+import android.content.pm.Flags
+import android.content.pm.PackageInstaller
+import android.content.pm.PackageInstaller.SessionParams.MODE_FULL_INSTALL
+import android.content.pm.PackageManager
+import android.os.Build
+import android.platform.test.annotations.RequiresFlagsEnabled
+import android.platform.test.flag.junit.CheckFlagsRule
+import android.platform.test.flag.junit.DeviceFlagsValueProvider
+import android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.compatibility.common.util.DeviceConfigStateManager
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.AfterClass
+import org.junit.Assert.assertThrows
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.BeforeClass
+import org.junit.Rule
+import org.junit.Test
+import org.junit.function.ThrowingRunnable
+import org.junit.runner.RunWith
+
+/**
+ * Pre-verified domains API tests. These tests require the device's default instant app
+ * installer to be disabled temporarily and is only able to run on ENG builds.
+ */
+@RunWith(AndroidJUnit4::class)
+class PreVerifiedDomainsTests {
+    companion object {
+        private const val PROPERTY_PRE_VERIFIED_DOMAINS_COUNT_LIMIT =
+                "pre_verified_domains_count_limit"
+        private const val PROPERTY_PRE_VERIFIED_DOMAIN_LENGTH_LIMIT =
+                "pre_verified_domain_length_limit"
+        private const val TEMP_COUNT_LIMIT = 10
+        private const val TEMP_LENGTH_LIMIT = 15
+        private val testDomains = setOf("com.foo", "com.bar")
+
+        private val uiAutomation: UiAutomation =
+                InstrumentationRegistry.getInstrumentation().getUiAutomation()
+        private lateinit var packageManager: PackageManager
+        private var defaultInstantAppInstaller: ComponentName? = null
+        private lateinit var fakeInstantAppInstaller: ComponentName
+
+        @JvmStatic
+        @BeforeClass
+        fun setupBeforeClass() {
+            val context = InstrumentationRegistry.getInstrumentation().getContext()
+            packageManager = context.packageManager
+            defaultInstantAppInstaller = packageManager.getInstantAppInstallerComponent()
+            fakeInstantAppInstaller = ComponentName(
+                    context.packageName,
+                    context.packageName + ".FakeInstantAppInstallerActivity")
+            // By disabling the original instant app installer, this test app becomes the instant
+            // app installer
+            uiAutomation.adoptShellPermissionIdentity()
+            try {
+                // Enable the fake instant app installer before disabling the default one
+                packageManager.setComponentEnabledSetting(
+                        fakeInstantAppInstaller,
+                        PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+                        PackageManager.DONT_KILL_APP
+                )
+                if (defaultInstantAppInstaller != null) {
+                    packageManager.setComponentEnabledSetting(
+                            defaultInstantAppInstaller!!,
+                            PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+                            0
+                    )
+                }
+            } finally {
+                uiAutomation.dropShellPermissionIdentity()
+            }
+            assertThat(fakeInstantAppInstaller).isEqualTo(
+                    packageManager.getInstantAppInstallerComponent())
+        }
+
+        @JvmStatic
+        @AfterClass
+        fun restoreInstantAppInstaller() {
+            uiAutomation.adoptShellPermissionIdentity()
+            try {
+                // Enable the original instant app installer before disabling the temporary one, so
+                // there won't be a time when the device doesn't have a valid instant app installer
+                if (defaultInstantAppInstaller != null) {
+                    packageManager.setComponentEnabledSetting(
+                            defaultInstantAppInstaller!!,
+                            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+                            0
+                    )
+                }
+                // Be careful not to let this test process killed, or the test will be considered
+                // as failed
+                packageManager.setComponentEnabledSetting(
+                        fakeInstantAppInstaller,
+                        PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+                        PackageManager.DONT_KILL_APP
+                )
+            } finally {
+                uiAutomation.dropShellPermissionIdentity()
+            }
+        }
+    }
+
+    private lateinit var packageInstaller: PackageInstaller
+    private lateinit var context: Context
+    private lateinit var packageManager: PackageManager
+    private var mDefaultCountLimit: String? = null
+    private var mDefaultLengthLimit: String? = null
+
+    @JvmField
+    @Rule
+    val mCheckFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
+
+    @Before
+    fun setUp() {
+        context = InstrumentationRegistry.getInstrumentation().getContext()
+        packageManager = context.packageManager
+        packageInstaller = packageManager.packageInstaller
+        mDefaultCountLimit = getLimitFromDeviceConfig(PROPERTY_PRE_VERIFIED_DOMAINS_COUNT_LIMIT)
+        mDefaultLengthLimit = getLimitFromDeviceConfig(PROPERTY_PRE_VERIFIED_DOMAIN_LENGTH_LIMIT)
+    }
+
+    @After
+    fun cleanUp() {
+        setLimitInDeviceConfig(PROPERTY_PRE_VERIFIED_DOMAINS_COUNT_LIMIT, mDefaultCountLimit)
+        setLimitInDeviceConfig(PROPERTY_PRE_VERIFIED_DOMAIN_LENGTH_LIMIT, mDefaultLengthLimit)
+    }
+
+    @RequiresFlagsEnabled(Flags.FLAG_SET_PRE_VERIFIED_DOMAINS)
+    @Test
+    fun testSetPreVerifiedDomainsExceedsCountLimit() {
+        // Temporarily change the count limit to a much smaller number so the test can exceed it
+        setLimitInDeviceConfig(
+                PROPERTY_PRE_VERIFIED_DOMAINS_COUNT_LIMIT,
+                TEMP_COUNT_LIMIT.toString()
+        )
+        val domains = mutableSetOf<String>()
+        for (i in 0 until(TEMP_COUNT_LIMIT + 1)) {
+            domains.add("domain$i")
+        }
+
+        uiAutomation.adoptShellPermissionIdentity(android.Manifest.permission.ACCESS_INSTANT_APPS)
+        try {
+            assertThrows(
+                    IllegalArgumentException::class.java,
+                    ThrowingRunnable {
+                        createSessionWithPreVerifiedDomains(domains)
+                    }
+            )
+        } finally {
+            uiAutomation.dropShellPermissionIdentity()
+        }
+    }
+
+    @RequiresFlagsEnabled(Flags.FLAG_SET_PRE_VERIFIED_DOMAINS)
+    @Test
+    fun testSetPreVerifiedDomainsExceedsLengthLimit() {
+        // Temporarily change the count limit to a much smaller number so the test can exceed it
+        setLimitInDeviceConfig(
+                PROPERTY_PRE_VERIFIED_DOMAIN_LENGTH_LIMIT,
+                TEMP_LENGTH_LIMIT.toString()
+        )
+        val invalidDomain = "a".repeat(TEMP_LENGTH_LIMIT + 1)
+
+        uiAutomation.adoptShellPermissionIdentity(android.Manifest.permission.ACCESS_INSTANT_APPS)
+        try {
+            assertThrows(
+                    "Pre-verified domain: [" +
+                            invalidDomain + " ] exceeds maximum length allowed: " +
+                            TEMP_LENGTH_LIMIT,
+                    IllegalArgumentException::class.java,
+                    ThrowingRunnable {
+                        createSessionWithPreVerifiedDomains(setOf(invalidDomain))
+                    }
+            )
+        } finally {
+            uiAutomation.dropShellPermissionIdentity()
+        }
+    }
+
+    @RequiresFlagsEnabled(Flags.FLAG_SET_PRE_VERIFIED_DOMAINS)
+    @Test
+    fun testSetAndGetPreVerifiedDomains() {
+        // Fake instant app installers can only work on ENG builds
+        assumeTrue("eng" == Build.TYPE)
+        var session: PackageInstaller.Session? = null
+        uiAutomation.adoptShellPermissionIdentity(android.Manifest.permission.ACCESS_INSTANT_APPS)
+        try {
+            val sessionId = createSessionWithPreVerifiedDomains(testDomains)
+            session = packageInstaller.openSession(sessionId)
+            assertThat(session.getPreVerifiedDomains()).isEqualTo(testDomains)
+        } finally {
+            uiAutomation.dropShellPermissionIdentity()
+            session?.abandon()
+        }
+    }
+
+    private fun createSessionWithPreVerifiedDomains(domains: Set<String>): Int {
+        val sessionParam = PackageInstaller.SessionParams(MODE_FULL_INSTALL)
+        val sessionId = packageInstaller.createSession(sessionParam)
+        val session = packageInstaller.openSession(sessionId)
+        try {
+            session.setPreVerifiedDomains(domains)
+        } catch (e: Exception) {
+            session.abandon()
+            throw e
+        }
+        return sessionId
+    }
+
+    private fun getLimitFromDeviceConfig(propertyName: String): String? {
+        val stateManager = DeviceConfigStateManager(
+                context,
+                NAMESPACE_PACKAGE_MANAGER_SERVICE,
+                propertyName
+        )
+        return stateManager.get()
+    }
+
+    private fun setLimitInDeviceConfig(propertyName: String, value: String?) {
+        val stateManager = DeviceConfigStateManager(
+                context,
+                NAMESPACE_PACKAGE_MANAGER_SERVICE,
+                propertyName
+        )
+        val currentValue = stateManager.get()
+        if (currentValue != value) {
+            // Only change the value if the current value is different
+            stateManager.set(value)
+        }
+    }
+}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index d4b57f1..96e9ca0 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -275,6 +275,7 @@
         AndroidPackage::isUpdatableSystem,
         AndroidPackage::getEmergencyInstaller,
         AndroidPackage::isAllowCrossUidActivitySwitchFromBelow,
+        PackageImpl::isAppMetadataFileInApk,
     )
 
     override fun extraParams() = listOf(
diff --git a/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
index 418b78c..9c9aeea 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
@@ -16,6 +16,7 @@
 
 package com.android.server.display;
 
+import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED;
 import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED;
 import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT;
 import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_IDLE;
@@ -1016,4 +1017,34 @@
         listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 500));
         assertEquals(500, mController.getAmbientLux(), EPSILON);
     }
+
+    @Test
+    public void testBrightnessBasedOnLastObservedLux() throws Exception {
+        ArgumentCaptor<SensorEventListener> listenerCaptor =
+                ArgumentCaptor.forClass(SensorEventListener.class);
+        verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor),
+                eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class));
+        SensorEventListener listener = listenerCaptor.getValue();
+
+        // Set up system to return 0.3f as a brightness value
+        float lux = 100.0f;
+        // Brightness as float (from 0.0f to 1.0f)
+        float normalizedBrightness = 0.3f;
+        when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux)).thenReturn(lux);
+        when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux)).thenReturn(lux);
+        when(mBrightnessMappingStrategy.getBrightness(eq(lux), eq(null), anyInt()))
+                .thenReturn(normalizedBrightness);
+        when(mBrightnessThrottler.getBrightnessCap()).thenReturn(BRIGHTNESS_MAX_FLOAT);
+        when(mBrightnessThrottler.isThrottled()).thenReturn(true);
+
+        // Send a new sensor value, disable the sensor and verify
+        listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, (int) lux));
+        mController.configure(AUTO_BRIGHTNESS_DISABLED, /* configuration= */ null,
+                /* brightness= */ 0, /* userChangedBrightness= */ false, /* adjustment= */ 0,
+                /* userChanged= */ false, DisplayPowerRequest.POLICY_BRIGHT,
+                /* shouldResetShortTermModel= */ true);
+        assertEquals(normalizedBrightness,
+                mController.getAutomaticScreenBrightnessBasedOnLastObservedLux(
+                        /* brightnessEvent= */ null), EPSILON);
+    }
 }
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
index 807774f..acddc9d 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -1665,6 +1665,35 @@
                 /* luxTimestamps= */ any());
     }
 
+    @Test
+    public void testInitialDozeBrightness() {
+        when(mDisplayManagerFlagsMock.areAutoBrightnessModesEnabled()).thenReturn(true);
+        when(mDisplayManagerFlagsMock.isDisplayOffloadEnabled()).thenReturn(true);
+        mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession);
+        Settings.System.putInt(mContext.getContentResolver(),
+                Settings.System.SCREEN_BRIGHTNESS_MODE,
+                Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing, false);
+        float brightness = 0.277f;
+        when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+        when(mHolder.automaticBrightnessController
+                .getAutomaticScreenBrightnessBasedOnLastObservedLux(any(BrightnessEvent.class)))
+                .thenReturn(brightness);
+        when(mHolder.hbmController.getCurrentBrightnessMax())
+                .thenReturn(PowerManager.BRIGHTNESS_MAX);
+        when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_DOZE);
+
+        DisplayPowerRequest dpr = new DisplayPowerRequest();
+        dpr.policy = DisplayPowerRequest.POLICY_DOZE;
+        mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+        advanceTime(1); // Run updatePowerState
+
+        verify(mHolder.animator).animateTo(eq(brightness),
+                /* linearSecondTarget= */ anyFloat(), /* rate= */ anyFloat(),
+                /* ignoreAnimationLimits= */ anyBoolean());
+    }
+
     /**
      * Creates a mock and registers it to {@link LocalServices}.
      */
diff --git a/services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java b/services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java
index a8af98f..8a6c2440 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java
@@ -16,6 +16,8 @@
 
 package com.android.server.display;
 
+import static android.hardware.display.DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED;
+
 import static com.android.internal.display.RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE;
 
 import static org.junit.Assert.assertEquals;
@@ -50,6 +52,8 @@
     private DisplayManager mDisplayManagerMock;
     @Mock
     private Display mDisplayMock;
+    @Mock
+    private Display mDisplayMock2;
 
     @Before
     public void setUp() {
@@ -65,25 +69,54 @@
                 new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
                         /* refreshRate= */ 90)
         };
-
         when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock);
         when(mDisplayMock.getSupportedModes()).thenReturn(modes);
+
+        Display.Mode[] modes2 = new Display.Mode[]{
+                new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
+                        /* refreshRate= */ 70),
+                new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
+                        /* refreshRate= */ 130),
+                new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600,
+                        /* refreshRate= */ 80)
+        };
+        when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY + 1)).thenReturn(mDisplayMock2);
+        when(mDisplayMock2.getSupportedModes()).thenReturn(modes2);
+
+        when(mDisplayManagerMock.getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED))
+                .thenReturn(new Display[]{ mDisplayMock, mDisplayMock2 });
     }
 
     @Test
     public void testFindHighestRefreshRateForDefaultDisplay() {
-        when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock);
         assertEquals(120,
                 RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext),
                 /* delta= */ 0);
     }
 
     @Test
-    public void testFindHighestRefreshRate_DisplayIsNull() {
+    public void testFindHighestRefreshRateForDefaultDisplay_DisplayIsNull() {
         when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(null);
         assertEquals(DEFAULT_REFRESH_RATE,
                 RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext),
                 /* delta= */ 0);
 
     }
+
+    @Test
+    public void testFindHighestRefreshRateAmongAllDisplays() {
+        assertEquals(130,
+                RefreshRateSettingsUtils.findHighestRefreshRateAmongAllDisplays(mContext),
+                /* delta= */ 0);
+    }
+
+    @Test
+    public void testFindHighestRefreshRateAmongAllDisplays_NoDisplays() {
+        when(mDisplayManagerMock.getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED))
+                .thenReturn(new Display[0]);
+        assertEquals(DEFAULT_REFRESH_RATE,
+                RefreshRateSettingsUtils.findHighestRefreshRateAmongAllDisplays(mContext),
+                /* delta= */ 0);
+
+    }
 }
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/BrightnessEventTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/BrightnessEventTest.java
index c0c63c6..060f99b 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/BrightnessEventTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/BrightnessEventTest.java
@@ -16,9 +16,12 @@
 
 package com.android.server.display.brightness;
 
+import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_IDLE;
+
 import static org.junit.Assert.assertEquals;
 
 import android.hardware.display.BrightnessInfo;
+import android.view.Display;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -39,6 +42,7 @@
         mBrightnessEvent.setReason(
                 getReason(BrightnessReason.REASON_DOZE, BrightnessReason.MODIFIER_LOW_POWER));
         mBrightnessEvent.setPhysicalDisplayId("test");
+        mBrightnessEvent.setDisplayState(Display.STATE_ON);
         mBrightnessEvent.setLux(100.0f);
         mBrightnessEvent.setPreThresholdLux(150.0f);
         mBrightnessEvent.setTime(System.currentTimeMillis());
@@ -55,6 +59,7 @@
         mBrightnessEvent.setAdjustmentFlags(0);
         mBrightnessEvent.setAutomaticBrightnessEnabled(true);
         mBrightnessEvent.setDisplayBrightnessStrategyName(DISPLAY_BRIGHTNESS_STRATEGY_NAME);
+        mBrightnessEvent.setAutoBrightnessMode(AUTO_BRIGHTNESS_MODE_IDLE);
     }
 
     @Test
@@ -69,20 +74,20 @@
     public void testToStringWorksAsExpected() {
         String actualString = mBrightnessEvent.toString(false);
         String expectedString =
-                "BrightnessEvent: disp=1, physDisp=test, brt=0.6, initBrt=25.0, rcmdBrt=0.6,"
-                + " preBrt=NaN, lux=100.0, preLux=150.0, hbmMax=0.62, hbmMode=off, rbcStrength=-1,"
-                + " thrmMax=0.65, powerFactor=0.2, wasShortTermModelActive=true, flags=,"
-                + " reason=doze [ low_pwr ], autoBrightness=true, strategy="
-                        + DISPLAY_BRIGHTNESS_STRATEGY_NAME;
+                "BrightnessEvent: disp=1, physDisp=test, displayState=ON, brt=0.6, initBrt=25.0,"
+                + " rcmdBrt=0.6, preBrt=NaN, lux=100.0, preLux=150.0, hbmMax=0.62, hbmMode=off,"
+                + " rbcStrength=-1, thrmMax=0.65, powerFactor=0.2, wasShortTermModelActive=true,"
+                + " flags=, reason=doze [ low_pwr ], autoBrightness=true, strategy="
+                        + DISPLAY_BRIGHTNESS_STRATEGY_NAME + ", autoBrightnessMode=idle";
         assertEquals(expectedString, actualString);
     }
 
     @Test
     public void testFlagsToString() {
         mBrightnessEvent.reset();
-        mBrightnessEvent.setFlags(mBrightnessEvent.getFlags() | BrightnessEvent.FLAG_IDLE_CURVE);
+        mBrightnessEvent.setFlags(mBrightnessEvent.getFlags() | BrightnessEvent.FLAG_RBC);
         String actualString = mBrightnessEvent.flagsToString();
-        String expectedString = "idle_curve ";
+        String expectedString = "rbc ";
         assertEquals(expectedString, actualString);
     }
 
@@ -90,10 +95,10 @@
     public void testFlagsToString_multipleFlags() {
         mBrightnessEvent.reset();
         mBrightnessEvent.setFlags(mBrightnessEvent.getFlags()
-                    | BrightnessEvent.FLAG_IDLE_CURVE
+                    | BrightnessEvent.FLAG_RBC
                     | BrightnessEvent.FLAG_LOW_POWER_MODE);
         String actualString = mBrightnessEvent.flagsToString();
-        String expectedString = "idle_curve low_power_mode ";
+        String expectedString = "rbc low_power_mode ";
         assertEquals(expectedString, actualString);
     }
 
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
index 5408e11..8867806 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
@@ -359,11 +359,17 @@
                 AutomaticBrightnessController.class);
         when(automaticBrightnessController.getAutomaticScreenBrightness(any(BrightnessEvent.class)))
                 .thenReturn(automaticScreenBrightness);
+        when(automaticBrightnessController.getAutomaticScreenBrightnessBasedOnLastObservedLux(
+                any(BrightnessEvent.class)))
+                .thenReturn(automaticScreenBrightness);
         mAutomaticBrightnessStrategy.setAutomaticBrightnessController(
                 automaticBrightnessController);
         assertEquals(automaticScreenBrightness,
                 mAutomaticBrightnessStrategy.getAutomaticScreenBrightness(
                         new BrightnessEvent(DISPLAY_ID)), 0.0f);
+        assertEquals(automaticScreenBrightness,
+                mAutomaticBrightnessStrategy.getAutomaticScreenBrightnessBasedOnLastObservedLux(
+                        new BrightnessEvent(DISPLAY_ID)), 0.0f);
     }
 
     @Test
diff --git a/services/tests/media/mediarouterservicetest/src/com/android/server/media/AudioManagerRouteControllerTest.java b/services/tests/media/mediarouterservicetest/src/com/android/server/media/AudioManagerRouteControllerTest.java
index 8f5d125..a918be2 100644
--- a/services/tests/media/mediarouterservicetest/src/com/android/server/media/AudioManagerRouteControllerTest.java
+++ b/services/tests/media/mediarouterservicetest/src/com/android/server/media/AudioManagerRouteControllerTest.java
@@ -16,6 +16,8 @@
 
 package com.android.server.media;
 
+import static android.Manifest.permission.MODIFY_AUDIO_ROUTING;
+
 import static com.android.server.media.AudioRoutingUtils.ATTRIBUTES_MEDIA;
 import static com.android.server.media.AudioRoutingUtils.getMediaAudioProductStrategy;
 
@@ -31,6 +33,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.Instrumentation;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothManager;
 import android.content.Context;
@@ -48,6 +51,7 @@
 
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -85,6 +89,7 @@
                     /* name= */ null,
                     /* address= */ null);
 
+    private Instrumentation mInstrumentation;
     private AudioDeviceInfo mSelectedAudioDeviceInfo;
     private Set<AudioDeviceInfo> mAvailableAudioDeviceInfos;
     @Mock private AudioManager mMockAudioManager;
@@ -96,10 +101,11 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mInstrumentation.getUiAutomation().adoptShellPermissionIdentity(MODIFY_AUDIO_ROUTING);
         Resources mockResources = Mockito.mock(Resources.class);
         when(mockResources.getText(anyInt())).thenReturn(FAKE_ROUTE_NAME);
-        Context realContext = InstrumentationRegistry.getInstrumentation().getContext();
+        Context realContext = mInstrumentation.getContext();
         Context mockContext = Mockito.mock(Context.class);
         when(mockContext.getResources()).thenReturn(mockResources);
         // The bluetooth stack needs the application info, but we cannot use a spy because the
@@ -135,6 +141,11 @@
         clearInvocations(mOnDeviceRouteChangedListener);
     }
 
+    @After
+    public void tearDown() {
+        mInstrumentation.getUiAutomation().dropShellPermissionIdentity();
+    }
+
     @Test
     public void getSelectedRoute_afterDevicesConnect_returnsRightSelectedRoute() {
         assertThat(mControllerUnderTest.getSelectedRoute().getType())
diff --git a/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceContentTest.java b/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceContentTest.java
index dad36e7..2366f56 100644
--- a/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceContentTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceContentTest.java
@@ -30,6 +30,7 @@
 import android.media.projection.MediaProjectionInfo;
 import android.media.projection.MediaProjectionManager;
 import android.os.Binder;
+import android.os.Process;
 import android.platform.test.annotations.RequiresFlagsEnabled;
 import android.platform.test.flag.junit.CheckFlagsRule;
 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
@@ -52,6 +53,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.Set;
+
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @RequiresFlagsEnabled(FLAG_SENSITIVE_CONTENT_APP_PROTECTION)
@@ -62,12 +65,14 @@
 public class SensitiveContentProtectionManagerServiceContentTest {
     private final PackageInfo mPackageInfo =
             new PackageInfo("test.package", 12345, new Binder());
+    private final String mScreenRecorderPackage = "test.screen.recorder.package";
+    private final String mExemptedScreenRecorderPackage = "test.exempted.screen.recorder.package";
     private SensitiveContentProtectionManagerService mSensitiveContentProtectionManagerService;
     private MediaProjectionManager.Callback mMediaPorjectionCallback;
 
     @Mock private WindowManagerInternal mWindowManager;
     @Mock private MediaProjectionManager mProjectionManager;
-    @Mock private MediaProjectionInfo mMediaProjectionInfo;
+    private MediaProjectionInfo mMediaProjectionInfo;
 
     @Captor
     private ArgumentCaptor<MediaProjectionManager.Callback> mMediaProjectionCallbackCaptor;
@@ -85,9 +90,22 @@
         MockitoAnnotations.initMocks(this);
         mSensitiveContentProtectionManagerService =
                 new SensitiveContentProtectionManagerService(mContext);
-        mSensitiveContentProtectionManagerService.init(mProjectionManager, mWindowManager);
+        mSensitiveContentProtectionManagerService.init(mProjectionManager, mWindowManager,
+                new ArraySet<>(Set.of(mExemptedScreenRecorderPackage)));
         verify(mProjectionManager).addCallback(mMediaProjectionCallbackCaptor.capture(), any());
         mMediaPorjectionCallback = mMediaProjectionCallbackCaptor.getValue();
+        mMediaProjectionInfo =
+                new MediaProjectionInfo(mScreenRecorderPackage, Process.myUserHandle(), null);
+    }
+
+    @Test
+    public void testExemptedRecorderPackageForScreenCapture() {
+        MediaProjectionInfo exemptedRecorderPackage = new MediaProjectionInfo(
+                mExemptedScreenRecorderPackage, Process.myUserHandle(), null);
+        mMediaPorjectionCallback.onStart(exemptedRecorderPackage);
+        mSensitiveContentProtectionManagerService.setSensitiveContentProtection(
+                mPackageInfo.getWindowToken(), mPackageInfo.getPkg(), mPackageInfo.getUid(), true);
+        verifyZeroInteractions(mWindowManager);
     }
 
     @Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java b/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java
index 08050a9..e74fe29 100644
--- a/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceNotificationTest.java
@@ -78,6 +78,8 @@
     private static final String NOTIFICATION_PKG_1 = "com.android.server.notification.one";
     private static final String NOTIFICATION_PKG_2 = "com.android.server.notification.two";
 
+    private static final String EXEMPTED_SCREEN_RECORDER_PACKAGE = "test.screen.recorder.package";
+
     private static final int NOTIFICATION_UID_1 = 5;
     private static final int NOTIFICATION_UID_2 = 6;
 
@@ -138,7 +140,8 @@
 
         setupSensitiveNotification();
 
-        mSensitiveContentProtectionManagerService.init(mProjectionManager, mWindowManager);
+        mSensitiveContentProtectionManagerService.init(mProjectionManager, mWindowManager,
+                new ArraySet<>(Set.of(EXEMPTED_SCREEN_RECORDER_PACKAGE)));
 
         // Obtain useful mMediaProjectionCallback
         verify(mProjectionManager).addCallback(mMediaProjectionCallbackCaptor.capture(), any());
@@ -275,6 +278,16 @@
     }
 
     @Test
+    public void mediaProjectionOnStart_verifyExemptedRecorderPackage() {
+        MediaProjectionInfo mediaProjectionInfo = mock(MediaProjectionInfo.class);
+        when(mediaProjectionInfo.getPackageName()).thenReturn(EXEMPTED_SCREEN_RECORDER_PACKAGE);
+
+        mMediaProjectionCallbackCaptor.getValue().onStart(mediaProjectionInfo);
+
+        verifyZeroInteractions(mWindowManager);
+    }
+
+    @Test
     public void mediaProjectionOnStart_onProjectionStart_setWmBlockedPackages() {
         ArraySet<PackageInfo> expectedBlockedPackages = setupSensitiveNotification();
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java b/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
index a8faa54..ad68de8 100644
--- a/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/power/batterysaver/BatterySaverStateMachineTest.java
@@ -196,6 +196,9 @@
         when(mMockResources.getBoolean(
                 com.android.internal.R.bool.config_batterySaverStickyBehaviourDisabled))
                 .thenReturn(false);
+        when(mMockResources.getBoolean(
+                com.android.internal.R.bool.config_batterySaverTurnedOffNotificationEnabled))
+                .thenReturn(true);
         when(mMockResources.getInteger(
                 com.android.internal.R.integer.config_dynamicPowerSavingsDefaultDisableThreshold))
                 .thenReturn(80);
diff --git a/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java b/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java
index d6e246f..6e41685 100644
--- a/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/rollback/RollbackPackageHealthObserverTest.java
@@ -25,6 +25,8 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
@@ -42,6 +44,7 @@
 import android.crashrecovery.flags.Flags;
 import android.os.Handler;
 import android.os.MessageQueue;
+import android.os.SystemProperties;
 import android.platform.test.flag.junit.SetFlagsRule;
 
 import androidx.test.runner.AndroidJUnit4;
@@ -65,6 +68,7 @@
 import org.mockito.stubbing.Answer;
 
 import java.time.Duration;
+import java.util.HashMap;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -90,7 +94,7 @@
 
     @Rule
     public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
-
+    private HashMap<String, String> mSystemSettingsMap;
     private MockitoSession mSession;
     private static final String APP_A = "com.package.a";
     private static final String APP_B = "com.package.b";
@@ -99,6 +103,9 @@
     private static final long VERSION_CODE_2 = 2L;
     private static final String LOG_TAG = "RollbackPackageHealthObserverTest";
 
+    private static final String PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG =
+            "persist.device_config.configuration.disable_high_impact_rollback";
+
     private SystemConfig mSysConfig;
 
     @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
@@ -111,11 +118,34 @@
                 .initMocks(this)
                 .strictness(Strictness.LENIENT)
                 .spyStatic(PackageWatchdog.class)
+                .spyStatic(SystemProperties.class)
                 .startMocking();
+        mSystemSettingsMap = new HashMap<>();
 
         // Mock PackageWatchdog
         doAnswer((Answer<PackageWatchdog>) invocationOnMock -> mMockPackageWatchdog)
                 .when(() -> PackageWatchdog.getInstance(mMockContext));
+
+        // Mock SystemProperties setter and various getters
+        doAnswer((Answer<Void>) invocationOnMock -> {
+                    String key = invocationOnMock.getArgument(0);
+                    String value = invocationOnMock.getArgument(1);
+
+                    mSystemSettingsMap.put(key, value);
+                    return null;
+                }
+        ).when(() -> SystemProperties.set(anyString(), anyString()));
+
+        doAnswer((Answer<Boolean>) invocationOnMock -> {
+                    String key = invocationOnMock.getArgument(0);
+                    boolean defaultValue = invocationOnMock.getArgument(1);
+
+                    String storedValue = mSystemSettingsMap.get(key);
+                    return storedValue == null ? defaultValue : Boolean.parseBoolean(storedValue);
+                }
+        ).when(() -> SystemProperties.getBoolean(anyString(), anyBoolean()));
+
+        SystemProperties.set(PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG, Boolean.toString(false));
     }
 
     @After
@@ -609,6 +639,32 @@
                 observer.onBootLoop(1));
     }
 
+    @Test
+    public void onBootLoop_impactLevelHighDisableHighImpactRollback_onePackage()
+            throws PackageManager.NameNotFoundException {
+        mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+        SystemProperties.set(PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG, Boolean.toString(true));
+        VersionedPackage appAFrom = new VersionedPackage(APP_A, VERSION_CODE_2);
+        VersionedPackage appATo = new VersionedPackage(APP_A, VERSION_CODE);
+        PackageRollbackInfo packageRollbackInfo = new PackageRollbackInfo(appAFrom, appATo,
+                null, null, false, false,
+                null);
+        RollbackInfo rollbackInfo1 = new RollbackInfo(1, List.of(packageRollbackInfo),
+                false, null, 111,
+                PackageManager.ROLLBACK_USER_IMPACT_HIGH);
+        RollbackPackageHealthObserver observer =
+                spy(new RollbackPackageHealthObserver(mMockContext, mApexManager));
+
+        when(mMockContext.getSystemService(RollbackManager.class)).thenReturn(mRollbackManager);
+        // Make the rollbacks available
+        when(mRollbackManager.getAvailableRollbacks()).thenReturn(List.of(rollbackInfo1));
+        when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+        when(mMockPackageManager.getModuleInfo(any(), eq(0))).thenReturn(null);
+
+        assertEquals(PackageWatchdog.PackageHealthObserverImpact.USER_IMPACT_LEVEL_0,
+                observer.onBootLoop(1));
+    }
+
     /**
      * When the rollback impact level is manual only return user impact level 0. (User impact level
      * 0 is ignored by package watchdog)
@@ -924,6 +980,50 @@
         assertThat(argument.getAllValues()).isEqualTo(List.of(rollbackId2));
     }
 
+    /**
+     * Don't roll back if kill switch is enabled.
+     */
+    @Test
+    public void executeBootLoopMitigation_impactLevelHighKillSwitchTrue_rollbackHigh()
+            throws PackageManager.NameNotFoundException {
+        mSetFlagsRule.enableFlags(Flags.FLAG_RECOVERABILITY_DETECTION);
+        SystemProperties.set(PROP_DISABLE_HIGH_IMPACT_ROLLBACK_FLAG, Boolean.toString(true));
+        int rollbackId1 = 1;
+        VersionedPackage appBFrom = new VersionedPackage(APP_B, VERSION_CODE_2);
+        VersionedPackage appBTo = new VersionedPackage(APP_B, VERSION_CODE);
+        PackageRollbackInfo packageRollbackInfoB = new PackageRollbackInfo(appBFrom, appBTo,
+                null, null , false, false,
+                null);
+        RollbackInfo rollbackInfo1 = new RollbackInfo(rollbackId1, List.of(packageRollbackInfoB),
+                false, null, 111,
+                PackageManager.ROLLBACK_USER_IMPACT_HIGH);
+        int rollbackId2 = 2;
+        VersionedPackage appAFrom = new VersionedPackage(APP_A, VERSION_CODE_2);
+        VersionedPackage appATo = new VersionedPackage(APP_A, VERSION_CODE);
+        PackageRollbackInfo packageRollbackInfoA = new PackageRollbackInfo(appAFrom, appATo,
+                null, null , false, false,
+                null);
+        RollbackInfo rollbackInfo2 = new RollbackInfo(rollbackId2, List.of(packageRollbackInfoA),
+                false, null, 111,
+                PackageManager.ROLLBACK_USER_IMPACT_HIGH);
+        RollbackPackageHealthObserver observer =
+                spy(new RollbackPackageHealthObserver(mMockContext, mApexManager));
+        ArgumentCaptor<Integer> argument = ArgumentCaptor.forClass(Integer.class);
+
+        when(mMockContext.getSystemService(RollbackManager.class)).thenReturn(mRollbackManager);
+        // Make the rollbacks available
+        when(mRollbackManager.getAvailableRollbacks()).thenReturn(
+                List.of(rollbackInfo1, rollbackInfo2));
+        when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+        when(mMockPackageManager.getModuleInfo(any(), eq(0))).thenReturn(null);
+
+        observer.executeBootLoopMitigation(1);
+        waitForIdleHandler(observer.getHandler(), Duration.ofSeconds(10));
+
+        verify(mRollbackManager, never()).commitRollback(
+                argument.capture(), any(), any());
+    }
+
     private void waitForIdleHandler(Handler handler, Duration timeout) {
         final MessageQueue queue = handler.getLooper().getQueue();
         final CountDownLatch latch = new CountDownLatch(1);
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsImplTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsImplTest.java
index 548fae7..a1101cd 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsImplTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryStatsImplTest.java
@@ -578,45 +578,136 @@
 
         // First wakelock, acquired once, not currently held
         mMockClock.realtime = 1000;
-        mBatteryStatsImpl.noteStartWakeLocked(10100, 100, null, "wakeLock1", null,
-                BatteryStats.WAKE_TYPE_PARTIAL, false);
+        mBatteryStatsImpl.noteStartWakeLocked(
+                10100, 100, null, "wakeLock1", null, BatteryStats.WAKE_TYPE_PARTIAL, false);
 
         mMockClock.realtime = 3000;
-        mBatteryStatsImpl.noteStopWakeLocked(10100, 100, null, "wakeLock1", null,
-                BatteryStats.WAKE_TYPE_PARTIAL);
+        mBatteryStatsImpl.noteStopWakeLocked(
+                10100, 100, null, "wakeLock1", null, BatteryStats.WAKE_TYPE_PARTIAL);
 
         // Second wakelock, acquired twice, still held
         mMockClock.realtime = 4000;
-        mBatteryStatsImpl.noteStartWakeLocked(10200, 101, null, "wakeLock2", null,
-                BatteryStats.WAKE_TYPE_PARTIAL, false);
+        mBatteryStatsImpl.noteStartWakeLocked(
+                10200, 101, null, "wakeLock2", null, BatteryStats.WAKE_TYPE_PARTIAL, false);
 
         mMockClock.realtime = 5000;
-        mBatteryStatsImpl.noteStopWakeLocked(10200, 101, null, "wakeLock2", null,
-                BatteryStats.WAKE_TYPE_PARTIAL);
+        mBatteryStatsImpl.noteStopWakeLocked(
+                10200, 101, null, "wakeLock2", null, BatteryStats.WAKE_TYPE_PARTIAL);
 
         mMockClock.realtime = 6000;
-        mBatteryStatsImpl.noteStartWakeLocked(10200, 101, null, "wakeLock2", null,
-                BatteryStats.WAKE_TYPE_PARTIAL, false);
+        mBatteryStatsImpl.noteStartWakeLocked(
+                10200, 101, null, "wakeLock2", null, BatteryStats.WAKE_TYPE_PARTIAL, false);
+
+        // Third and fourth wakelocks, overlapped with each other.
+        mMockClock.realtime = 7000;
+        mBatteryStatsImpl.noteStartWakeLocked(
+                10300, 102, null, "wakeLock3", null, BatteryStats.WAKE_TYPE_PARTIAL, false);
+
+        mMockClock.realtime = 8000;
+        mBatteryStatsImpl.noteStartWakeLocked(
+                10400, 103, null, "wakeLock4", null, BatteryStats.WAKE_TYPE_PARTIAL, false);
 
         mMockClock.realtime = 9000;
+        mBatteryStatsImpl.noteStopWakeLocked(
+                10400, 103, null, "wakeLock4", null, BatteryStats.WAKE_TYPE_PARTIAL);
 
-        List<WakeLockStats.WakeLock> wakeLockStats =
-                mBatteryStatsImpl.getWakeLockStats().getWakeLocks();
-        assertThat(wakeLockStats).hasSize(2);
+        mMockClock.realtime = 10000;
+        mBatteryStatsImpl.noteStartWakeLocked(
+                10400, 104, null, "wakeLock5", null, BatteryStats.WAKE_TYPE_PARTIAL, false);
 
-        WakeLockStats.WakeLock wakeLock1 = wakeLockStats.stream()
-                .filter(wl -> wl.uid == 10100 && wl.name.equals("wakeLock1")).findFirst().get();
+        mMockClock.realtime = 11000;
+        mBatteryStatsImpl.noteStopWakeLocked(
+                10400, 104, null, "wakeLock5", null, BatteryStats.WAKE_TYPE_PARTIAL);
 
-        assertThat(wakeLock1.timesAcquired).isEqualTo(1);
-        assertThat(wakeLock1.timeHeldMs).isEqualTo(0);  // Not currently held
-        assertThat(wakeLock1.totalTimeHeldMs).isEqualTo(2000); // 3000-1000
+        mMockClock.realtime = 12000;
+        mBatteryStatsImpl.noteStopWakeLocked(
+                10300, 102, null, "wakeLock3", null, BatteryStats.WAKE_TYPE_PARTIAL);
 
-        WakeLockStats.WakeLock wakeLock2 = wakeLockStats.stream()
-                .filter(wl -> wl.uid == 10200 && wl.name.equals("wakeLock2")).findFirst().get();
+        mMockClock.realtime = 13000;
 
-        assertThat(wakeLock2.timesAcquired).isEqualTo(2);
-        assertThat(wakeLock2.timeHeldMs).isEqualTo(3000);  // 9000-6000
-        assertThat(wakeLock2.totalTimeHeldMs).isEqualTo(4000); // (5000-4000) + (9000-6000)
+        // Verify un-aggregated wakelocks.
+        WakeLockStats wakeLockStats = mBatteryStatsImpl.getWakeLockStats();
+        List<WakeLockStats.WakeLock> wakeLockList = wakeLockStats.getWakeLocks();
+        assertThat(wakeLockList).hasSize(4);
+
+        WakeLockStats.WakeLock wakeLock1 = getWakeLockFromList(wakeLockList, 10100, "wakeLock1");
+        assertThat(wakeLock1.isAggregated).isFalse();
+        assertThat(wakeLock1.totalWakeLockData.timesAcquired).isEqualTo(1);
+        assertThat(wakeLock1.totalWakeLockData.timeHeldMs).isEqualTo(0); // Not currently held
+        assertThat(wakeLock1.totalWakeLockData.totalTimeHeldMs).isEqualTo(2000); // 3000-1000
+
+        WakeLockStats.WakeLock wakeLock3 = getWakeLockFromList(wakeLockList, 10300, "wakeLock3");
+        assertThat(wakeLock3.isAggregated).isFalse();
+        assertThat(wakeLock3.totalWakeLockData.timesAcquired).isEqualTo(1);
+        assertThat(wakeLock3.totalWakeLockData.timeHeldMs).isEqualTo(0); // Not currently held
+        // (8000-7000)/2 + (9000-8000)/3 + (10000-9000)/2 + (11000-10000)/3 + (12000-11000)/2
+        assertThat(wakeLock3.totalWakeLockData.totalTimeHeldMs).isEqualTo(2166);
+
+        WakeLockStats.WakeLock wakeLock4 = getWakeLockFromList(wakeLockList, 10400, "wakeLock4");
+        assertThat(wakeLock4.isAggregated).isFalse();
+        assertThat(wakeLock4.totalWakeLockData.timesAcquired).isEqualTo(1);
+        assertThat(wakeLock4.totalWakeLockData.timeHeldMs).isEqualTo(0); // Not currently held
+        assertThat(wakeLock4.totalWakeLockData.totalTimeHeldMs).isEqualTo(333); // (9000-8000)/3
+
+        WakeLockStats.WakeLock wakeLock5 = getWakeLockFromList(wakeLockList, 10400, "wakeLock5");
+        assertThat(wakeLock5.isAggregated).isFalse();
+        assertThat(wakeLock5.totalWakeLockData.timesAcquired).isEqualTo(1);
+        assertThat(wakeLock5.totalWakeLockData.timeHeldMs).isEqualTo(0); // Not currently held
+        assertThat(wakeLock5.totalWakeLockData.totalTimeHeldMs).isEqualTo(333); // (11000-10000)/3
+
+        // Verify aggregated wakelocks.
+        List<WakeLockStats.WakeLock> aggregatedWakeLockList =
+                wakeLockStats.getAggregatedWakeLocks();
+        assertThat(aggregatedWakeLockList).hasSize(4);
+
+        WakeLockStats.WakeLock aggregatedWakeLock1 =
+                getAggregatedWakeLockFromList(aggregatedWakeLockList, 10100);
+        assertThat(aggregatedWakeLock1.isAggregated).isTrue();
+        assertThat(aggregatedWakeLock1.totalWakeLockData.timesAcquired).isEqualTo(1);
+        // Not currently held
+        assertThat(aggregatedWakeLock1.totalWakeLockData.timeHeldMs).isEqualTo(0);
+        // 3000-1000
+        assertThat(aggregatedWakeLock1.totalWakeLockData.totalTimeHeldMs).isEqualTo(2000);
+
+        WakeLockStats.WakeLock aggregatedWakeLock2 =
+                getAggregatedWakeLockFromList(aggregatedWakeLockList, 10200);
+        assertThat(aggregatedWakeLock2.isAggregated).isTrue();
+        assertThat(aggregatedWakeLock2.totalWakeLockData.timesAcquired).isEqualTo(2);
+        assertThat(aggregatedWakeLock2.totalWakeLockData.timeHeldMs).isEqualTo(7000); // 13000-6000
+        // (5000-4000) + (13000-6000)
+        assertThat(aggregatedWakeLock2.totalWakeLockData.totalTimeHeldMs)
+                .isEqualTo(8000);
+
+        WakeLockStats.WakeLock aggregatedWakeLock3 =
+                getAggregatedWakeLockFromList(aggregatedWakeLockList, 10300);
+        assertThat(aggregatedWakeLock3.isAggregated).isTrue();
+        assertThat(aggregatedWakeLock3.totalWakeLockData.timesAcquired).isEqualTo(1);
+        // Not currently held
+        assertThat(aggregatedWakeLock3.totalWakeLockData.timeHeldMs).isEqualTo(0);
+        // 12000-7000
+        assertThat(aggregatedWakeLock3.totalWakeLockData.totalTimeHeldMs).isEqualTo(5000);
+
+        WakeLockStats.WakeLock aggregatedWakeLock4 =
+                getAggregatedWakeLockFromList(aggregatedWakeLockList, 10400);
+        assertThat(aggregatedWakeLock4.isAggregated).isTrue();
+        assertThat(aggregatedWakeLock4.totalWakeLockData.timesAcquired).isEqualTo(2);
+        // Not currently held
+        assertThat(aggregatedWakeLock4.totalWakeLockData.timeHeldMs).isEqualTo(0);
+        assertThat(aggregatedWakeLock4.totalWakeLockData.totalTimeHeldMs)
+                .isEqualTo(2000); // (9000-8000) + (11000-10000)
+    }
+
+    private WakeLockStats.WakeLock getAggregatedWakeLockFromList(
+            List<WakeLockStats.WakeLock> wakeLockList, final int uid) {
+        return getWakeLockFromList(wakeLockList, uid, WakeLockStats.WakeLock.NAME_AGGREGATED);
+    }
+
+    private WakeLockStats.WakeLock getWakeLockFromList(
+            List<WakeLockStats.WakeLock> wakeLockList, final int uid, final String name) {
+        return wakeLockList.stream()
+            .filter(wl -> wl.uid == uid && wl.name.equals(name))
+            .findFirst()
+            .get();
     }
 
     @Test
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java
index ae6984e..374426a 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsProviderTest.java
@@ -55,7 +55,6 @@
 
 import java.io.File;
 import java.io.IOException;
-import java.nio.file.Files;
 import java.util.List;
 
 @SmallTest
@@ -70,11 +69,10 @@
     private static final long MINUTE_IN_MS = 60 * 1000;
     private static final double PRECISION = 0.00001;
 
-    private File mHistoryDir;
-
     @Rule(order = 1)
     public final BatteryUsageStatsRule mStatsRule =
-            new BatteryUsageStatsRule(12345, mHistoryDir)
+            new BatteryUsageStatsRule(12345)
+                    .createTempDirectory()
                     .setAveragePower(PowerProfile.POWER_FLASHLIGHT, 360.0)
                     .setAveragePower(PowerProfile.POWER_AUDIO, 720.0);
 
@@ -83,9 +81,6 @@
 
     @Before
     public void setup() throws IOException {
-        mHistoryDir = Files.createTempDirectory("BatteryUsageStatsProviderTest").toFile();
-        clearDirectory(mHistoryDir);
-
         if (RavenwoodRule.isUnderRavenwood()) {
             mContext = mock(Context.class);
             SensorManager sensorManager = mock(SensorManager.class);
@@ -95,17 +90,6 @@
         }
     }
 
-    private void clearDirectory(File dir) {
-        if (dir.exists()) {
-            for (File child : dir.listFiles()) {
-                if (child.isDirectory()) {
-                    clearDirectory(child);
-                }
-                child.delete();
-            }
-        }
-    }
-
     @Test
     public void test_getBatteryUsageStats() {
         BatteryStatsImpl batteryStats = prepareBatteryStats();
@@ -423,7 +407,7 @@
         }
 
         PowerStatsStore powerStatsStore = new PowerStatsStore(
-                new File(mHistoryDir, "powerstatsstore"),
+                new File(mStatsRule.getHistoryDir(), "powerstatsstore"),
                 mStatsRule.getHandler(), null);
         powerStatsStore.reset();
 
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java
index 7e8fa55..296ad0e 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/BatteryUsageStatsRule.java
@@ -35,7 +35,6 @@
 import android.os.HandlerThread;
 import android.os.UidBatteryConsumer;
 import android.os.UserBatteryConsumer;
-import android.platform.test.ravenwood.RavenwoodRule;
 import android.util.SparseArray;
 
 import androidx.test.InstrumentationRegistry;
@@ -50,6 +49,8 @@
 import org.mockito.stubbing.Answer;
 
 import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
 import java.util.Arrays;
 
 @SuppressWarnings("SynchronizeOnNonFinalField")
@@ -62,7 +63,9 @@
 
     private final PowerProfile mPowerProfile;
     private final MockClock mMockClock = new MockClock();
-    private final File mHistoryDir;
+    private String mTestName;
+    private boolean mCreateTempDirectory;
+    private File mHistoryDir;
     private MockBatteryStatsImpl mBatteryStats;
     private Handler mHandler;
 
@@ -80,32 +83,30 @@
     private Throwable mThrowable;
 
     public BatteryUsageStatsRule() {
-        this(0, null);
+        this(0);
     }
 
     public BatteryUsageStatsRule(long currentTime) {
-        this(currentTime, null);
-    }
-
-    public BatteryUsageStatsRule(long currentTime, File historyDir) {
         mHandler = mock(Handler.class);
         mPowerProfile = spy(new PowerProfile());
         mMockClock.currentTime = currentTime;
-        mHistoryDir = historyDir;
-
-        if (!RavenwoodRule.isUnderRavenwood()) {
-            lateInitBatteryStats();
-        }
-
         mCpusByPolicy.put(0, new int[]{0, 1, 2, 3});
         mCpusByPolicy.put(4, new int[]{4, 5, 6, 7});
         mFreqsByPolicy.put(0, new int[]{300000, 1000000, 2000000});
         mFreqsByPolicy.put(4, new int[]{300000, 1000000, 2500000, 3000000});
     }
 
-    private void lateInitBatteryStats() {
+    private void initBatteryStats() {
         if (mBatteryStats != null) return;
 
+        if (mCreateTempDirectory) {
+            try {
+                mHistoryDir = Files.createTempDirectory(mTestName).toFile();
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+            clearDirectory();
+        }
         mBatteryStats = new MockBatteryStatsImpl(mMockClock, mHistoryDir, mHandler);
         mBatteryStats.setPowerProfile(mPowerProfile);
         mBatteryStats.setCpuScalingPolicies(new CpuScalingPolicies(mCpusByPolicy, mFreqsByPolicy));
@@ -138,6 +139,15 @@
         return mHandler;
     }
 
+    public File getHistoryDir() {
+        return mHistoryDir;
+    }
+
+    public BatteryUsageStatsRule createTempDirectory() {
+        mCreateTempDirectory = true;
+        return this;
+    }
+
     public BatteryUsageStatsRule setTestPowerProfile(@XmlRes int xmlId) {
         mPowerProfile.forceInitForTesting(InstrumentationRegistry.getContext(), xmlId);
         return this;
@@ -269,6 +279,7 @@
 
     @Override
     public Statement apply(Statement base, Description description) {
+        mTestName = description.getClassName() + "#" + description.getMethodName();
         return new Statement() {
             @Override
             public void evaluate() throws Throwable {
@@ -280,7 +291,7 @@
     }
 
     private void before() {
-        lateInitBatteryStats();
+        initBatteryStats();
         HandlerThread bgThread = new HandlerThread("bg thread");
         bgThread.setUncaughtExceptionHandler((thread, throwable)-> {
             mThrowable = throwable;
@@ -324,6 +335,9 @@
     }
 
     public MockBatteryStatsImpl getBatteryStats() {
+        if (mBatteryStats == null) {
+            initBatteryStats();
+        }
         return mBatteryStats;
     }
 
@@ -397,4 +411,19 @@
         }
         return null;
     }
+
+    public void clearDirectory() {
+        clearDirectory(mHistoryDir);
+    }
+
+    private void clearDirectory(File dir) {
+        if (dir.exists()) {
+            for (File child : dir.listFiles()) {
+                if (child.isDirectory()) {
+                    clearDirectory(child);
+                }
+                child.delete();
+            }
+        }
+    }
 }
diff --git a/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsAggregatorTest.java b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsAggregatorTest.java
index af5b462..2ea86a4 100644
--- a/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsAggregatorTest.java
+++ b/services/tests/powerstatstests/src/com/android/server/power/stats/PowerStatsAggregatorTest.java
@@ -58,7 +58,7 @@
 
     @Before
     public void setup() throws ParseException {
-        mHistory = new BatteryStatsHistory(32, 1024,
+        mHistory = new BatteryStatsHistory(1024,
                 mock(BatteryStatsHistory.HistoryStepDetailsCalculator.class), mClock,
                 mMonotonicClock, mock(BatteryStatsHistory.TraceDelegate.class), null);
 
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 3743483..37967fa 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -85,6 +85,7 @@
         "ravenwood-junit",
         "net_flags_lib",
         "CtsVirtualDeviceCommonLib",
+        "com_android_server_accessibility_flags_lib",
     ],
 
     libs: [
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterInputTest.kt b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterInputTest.kt
index 5c8c6bb..e6c94c5 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterInputTest.kt
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityInputFilterInputTest.kt
@@ -25,6 +25,7 @@
 import android.view.DisplayAdjustments
 import android.view.DisplayInfo
 import android.view.IInputFilterHost
+import android.view.InputDevice.SOURCE_JOYSTICK
 import android.view.InputDevice.SOURCE_STYLUS
 import android.view.InputDevice.SOURCE_TOUCHSCREEN
 import android.view.InputEvent
@@ -130,6 +131,8 @@
     private val fromTouchScreen = allOf(withDeviceId(touchDeviceId), withSource(SOURCE_TOUCHSCREEN))
     private val stylusDeviceId = 2
     private val fromStylus = allOf(withDeviceId(stylusDeviceId), withSource(STYLUS_SOURCE))
+    private val joystickDeviceId = 3
+    private val fromJoystick = allOf(withDeviceId(joystickDeviceId), withSource(SOURCE_JOYSTICK))
 
     @Before
     fun setUp() {
@@ -457,6 +460,23 @@
         verifier.assertNoEvents()
     }
 
+    /**
+     * Send some joystick events and ensure they pass through normally.
+     */
+    @Test
+    fun testJoystickEvents() {
+        enableFeatures(ALL_A11Y_FEATURES)
+
+        sendJoystickEvent()
+        verifier.assertReceivedMotion(fromJoystick)
+
+        sendJoystickEvent()
+        verifier.assertReceivedMotion(fromJoystick)
+
+        sendJoystickEvent()
+        verifier.assertReceivedMotion(fromJoystick)
+    }
+
     private fun createStubDisplay(displayId: Int, displayInfo: DisplayInfo): Display {
         val display = Display(DisplayManagerGlobal.getInstance(), displayId,
             displayInfo, DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS)
@@ -477,6 +497,11 @@
         send(createMotionEvent(action, downTime, eventTime, STYLUS_SOURCE, stylusDeviceId))
     }
 
+    private fun sendJoystickEvent() {
+        val time = SystemClock.uptimeMillis()
+        send(createMotionEvent(ACTION_MOVE, time, time, SOURCE_JOYSTICK, joystickDeviceId))
+    }
+
     private fun send(event: InputEvent) {
         // We need to make a copy of the event before sending it to the filter, because the filter
         // will recycle it, but the caller of this function might want to still be able to use
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
index 89d146d..8717a05 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerTest.java
@@ -47,6 +47,9 @@
 import android.os.LocaleList;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.util.SparseArray;
 import android.view.Display;
 import android.view.IWindow;
@@ -67,6 +70,7 @@
 import org.hamcrest.TypeSafeMatcher;
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
@@ -77,9 +81,16 @@
 import java.util.Arrays;
 import java.util.List;
 
+// This test verifies deprecated codepath. Probably changing this file means
+// AccessibilityWindowManagerWithAccessibilityWindowTest also needs to be updated.
+// LINT.IfChange
+
 /**
- * Tests for the AccessibilityWindowManager
+ * Tests for the AccessibilityWindowManager with Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y enabled.
+ * TODO(b/322444245): Merge with AccessibilityWindowManagerWithAccessibilityWindowTest
+ *  after completing the flag migration.
  */
+@RequiresFlagsDisabled(Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y)
 public class AccessibilityWindowManagerTest {
     private static final String PACKAGE_NAME = "com.android.server.accessibility";
     private static final boolean FORCE_SEND = true;
@@ -132,6 +143,9 @@
     @Mock private IBinder mMockEmbeddedToken;
     @Mock private IBinder mMockInvalidToken;
 
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
     @Before
     public void setUp() throws RemoteException {
         MockitoAnnotations.initMocks(this);
@@ -1227,3 +1241,4 @@
         }
     }
 }
+// LINT.ThenChange(/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java)
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java
new file mode 100644
index 0000000..4db27d2
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityWindowManagerWithAccessibilityWindowTest.java
@@ -0,0 +1,1247 @@
+/*
+ * Copyright (C) 2019 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.server.accessibility;
+
+import static com.android.server.accessibility.AbstractAccessibilityServiceConnection.DISPLAY_TYPE_DEFAULT;
+import static com.android.server.accessibility.AccessibilityWindowManagerTest.DisplayIdMatcher.displayId;
+import static com.android.server.accessibility.AccessibilityWindowManagerTest.WindowChangesMatcher.a11yWindowChanges;
+import static com.android.server.accessibility.AccessibilityWindowManagerTest.WindowIdMatcher.a11yWindowId;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+
+import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertThat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.annotation.Nullable;
+import android.graphics.Region;
+import android.os.IBinder;
+import android.os.LocaleList;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.util.SparseArray;
+import android.view.Display;
+import android.view.IWindow;
+import android.view.WindowInfo;
+import android.view.WindowManager;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityWindowAttributes;
+import android.view.accessibility.AccessibilityWindowInfo;
+import android.view.accessibility.IAccessibilityInteractionConnection;
+
+import com.android.server.accessibility.AccessibilityWindowManager.RemoteAccessibilityConnection;
+import com.android.server.accessibility.test.MessageCapturingHandler;
+import com.android.server.wm.WindowManagerInternal;
+import com.android.server.wm.WindowManagerInternal.WindowsForAccessibilityCallback;
+
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeMatcher;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Tests for the AccessibilityWindowManager with Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y
+ * TODO(b/322444245): Merge with AccessibilityWindowManagerTest
+ *  after completing the flag migration.
+ */
+@RequiresFlagsEnabled(Flags.FLAG_COMPUTE_WINDOW_CHANGES_ON_A11Y)
+public class AccessibilityWindowManagerWithAccessibilityWindowTest {
+    private static final String PACKAGE_NAME = "com.android.server.accessibility";
+    private static final boolean FORCE_SEND = true;
+    private static final boolean SEND_ON_WINDOW_CHANGES = false;
+    private static final int USER_SYSTEM_ID = UserHandle.USER_SYSTEM;
+    private static final int USER_PROFILE = 11;
+    private static final int USER_PROFILE_PARENT = 1;
+    private static final int SECONDARY_DISPLAY_ID = Display.DEFAULT_DISPLAY + 1;
+    private static final int NUM_GLOBAL_WINDOWS = 4;
+    private static final int NUM_APP_WINDOWS = 4;
+    private static final int NUM_OF_WINDOWS = (NUM_GLOBAL_WINDOWS + NUM_APP_WINDOWS);
+    private static final int DEFAULT_FOCUSED_INDEX = 1;
+    private static final int SCREEN_WIDTH = 1080;
+    private static final int SCREEN_HEIGHT = 1920;
+    private static final int INVALID_ID = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID;
+    private static final int HOST_WINDOW_ID = 10;
+    private static final int EMBEDDED_WINDOW_ID = 11;
+    private static final int OTHER_WINDOW_ID = 12;
+
+    private AccessibilityWindowManager mA11yWindowManager;
+    // Window manager will support multiple focused window if config_perDisplayFocusEnabled is true,
+    // i.e., each display would have its current focused window, and one of all focused windows
+    // would be top focused window. Otherwise, window manager only supports one focused window
+    // at all displays, and that focused window would be top focused window.
+    private boolean mSupportPerDisplayFocus = false;
+    private int mTopFocusedDisplayId = Display.INVALID_DISPLAY;
+    private IBinder mTopFocusedWindowToken = null;
+
+    // List of window token, mapping from windowId -> window token.
+    private final SparseArray<IWindow> mA11yWindowTokens = new SparseArray<>();
+    // List of window info lists, mapping from displayId -> window info lists.
+    private final SparseArray<ArrayList<WindowInfo>> mWindowInfos =
+            new SparseArray<>();
+    // List of callback, mapping from displayId -> callback.
+    private final SparseArray<WindowsForAccessibilityCallback> mCallbackOfWindows =
+            new SparseArray<>();
+    // List of display ID.
+    private final ArrayList<Integer> mExpectedDisplayList = new ArrayList<>(Arrays.asList(
+            Display.DEFAULT_DISPLAY, SECONDARY_DISPLAY_ID));
+
+    private final MessageCapturingHandler mHandler = new MessageCapturingHandler(null);
+
+    @Mock
+    private WindowManagerInternal mMockWindowManagerInternal;
+    @Mock
+    private AccessibilityWindowManager.AccessibilityEventSender mMockA11yEventSender;
+    @Mock
+    private AccessibilitySecurityPolicy mMockA11ySecurityPolicy;
+    @Mock
+    private AccessibilitySecurityPolicy.AccessibilityUserManager mMockA11yUserManager;
+    @Mock
+    private AccessibilityTraceManager mMockA11yTraceManager;
+
+    @Mock
+    private IBinder mMockHostToken;
+    @Mock
+    private IBinder mMockEmbeddedToken;
+    @Mock
+    private IBinder mMockInvalidToken;
+
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
+    @Before
+    public void setUp() throws RemoteException {
+        MockitoAnnotations.initMocks(this);
+        when(mMockA11yUserManager.getCurrentUserIdLocked()).thenReturn(USER_SYSTEM_ID);
+        when(mMockA11ySecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(
+                USER_PROFILE)).thenReturn(USER_PROFILE_PARENT);
+        when(mMockA11ySecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked(
+                USER_SYSTEM_ID)).thenReturn(USER_SYSTEM_ID);
+        when(mMockA11ySecurityPolicy.resolveValidReportedPackageLocked(
+                anyString(), anyInt(), anyInt(), anyInt())).thenReturn(PACKAGE_NAME);
+
+        doAnswer((invocation) -> {
+            onWindowsForAccessibilityChanged(invocation.getArgument(0), false);
+            return null;
+        }).when(mMockWindowManagerInternal).computeWindowsForAccessibility(anyInt());
+
+        mA11yWindowManager = new AccessibilityWindowManager(new Object(), mHandler,
+                mMockWindowManagerInternal,
+                mMockA11yEventSender,
+                mMockA11ySecurityPolicy,
+                mMockA11yUserManager,
+                mMockA11yTraceManager);
+        // Starts tracking window of default display and sets the default display
+        // as top focused display before each testing starts.
+        startTrackingPerDisplay(Display.DEFAULT_DISPLAY);
+
+        // AccessibilityEventSender is invoked during onWindowsForAccessibilityChanged.
+        // Resets it for mockito verify of further test case.
+        Mockito.reset(mMockA11yEventSender);
+
+        registerLeashedTokenAndWindowId();
+    }
+
+    @After
+    public void tearDown() {
+        mHandler.removeAllMessages();
+    }
+
+    @Test
+    public void startTrackingWindows_shouldEnableWindowManagerCallback() {
+        // AccessibilityWindowManager#startTrackingWindows already invoked in setup.
+        assertTrue(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY));
+        final WindowsForAccessibilityCallback callbacks =
+                mCallbackOfWindows.get(Display.DEFAULT_DISPLAY);
+        verify(mMockWindowManagerInternal).setWindowsForAccessibilityCallback(
+                eq(Display.DEFAULT_DISPLAY), eq(callbacks));
+    }
+
+    @Test
+    public void stopTrackingWindows_shouldDisableWindowManagerCallback() {
+        assertTrue(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY));
+        Mockito.reset(mMockWindowManagerInternal);
+
+        mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY);
+        assertFalse(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY));
+        verify(mMockWindowManagerInternal).setWindowsForAccessibilityCallback(
+                eq(Display.DEFAULT_DISPLAY), isNull());
+
+    }
+
+    @Test
+    public void stopTrackingWindows_shouldClearWindows() {
+        assertTrue(mA11yWindowManager.isTrackingWindowsLocked(Display.DEFAULT_DISPLAY));
+        final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
+
+        mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY);
+        assertNull(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY));
+        assertEquals(mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT),
+                AccessibilityWindowInfo.UNDEFINED_WINDOW_ID);
+        assertEquals(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID),
+                activeWindowId);
+    }
+
+    @Test
+    public void stopTrackingWindows_onNonTopFocusedDisplay_shouldNotResetTopFocusWindow()
+            throws RemoteException {
+        // At setup, the default display sets be the top focused display and
+        // its current focused window sets be the top focused window.
+        // Starts tracking window of second display.
+        startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
+        assertTrue(mA11yWindowManager.isTrackingWindowsLocked(SECONDARY_DISPLAY_ID));
+        // Stops tracking windows of second display.
+        mA11yWindowManager.stopTrackingWindows(SECONDARY_DISPLAY_ID);
+        assertNotEquals(mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT),
+                AccessibilityWindowInfo.UNDEFINED_WINDOW_ID);
+    }
+
+    @Test
+    public void onWindowsChanged_duringTouchInteractAndFocusChange_shouldChangeActiveWindow() {
+        final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
+        WindowInfo focusedWindowInfo =
+                mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX);
+        assertEquals(activeWindowId, mA11yWindowManager.findWindowIdLocked(
+                USER_SYSTEM_ID, focusedWindowInfo.token));
+
+        focusedWindowInfo.focused = false;
+        focusedWindowInfo =
+                mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX + 1);
+        focusedWindowInfo.focused = true;
+
+        mA11yWindowManager.onTouchInteractionStart();
+        setTopFocusedWindowAndDisplay(Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX + 1);
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+        assertNotEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
+    }
+
+    @Test
+    public void
+            onWindowsChanged_focusChangeOnNonTopFocusedDisplay_perDisplayFocusOn_notChangeWindow()
+            throws RemoteException {
+        // At setup, the default display sets be the top focused display and
+        // its current focused window sets be the top focused window.
+        // Sets supporting multiple focused window, i.e., config_perDisplayFocusEnabled is true.
+        mSupportPerDisplayFocus = true;
+        // Starts tracking window of second display.
+        startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
+        // Gets the active window.
+        final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
+        // Gets the top focused window.
+        final int topFocusedWindowId =
+                mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT);
+        // Changes the current focused window at second display.
+        changeFocusedWindowOnDisplayPerDisplayFocusConfig(SECONDARY_DISPLAY_ID,
+                DEFAULT_FOCUSED_INDEX + 1, Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX);
+
+        onWindowsForAccessibilityChanged(SECONDARY_DISPLAY_ID, SEND_ON_WINDOW_CHANGES);
+        // The active window should not be changed.
+        assertEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
+        // The top focused window should not be changed.
+        assertEquals(topFocusedWindowId,
+                mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT));
+    }
+
+    @Test
+    public void
+            onWindowChange_focusChangeToNonTopFocusedDisplay_perDisplayFocusOff_shouldChangeWindow()
+            throws RemoteException {
+        // At setup, the default display sets be the top focused display and
+        // its current focused window sets be the top focused window.
+        // Sets not supporting multiple focused window, i.e., config_perDisplayFocusEnabled is
+        // false.
+        mSupportPerDisplayFocus = false;
+        // Starts tracking window of second display.
+        startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
+        // Gets the active window.
+        final int activeWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
+        // Gets the top focused window.
+        final int topFocusedWindowId =
+                mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT);
+        // Changes the current focused window from default display to second display.
+        changeFocusedWindowOnDisplayPerDisplayFocusConfig(SECONDARY_DISPLAY_ID,
+                DEFAULT_FOCUSED_INDEX, Display.DEFAULT_DISPLAY, DEFAULT_FOCUSED_INDEX);
+
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        onWindowsForAccessibilityChanged(SECONDARY_DISPLAY_ID, SEND_ON_WINDOW_CHANGES);
+        // The active window should be changed.
+        assertNotEquals(activeWindowId, mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID));
+        // The top focused window should be changed.
+        assertNotEquals(topFocusedWindowId,
+                mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT));
+    }
+
+    @Test
+    public void onWindowsChanged_shouldReportCorrectLayer() {
+        // AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup.
+        List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        for (int i = 0; i < a11yWindows.size(); i++) {
+            final AccessibilityWindowInfo a11yWindow = a11yWindows.get(i);
+            final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(i);
+            assertThat(mWindowInfos.get(Display.DEFAULT_DISPLAY).size() - windowInfo.layer - 1,
+                    is(a11yWindow.getLayer()));
+        }
+    }
+
+    @Test
+    public void onWindowsChanged_shouldReportCorrectOrder() {
+        // AccessibilityWindowManager#onWindowsForAccessibilityChanged already invoked in setup.
+        List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        for (int i = 0; i < a11yWindows.size(); i++) {
+            final AccessibilityWindowInfo a11yWindow = a11yWindows.get(i);
+            final IBinder windowToken = mA11yWindowManager
+                    .getWindowTokenForUserAndWindowIdLocked(USER_SYSTEM_ID, a11yWindow.getId());
+            final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(i);
+            assertThat(windowToken, is(windowInfo.token));
+        }
+    }
+
+    @Test
+    public void onWindowsChangedAndForceSend_shouldUpdateWindows() {
+        final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
+        final int correctLayer =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer();
+        windowInfo.layer += 1;
+
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
+        assertNotEquals(correctLayer,
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer());
+    }
+
+    @Test
+    public void onWindowsChangedNoForceSend_layerChanged_shouldNotUpdateWindows() {
+        final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
+        final int correctLayer =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer();
+        windowInfo.layer += 1;
+
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        assertEquals(correctLayer,
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0).getLayer());
+    }
+
+    @Test
+    public void onWindowsChangedNoForceSend_windowChanged_shouldUpdateWindows()
+            throws RemoteException {
+        final AccessibilityWindowInfo oldWindow =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0);
+        final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+                true, USER_SYSTEM_ID);
+        final WindowInfo windowInfo = WindowInfo.obtain();
+        windowInfo.type = AccessibilityWindowInfo.TYPE_APPLICATION;
+        windowInfo.token = token.asBinder();
+        windowInfo.layer = 0;
+        windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+        mWindowInfos.get(Display.DEFAULT_DISPLAY).set(0, windowInfo);
+
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        assertNotEquals(oldWindow,
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0));
+    }
+
+    @Test
+    public void onWindowsChangedNoForceSend_focusChanged_shouldUpdateWindows() {
+        final WindowInfo focusedWindowInfo =
+                mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX);
+        final WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
+        focusedWindowInfo.focused = false;
+        windowInfo.focused = true;
+
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        assertTrue(mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY).get(0)
+                .isFocused());
+    }
+
+    @Test
+    public void removeAccessibilityInteractionConnection_byWindowToken_shouldRemoved() {
+        for (int i = 0; i < NUM_OF_WINDOWS; i++) {
+            final int windowId = mA11yWindowTokens.keyAt(i);
+            final IWindow windowToken = mA11yWindowTokens.valueAt(i);
+            assertNotNull(mA11yWindowManager.getConnectionLocked(USER_SYSTEM_ID, windowId));
+
+            mA11yWindowManager.removeAccessibilityInteractionConnection(windowToken);
+            assertNull(mA11yWindowManager.getConnectionLocked(USER_SYSTEM_ID, windowId));
+        }
+    }
+
+    @Test
+    public void remoteAccessibilityConnection_binderDied_shouldRemoveConnection() {
+        for (int i = 0; i < NUM_OF_WINDOWS; i++) {
+            final int windowId = mA11yWindowTokens.keyAt(i);
+            final RemoteAccessibilityConnection remoteA11yConnection =
+                    mA11yWindowManager.getConnectionLocked(USER_SYSTEM_ID, windowId);
+            assertNotNull(remoteA11yConnection);
+
+            remoteA11yConnection.binderDied();
+            assertNull(mA11yWindowManager.getConnectionLocked(USER_SYSTEM_ID, windowId));
+        }
+    }
+
+    @Test
+    public void getWindowTokenForUserAndWindowId_shouldNotNull() {
+        final List<AccessibilityWindowInfo> windows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        for (int i = 0; i < windows.size(); i++) {
+            final int windowId = windows.get(i).getId();
+
+            assertNotNull(mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(
+                    USER_SYSTEM_ID, windowId));
+        }
+    }
+
+    @Test
+    public void findWindowId() {
+        final List<AccessibilityWindowInfo> windows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        for (int i = 0; i < windows.size(); i++) {
+            final int windowId = windows.get(i).getId();
+            final IBinder windowToken = mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(
+                    USER_SYSTEM_ID, windowId);
+
+            assertEquals(mA11yWindowManager.findWindowIdLocked(
+                    USER_SYSTEM_ID, windowToken), windowId);
+        }
+    }
+
+    @Test
+    public void resolveParentWindowId_windowIsNotEmbedded_shouldReturnGivenId()
+            throws RemoteException {
+        final int windowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY, false,
+                Mockito.mock(IBinder.class), USER_SYSTEM_ID);
+        assertEquals(windowId, mA11yWindowManager.resolveParentWindowIdLocked(windowId));
+    }
+
+    @Test
+    public void resolveParentWindowId_windowIsNotRegistered_shouldReturnGivenId() {
+        final int windowId = -1;
+        assertEquals(windowId, mA11yWindowManager.resolveParentWindowIdLocked(windowId));
+    }
+
+    @Test
+    public void resolveParentWindowId_windowIsAssociated_shouldReturnParentWindowId()
+            throws RemoteException {
+        final IBinder mockHostToken = Mockito.mock(IBinder.class);
+        final IBinder mockEmbeddedToken = Mockito.mock(IBinder.class);
+        final int hostWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+                false, mockHostToken, USER_SYSTEM_ID);
+        final int embeddedWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+                false, mockEmbeddedToken, USER_SYSTEM_ID);
+
+        mA11yWindowManager.associateEmbeddedHierarchyLocked(mockHostToken, mockEmbeddedToken);
+
+        final int resolvedWindowId = mA11yWindowManager.resolveParentWindowIdLocked(
+                embeddedWindowId);
+        assertEquals(hostWindowId, resolvedWindowId);
+    }
+
+    @Test
+    public void resolveParentWindowId_windowIsDisassociated_shouldReturnGivenId()
+            throws RemoteException {
+        final IBinder mockHostToken = Mockito.mock(IBinder.class);
+        final IBinder mockEmbeddedToken = Mockito.mock(IBinder.class);
+        final int hostWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+                false, mockHostToken, USER_SYSTEM_ID);
+        final int embeddedWindowId = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+                false, mockEmbeddedToken, USER_SYSTEM_ID);
+
+        mA11yWindowManager.associateEmbeddedHierarchyLocked(mockHostToken, mockEmbeddedToken);
+        mA11yWindowManager.disassociateEmbeddedHierarchyLocked(mockEmbeddedToken);
+
+        final int resolvedWindowId = mA11yWindowManager.resolveParentWindowIdLocked(
+                embeddedWindowId);
+        assertNotEquals(hostWindowId, resolvedWindowId);
+        assertEquals(embeddedWindowId, resolvedWindowId);
+    }
+
+    @Test
+    public void computePartialInteractiveRegionForWindow_wholeVisible_returnWholeRegion() {
+        // Updates top 2 z-order WindowInfo are whole visible.
+        WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
+        windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2);
+        windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(1);
+        windowInfo.regionInScreen.set(0, SCREEN_HEIGHT / 2,
+                SCREEN_WIDTH, SCREEN_HEIGHT);
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+        final List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        final Region outBounds = new Region();
+        int windowId = a11yWindows.get(0).getId();
+
+        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
+        assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH));
+        assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT / 2));
+
+        windowId = a11yWindows.get(1).getId();
+
+        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
+        assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH));
+        assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT / 2));
+    }
+
+    @Test
+    public void computePartialInteractiveRegionForWindow_halfVisible_returnHalfRegion() {
+        // Updates z-order #1 WindowInfo is half visible.
+        WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
+        windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT / 2);
+
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+        final List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        final Region outBounds = new Region();
+        int windowId = a11yWindows.get(1).getId();
+
+        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
+        assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH));
+        assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT / 2));
+    }
+
+    @Test
+    public void computePartialInteractiveRegionForWindow_notVisible_returnEmptyRegion() {
+        // Since z-order #0 WindowInfo is full screen, z-order #1 WindowInfo should be invisible.
+        final List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        final Region outBounds = new Region();
+        int windowId = a11yWindows.get(1).getId();
+
+        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
+        assertTrue(outBounds.getBounds().isEmpty());
+    }
+
+    @Test
+    public void computePartialInteractiveRegionForWindow_partialVisible_returnVisibleRegion() {
+        // Updates z-order #0 WindowInfo to have two interact-able areas.
+        Region region = new Region(0, 0, SCREEN_WIDTH, 200);
+        region.op(0, SCREEN_HEIGHT - 200, SCREEN_WIDTH, SCREEN_HEIGHT, Region.Op.UNION);
+        WindowInfo windowInfo = mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0);
+        windowInfo.regionInScreen.set(region);
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+        final List<AccessibilityWindowInfo> a11yWindows =
+                mA11yWindowManager.getWindowListLocked(Display.DEFAULT_DISPLAY);
+        final Region outBounds = new Region();
+        int windowId = a11yWindows.get(1).getId();
+
+        mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(windowId, outBounds);
+        assertFalse(outBounds.getBounds().isEmpty());
+        assertThat(outBounds.getBounds().width(), is(SCREEN_WIDTH));
+        assertThat(outBounds.getBounds().height(), is(SCREEN_HEIGHT - 400));
+    }
+
+    @Test
+    public void updateActiveAndA11yFocusedWindow_windowStateChangedEvent_noTracking_shouldUpdate() {
+        final IBinder eventWindowToken =
+                mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX + 1).token;
+        final int eventWindowId = mA11yWindowManager.findWindowIdLocked(
+                USER_SYSTEM_ID, eventWindowToken);
+        when(mMockWindowManagerInternal.getFocusedWindowTokenFromWindowStates())
+                .thenReturn(eventWindowToken);
+
+        final int noUse = 0;
+        mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY);
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                eventWindowId,
+                noUse,
+                AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
+                noUse);
+        assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(eventWindowId));
+        assertThat(mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT),
+                is(eventWindowId));
+    }
+
+    @Test
+    public void updateActiveAndA11yFocusedWindow_hoverEvent_touchInteract_shouldSetActiveWindow() {
+        final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
+                DEFAULT_FOCUSED_INDEX + 1);
+        final int currentActiveWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
+        assertThat(currentActiveWindowId, is(not(eventWindowId)));
+
+        final int noUse = 0;
+        mA11yWindowManager.onTouchInteractionStart();
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                eventWindowId,
+                noUse,
+                AccessibilityEvent.TYPE_VIEW_HOVER_ENTER,
+                noUse);
+        assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(eventWindowId));
+        final ArgumentCaptor<AccessibilityEvent> captor =
+                ArgumentCaptor.forClass(AccessibilityEvent.class);
+        verify(mMockA11yEventSender, times(2))
+                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
+        assertThat(captor.getAllValues().get(0),
+                allOf(displayId(Display.DEFAULT_DISPLAY),
+                        a11yWindowId(currentActiveWindowId),
+                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
+        assertThat(captor.getAllValues().get(1),
+                allOf(displayId(Display.DEFAULT_DISPLAY),
+                        a11yWindowId(eventWindowId),
+                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
+    }
+
+    @Test
+    public void updateActiveAndA11yFocusedWindow_a11yFocusEvent_shouldUpdateA11yFocus() {
+        final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
+                DEFAULT_FOCUSED_INDEX);
+        final int currentA11yFocusedWindowId = mA11yWindowManager.getFocusedWindowId(
+                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
+        assertThat(currentA11yFocusedWindowId, is(AccessibilityWindowInfo.UNDEFINED_WINDOW_ID));
+
+        final int noUse = 0;
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                eventWindowId,
+                AccessibilityNodeInfo.ROOT_NODE_ID,
+                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
+                noUse);
+        assertThat(mA11yWindowManager.getFocusedWindowId(
+                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(eventWindowId));
+        final ArgumentCaptor<AccessibilityEvent> captor =
+                ArgumentCaptor.forClass(AccessibilityEvent.class);
+        verify(mMockA11yEventSender, times(1))
+                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
+        assertThat(captor.getAllValues().get(0),
+                allOf(displayId(Display.DEFAULT_DISPLAY),
+                        a11yWindowId(eventWindowId),
+                        a11yWindowChanges(
+                                AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
+    }
+
+    @Test
+    public void updateActiveAndA11yFocusedWindow_a11yFocusEvent_multiDisplay_defaultToSecondary()
+            throws RemoteException {
+        runUpdateActiveAndA11yFocusedWindow_MultiDisplayTest(
+                Display.DEFAULT_DISPLAY, SECONDARY_DISPLAY_ID);
+    }
+
+    @Test
+    public void updateActiveAndA11yFocusedWindow_a11yFocusEvent_multiDisplay_SecondaryToDefault()
+            throws RemoteException {
+        runUpdateActiveAndA11yFocusedWindow_MultiDisplayTest(
+                SECONDARY_DISPLAY_ID, Display.DEFAULT_DISPLAY);
+    }
+
+    private void runUpdateActiveAndA11yFocusedWindow_MultiDisplayTest(
+            int initialDisplayId, int eventDisplayId) throws RemoteException {
+        startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
+        final int initialWindowId = getWindowIdFromWindowInfosForDisplay(
+                initialDisplayId, DEFAULT_FOCUSED_INDEX);
+        final int noUse = 0;
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                initialWindowId,
+                AccessibilityNodeInfo.ROOT_NODE_ID,
+                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
+                noUse);
+        assertThat(mA11yWindowManager.getFocusedWindowId(
+                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(initialWindowId));
+        Mockito.reset(mMockA11yEventSender);
+
+        final int eventWindowId = getWindowIdFromWindowInfosForDisplay(
+                eventDisplayId, DEFAULT_FOCUSED_INDEX);
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                eventWindowId,
+                AccessibilityNodeInfo.ROOT_NODE_ID,
+                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
+                noUse);
+        assertThat(mA11yWindowManager.getFocusedWindowId(
+                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(eventWindowId));
+        final ArgumentCaptor<AccessibilityEvent> captor =
+                ArgumentCaptor.forClass(AccessibilityEvent.class);
+        verify(mMockA11yEventSender, times(2))
+                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
+        assertThat(captor.getAllValues().get(0),
+                allOf(displayId(initialDisplayId),
+                        a11yWindowId(initialWindowId),
+                        a11yWindowChanges(
+                                AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
+        assertThat(captor.getAllValues().get(1),
+                allOf(displayId(eventDisplayId),
+                        a11yWindowId(eventWindowId),
+                        a11yWindowChanges(
+                                AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED)));
+    }
+
+    @Test
+    public void updateActiveAndA11yFocusedWindow_clearA11yFocusEvent_shouldClearA11yFocus() {
+        final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
+                DEFAULT_FOCUSED_INDEX);
+        final int currentA11yFocusedWindowId = mA11yWindowManager.getFocusedWindowId(
+                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY);
+        assertThat(currentA11yFocusedWindowId, is(not(eventWindowId)));
+
+        final int noUse = 0;
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                eventWindowId,
+                AccessibilityNodeInfo.ROOT_NODE_ID,
+                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
+                noUse);
+        assertThat(mA11yWindowManager.getFocusedWindowId(
+                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(eventWindowId));
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                eventWindowId,
+                AccessibilityNodeInfo.ROOT_NODE_ID,
+                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED,
+                noUse);
+        assertThat(mA11yWindowManager.getFocusedWindowId(
+                        AccessibilityNodeInfo.FOCUS_ACCESSIBILITY),
+                is(AccessibilityWindowInfo.UNDEFINED_WINDOW_ID));
+    }
+
+    @Test
+    public void onTouchInteractionEnd_shouldRollbackActiveWindow() {
+        final int eventWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
+                DEFAULT_FOCUSED_INDEX + 1);
+        final int currentActiveWindowId = mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID);
+        assertThat(currentActiveWindowId, is(not(eventWindowId)));
+
+        final int noUse = 0;
+        mA11yWindowManager.onTouchInteractionStart();
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                eventWindowId,
+                noUse,
+                AccessibilityEvent.TYPE_VIEW_HOVER_ENTER,
+                noUse);
+        assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(eventWindowId));
+        // AccessibilityEventSender is invoked after active window changed. Reset it.
+        Mockito.reset(mMockA11yEventSender);
+
+        mA11yWindowManager.onTouchInteractionEnd();
+        final ArgumentCaptor<AccessibilityEvent> captor =
+                ArgumentCaptor.forClass(AccessibilityEvent.class);
+        verify(mMockA11yEventSender, times(2))
+                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
+        assertThat(captor.getAllValues().get(0),
+                allOf(displayId(Display.DEFAULT_DISPLAY),
+                        a11yWindowId(eventWindowId),
+                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
+        assertThat(captor.getAllValues().get(1),
+                allOf(displayId(Display.DEFAULT_DISPLAY),
+                        a11yWindowId(currentActiveWindowId),
+                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ACTIVE)));
+    }
+
+    @Test
+    public void onTouchInteractionEnd_noServiceInteractiveWindow_shouldClearA11yFocus()
+            throws RemoteException {
+        final IBinder defaultFocusWinToken =
+                mWindowInfos.get(Display.DEFAULT_DISPLAY).get(DEFAULT_FOCUSED_INDEX).token;
+        final int defaultFocusWindowId = mA11yWindowManager.findWindowIdLocked(
+                USER_SYSTEM_ID, defaultFocusWinToken);
+        when(mMockWindowManagerInternal.getFocusedWindowTokenFromWindowStates())
+                .thenReturn(defaultFocusWinToken);
+        final int newFocusWindowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY,
+                DEFAULT_FOCUSED_INDEX + 1);
+        final IAccessibilityInteractionConnection mockNewFocusConnection =
+                mA11yWindowManager.getConnectionLocked(
+                        USER_SYSTEM_ID, newFocusWindowId).getRemote();
+
+        mA11yWindowManager.stopTrackingWindows(Display.DEFAULT_DISPLAY);
+        final int noUse = 0;
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                defaultFocusWindowId,
+                noUse,
+                AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
+                noUse);
+        assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(defaultFocusWindowId));
+        assertThat(mA11yWindowManager.getFocusedWindowId(AccessibilityNodeInfo.FOCUS_INPUT),
+                is(defaultFocusWindowId));
+
+        mA11yWindowManager.onTouchInteractionStart();
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                newFocusWindowId,
+                noUse,
+                AccessibilityEvent.TYPE_VIEW_HOVER_ENTER,
+                noUse);
+        mA11yWindowManager.updateActiveAndAccessibilityFocusedWindowLocked(USER_SYSTEM_ID,
+                newFocusWindowId,
+                AccessibilityNodeInfo.ROOT_NODE_ID,
+                AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED,
+                noUse);
+        assertThat(mA11yWindowManager.getActiveWindowId(USER_SYSTEM_ID), is(newFocusWindowId));
+        assertThat(mA11yWindowManager.getFocusedWindowId(
+                AccessibilityNodeInfo.FOCUS_ACCESSIBILITY), is(newFocusWindowId));
+
+        mA11yWindowManager.onTouchInteractionEnd();
+        mHandler.sendLastMessage();
+        verify(mockNewFocusConnection).clearAccessibilityFocus();
+    }
+
+    @Test
+    public void getPictureInPictureWindow_shouldNotNull() {
+        assertNull(mA11yWindowManager.getPictureInPictureWindowLocked());
+        mWindowInfos.get(Display.DEFAULT_DISPLAY).get(1).inPictureInPicture = true;
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+        assertNotNull(mA11yWindowManager.getPictureInPictureWindowLocked());
+    }
+
+    @Test
+    public void notifyOutsideTouch() throws RemoteException {
+        final int targetWindowId =
+                getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 1);
+        final int outsideWindowId =
+                getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
+        final IAccessibilityInteractionConnection mockRemoteConnection =
+                mA11yWindowManager.getConnectionLocked(
+                        USER_SYSTEM_ID, outsideWindowId).getRemote();
+        mWindowInfos.get(Display.DEFAULT_DISPLAY).get(0).hasFlagWatchOutsideTouch = true;
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, SEND_ON_WINDOW_CHANGES);
+
+        mA11yWindowManager.notifyOutsideTouch(USER_SYSTEM_ID, targetWindowId);
+        verify(mockRemoteConnection).notifyOutsideTouch();
+    }
+
+    @Test
+    public void addAccessibilityInteractionConnection_profileUser_findInParentUser()
+            throws RemoteException {
+        final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+                false, USER_PROFILE);
+        final int windowId = mA11yWindowManager.findWindowIdLocked(
+                USER_PROFILE_PARENT, token.asBinder());
+        assertTrue(windowId >= 0);
+    }
+
+    @Test
+    public void getDisplayList() throws RemoteException {
+        // Starts tracking window of second display.
+        startTrackingPerDisplay(SECONDARY_DISPLAY_ID);
+
+        final ArrayList<Integer> displayList = mA11yWindowManager.getDisplayListLocked(
+                DISPLAY_TYPE_DEFAULT);
+        assertTrue(displayList.equals(mExpectedDisplayList));
+    }
+
+    @Test
+    public void setAccessibilityWindowIdToSurfaceMetadata()
+            throws RemoteException {
+        final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+                true, USER_SYSTEM_ID);
+        int windowId = -1;
+        for (int i = 0; i < mA11yWindowTokens.size(); i++) {
+            if (mA11yWindowTokens.valueAt(i).equals(token)) {
+                windowId = mA11yWindowTokens.keyAt(i);
+            }
+        }
+        assertNotEquals("Returned token is not found in mA11yWindowTokens", -1, windowId);
+        verify(mMockWindowManagerInternal, times(1)).setAccessibilityIdToSurfaceMetadata(
+                token.asBinder(), windowId);
+
+        mA11yWindowManager.removeAccessibilityInteractionConnection(token);
+        verify(mMockWindowManagerInternal, times(1)).setAccessibilityIdToSurfaceMetadata(
+                token.asBinder(), -1);
+    }
+
+    @Test
+    public void getHostTokenLocked_hierarchiesAreAssociated_shouldReturnHostToken() {
+        mA11yWindowManager.associateLocked(mMockEmbeddedToken, mMockHostToken);
+        final IBinder hostToken = mA11yWindowManager.getHostTokenLocked(mMockEmbeddedToken);
+        assertEquals(hostToken, mMockHostToken);
+    }
+
+    @Test
+    public void getHostTokenLocked_hierarchiesAreNotAssociated_shouldReturnNull() {
+        final IBinder hostToken = mA11yWindowManager.getHostTokenLocked(mMockEmbeddedToken);
+        assertNull(hostToken);
+    }
+
+    @Test
+    public void getHostTokenLocked_embeddedHierarchiesAreDisassociated_shouldReturnNull() {
+        mA11yWindowManager.associateLocked(mMockEmbeddedToken, mMockHostToken);
+        mA11yWindowManager.disassociateLocked(mMockEmbeddedToken);
+        final IBinder hostToken = mA11yWindowManager.getHostTokenLocked(mMockEmbeddedToken);
+        assertNull(hostToken);
+    }
+
+    @Test
+    public void getHostTokenLocked_hostHierarchiesAreDisassociated_shouldReturnNull() {
+        mA11yWindowManager.associateLocked(mMockEmbeddedToken, mMockHostToken);
+        mA11yWindowManager.disassociateLocked(mMockHostToken);
+        final IBinder hostToken = mA11yWindowManager.getHostTokenLocked(mMockHostToken);
+        assertNull(hostToken);
+    }
+
+    @Test
+    public void getWindowIdLocked_windowIsRegistered_shouldReturnWindowId() {
+        final int windowId = mA11yWindowManager.getWindowIdLocked(mMockHostToken);
+        assertEquals(windowId, HOST_WINDOW_ID);
+    }
+
+    @Test
+    public void getWindowIdLocked_windowIsNotRegistered_shouldReturnInvalidWindowId() {
+        final int windowId = mA11yWindowManager.getWindowIdLocked(mMockInvalidToken);
+        assertEquals(windowId, INVALID_ID);
+    }
+
+    @Test
+    public void getTokenLocked_windowIsRegistered_shouldReturnToken() {
+        final IBinder token = mA11yWindowManager.getLeashTokenLocked(HOST_WINDOW_ID);
+        assertEquals(token, mMockHostToken);
+    }
+
+    @Test
+    public void getTokenLocked_windowIsNotRegistered_shouldReturnNull() {
+        final IBinder token = mA11yWindowManager.getLeashTokenLocked(OTHER_WINDOW_ID);
+        assertNull(token);
+    }
+
+    @Test
+    public void setAccessibilityWindowAttributes_windowIsNotRegistered_titleIsChanged() {
+        final int windowId =
+                getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
+        final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
+        layoutParams.accessibilityTitle = "accessibility window title";
+        final AccessibilityWindowAttributes attributes = new AccessibilityWindowAttributes(
+                layoutParams, new LocaleList());
+
+        mA11yWindowManager.setAccessibilityWindowAttributes(Display.DEFAULT_DISPLAY, windowId,
+                USER_SYSTEM_ID, attributes);
+
+        final AccessibilityWindowInfo a11yWindow = mA11yWindowManager.findA11yWindowInfoByIdLocked(
+                windowId);
+        assertEquals(toString(layoutParams.accessibilityTitle), toString(a11yWindow.getTitle()));
+    }
+
+    @Test
+    public void sendAccessibilityEventOnWindowRemoval() {
+        final ArrayList<WindowInfo> infos = mWindowInfos.get(Display.DEFAULT_DISPLAY);
+
+        // Removing index 0 because it's not focused, and avoids unnecessary layer change.
+        final int windowId =
+                getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
+        infos.remove(0);
+        for (WindowInfo info : infos) {
+            // Adjust layer number because it should start from 0.
+            info.layer--;
+        }
+
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
+
+        final ArgumentCaptor<AccessibilityEvent> captor =
+                ArgumentCaptor.forClass(AccessibilityEvent.class);
+        verify(mMockA11yEventSender, times(1))
+                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
+        assertThat(captor.getAllValues().get(0),
+                allOf(displayId(Display.DEFAULT_DISPLAY),
+                        a11yWindowId(windowId),
+                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_REMOVED)));
+    }
+
+    @Test
+    public void sendAccessibilityEventOnWindowAddition() throws RemoteException {
+        final ArrayList<WindowInfo> infos = mWindowInfos.get(Display.DEFAULT_DISPLAY);
+
+        for (WindowInfo info : infos) {
+            // Adjust layer number because new window will have 0 so that layer number in
+            // A11yWindowInfo in window won't be changed.
+            info.layer++;
+        }
+
+        final IWindow token = addAccessibilityInteractionConnection(Display.DEFAULT_DISPLAY,
+                false, USER_SYSTEM_ID);
+        addWindowInfo(infos, token, 0);
+        final int windowId =
+                getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, infos.size() - 1);
+
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
+
+        final ArgumentCaptor<AccessibilityEvent> captor =
+                ArgumentCaptor.forClass(AccessibilityEvent.class);
+        verify(mMockA11yEventSender, times(1))
+                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
+        assertThat(captor.getAllValues().get(0),
+                allOf(displayId(Display.DEFAULT_DISPLAY),
+                        a11yWindowId(windowId),
+                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_ADDED)));
+    }
+
+    @Test
+    public void sendAccessibilityEventOnWindowChange() {
+        final ArrayList<WindowInfo> infos = mWindowInfos.get(Display.DEFAULT_DISPLAY);
+        infos.get(0).title = "new title";
+        final int windowId = getWindowIdFromWindowInfosForDisplay(Display.DEFAULT_DISPLAY, 0);
+
+        onWindowsForAccessibilityChanged(Display.DEFAULT_DISPLAY, FORCE_SEND);
+
+        final ArgumentCaptor<AccessibilityEvent> captor =
+                ArgumentCaptor.forClass(AccessibilityEvent.class);
+        verify(mMockA11yEventSender, times(1))
+                .sendAccessibilityEventForCurrentUserLocked(captor.capture());
+        assertThat(captor.getAllValues().get(0),
+                allOf(displayId(Display.DEFAULT_DISPLAY),
+                        a11yWindowId(windowId),
+                        a11yWindowChanges(AccessibilityEvent.WINDOWS_CHANGE_TITLE)));
+    }
+
+    private void registerLeashedTokenAndWindowId() {
+        mA11yWindowManager.registerIdLocked(mMockHostToken, HOST_WINDOW_ID);
+        mA11yWindowManager.registerIdLocked(mMockEmbeddedToken, EMBEDDED_WINDOW_ID);
+    }
+
+    private void startTrackingPerDisplay(int displayId) throws RemoteException {
+        ArrayList<WindowInfo> windowInfosForDisplay = new ArrayList<>();
+        // Adds RemoteAccessibilityConnection into AccessibilityWindowManager, and copy
+        // mock window token into mA11yWindowTokens. Also, preparing WindowInfo mWindowInfos
+        // for the test.
+        int layer = 0;
+        for (int i = 0; i < NUM_GLOBAL_WINDOWS; i++) {
+            final IWindow token = addAccessibilityInteractionConnection(displayId,
+                    true, USER_SYSTEM_ID);
+            addWindowInfo(windowInfosForDisplay, token, layer++);
+
+        }
+        for (int i = 0; i < NUM_APP_WINDOWS; i++) {
+            final IWindow token = addAccessibilityInteractionConnection(displayId,
+                    false, USER_SYSTEM_ID);
+            addWindowInfo(windowInfosForDisplay, token, layer++);
+        }
+        // Sets up current focused window of display.
+        // Each display has its own current focused window if config_perDisplayFocusEnabled is true.
+        // Otherwise only default display needs to current focused window.
+        if (mSupportPerDisplayFocus || displayId == Display.DEFAULT_DISPLAY) {
+            windowInfosForDisplay.get(DEFAULT_FOCUSED_INDEX).focused = true;
+        }
+        // Turns on windows tracking, and update window info.
+        mA11yWindowManager.startTrackingWindows(displayId, false);
+        // Puts window lists into array.
+        mWindowInfos.put(displayId, windowInfosForDisplay);
+        // Sets the default display is the top focused display and
+        // its current focused window is the top focused window.
+        if (displayId == Display.DEFAULT_DISPLAY) {
+            setTopFocusedWindowAndDisplay(displayId, DEFAULT_FOCUSED_INDEX);
+        }
+        // Invokes callback for sending window lists to A11y framework.
+        onWindowsForAccessibilityChanged(displayId, FORCE_SEND);
+
+        assertEquals(mA11yWindowManager.getWindowListLocked(displayId).size(),
+                windowInfosForDisplay.size());
+    }
+
+    private WindowsForAccessibilityCallback getWindowsForAccessibilityCallbacks(int displayId) {
+        ArgumentCaptor<WindowsForAccessibilityCallback> windowsForAccessibilityCallbacksCaptor =
+                ArgumentCaptor.forClass(
+                        WindowsForAccessibilityCallback.class);
+        verify(mMockWindowManagerInternal)
+                .setWindowsForAccessibilityCallback(eq(displayId),
+                        windowsForAccessibilityCallbacksCaptor.capture());
+        return windowsForAccessibilityCallbacksCaptor.getValue();
+    }
+
+    private IWindow addAccessibilityInteractionConnection(int displayId, boolean bGlobal,
+            int userId) throws RemoteException {
+        final IWindow mockWindowToken = Mockito.mock(IWindow.class);
+        final IAccessibilityInteractionConnection mockA11yConnection = Mockito.mock(
+                IAccessibilityInteractionConnection.class);
+        final IBinder mockConnectionBinder = Mockito.mock(IBinder.class);
+        final IBinder mockWindowBinder = Mockito.mock(IBinder.class);
+        final IBinder mockLeashToken = Mockito.mock(IBinder.class);
+        when(mockA11yConnection.asBinder()).thenReturn(mockConnectionBinder);
+        when(mockWindowToken.asBinder()).thenReturn(mockWindowBinder);
+        when(mMockA11ySecurityPolicy.isCallerInteractingAcrossUsers(userId))
+                .thenReturn(bGlobal);
+        when(mMockWindowManagerInternal.getDisplayIdForWindow(mockWindowBinder))
+                .thenReturn(displayId);
+
+        int windowId = mA11yWindowManager.addAccessibilityInteractionConnection(
+                mockWindowToken, mockLeashToken, mockA11yConnection, PACKAGE_NAME, userId);
+        mA11yWindowTokens.put(windowId, mockWindowToken);
+        return mockWindowToken;
+    }
+
+    private int addAccessibilityInteractionConnection(int displayId, boolean bGlobal,
+            IBinder leashToken, int userId) throws RemoteException {
+        final IWindow mockWindowToken = Mockito.mock(IWindow.class);
+        final IAccessibilityInteractionConnection mockA11yConnection = Mockito.mock(
+                IAccessibilityInteractionConnection.class);
+        final IBinder mockConnectionBinder = Mockito.mock(IBinder.class);
+        final IBinder mockWindowBinder = Mockito.mock(IBinder.class);
+        when(mockA11yConnection.asBinder()).thenReturn(mockConnectionBinder);
+        when(mockWindowToken.asBinder()).thenReturn(mockWindowBinder);
+        when(mMockA11ySecurityPolicy.isCallerInteractingAcrossUsers(userId))
+                .thenReturn(bGlobal);
+        when(mMockWindowManagerInternal.getDisplayIdForWindow(mockWindowBinder))
+                .thenReturn(displayId);
+
+        int windowId = mA11yWindowManager.addAccessibilityInteractionConnection(
+                mockWindowToken, leashToken, mockA11yConnection, PACKAGE_NAME, userId);
+        mA11yWindowTokens.put(windowId, mockWindowToken);
+        return windowId;
+    }
+
+    private void addWindowInfo(ArrayList<WindowInfo> windowInfos, IWindow windowToken, int layer) {
+        final WindowInfo windowInfo = WindowInfo.obtain();
+        windowInfo.type = AccessibilityWindowInfo.TYPE_APPLICATION;
+        windowInfo.token = windowToken.asBinder();
+        windowInfo.layer = layer;
+        windowInfo.regionInScreen.set(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+        windowInfos.add(windowInfo);
+    }
+
+    private int getWindowIdFromWindowInfosForDisplay(int displayId, int index) {
+        final IBinder windowToken = mWindowInfos.get(displayId).get(index).token;
+        return mA11yWindowManager.findWindowIdLocked(
+                USER_SYSTEM_ID, windowToken);
+    }
+
+    private void setTopFocusedWindowAndDisplay(int displayId, int index) {
+        // Sets the top focus window.
+        mTopFocusedWindowToken = mWindowInfos.get(displayId).get(index).token;
+        // Sets the top focused display.
+        mTopFocusedDisplayId = displayId;
+    }
+
+    private void onWindowsForAccessibilityChanged(int displayId, boolean forceSend) {
+        WindowsForAccessibilityCallback callbacks = mCallbackOfWindows.get(displayId);
+        if (callbacks == null) {
+            callbacks = getWindowsForAccessibilityCallbacks(displayId);
+            mCallbackOfWindows.put(displayId, callbacks);
+        }
+        callbacks.onWindowsForAccessibilityChanged(forceSend, mTopFocusedDisplayId,
+                mTopFocusedWindowToken, mWindowInfos.get(displayId));
+    }
+
+    private void changeFocusedWindowOnDisplayPerDisplayFocusConfig(
+            int changeFocusedDisplayId, int newFocusedWindowIndex, int oldTopFocusedDisplayId,
+            int oldFocusedWindowIndex) {
+        if (mSupportPerDisplayFocus) {
+            // Gets the old focused window of display which wants to change focused window.
+            WindowInfo focusedWindowInfo =
+                    mWindowInfos.get(changeFocusedDisplayId).get(oldFocusedWindowIndex);
+            // Resets the focus of old focused window.
+            focusedWindowInfo.focused = false;
+            // Gets the new window of display which wants to change focused window.
+            focusedWindowInfo =
+                    mWindowInfos.get(changeFocusedDisplayId).get(newFocusedWindowIndex);
+            // Sets the focus of new focused window.
+            focusedWindowInfo.focused = true;
+        } else {
+            // Gets the window of display which wants to change focused window.
+            WindowInfo focusedWindowInfo =
+                    mWindowInfos.get(changeFocusedDisplayId).get(newFocusedWindowIndex);
+            // Sets the focus of new focused window.
+            focusedWindowInfo.focused = true;
+            // Gets the old focused window of old top focused display.
+            focusedWindowInfo =
+                    mWindowInfos.get(oldTopFocusedDisplayId).get(oldFocusedWindowIndex);
+            // Resets the focus of old focused window.
+            focusedWindowInfo.focused = false;
+            // Changes the top focused display and window.
+            setTopFocusedWindowAndDisplay(changeFocusedDisplayId, newFocusedWindowIndex);
+        }
+    }
+
+    @Nullable
+    private static String toString(@Nullable CharSequence cs) {
+        return cs == null ? null : cs.toString();
+    }
+
+    static class DisplayIdMatcher extends TypeSafeMatcher<AccessibilityEvent> {
+        private final int mDisplayId;
+
+        DisplayIdMatcher(int displayId) {
+            super();
+            mDisplayId = displayId;
+        }
+
+        static DisplayIdMatcher displayId(int displayId) {
+            return new DisplayIdMatcher(displayId);
+        }
+
+        @Override
+        protected boolean matchesSafely(AccessibilityEvent event) {
+            return event.getDisplayId() == mDisplayId;
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            description.appendText("Matching to displayId " + mDisplayId);
+        }
+    }
+
+    static class WindowIdMatcher extends TypeSafeMatcher<AccessibilityEvent> {
+        private int mWindowId;
+
+        WindowIdMatcher(int windowId) {
+            super();
+            mWindowId = windowId;
+        }
+
+        static WindowIdMatcher a11yWindowId(int windowId) {
+            return new WindowIdMatcher(windowId);
+        }
+
+        @Override
+        protected boolean matchesSafely(AccessibilityEvent event) {
+            return event.getWindowId() == mWindowId;
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            description.appendText("Matching to windowId " + mWindowId);
+        }
+    }
+
+    static class WindowChangesMatcher extends TypeSafeMatcher<AccessibilityEvent> {
+        private int mWindowChanges;
+
+        WindowChangesMatcher(int windowChanges) {
+            super();
+            mWindowChanges = windowChanges;
+        }
+
+        static WindowChangesMatcher a11yWindowChanges(int windowChanges) {
+            return new WindowChangesMatcher(windowChanges);
+        }
+
+        @Override
+        protected boolean matchesSafely(AccessibilityEvent event) {
+            return event.getWindowChanges() == mWindowChanges;
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            description.appendText("Matching to window changes " + mWindowChanges);
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionManagerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionManagerTest.java
index 009bfb7..87fe6cf 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionManagerTest.java
@@ -813,6 +813,18 @@
                 anyBoolean());
     }
 
+    @Test
+    public void onFullscreenMagnificationActivationChanged_hasConnection_notifyActivatedState()
+            throws RemoteException {
+        mMagnificationConnectionManager.setConnection(mMockConnection.getConnection());
+
+        mMagnificationConnectionManager
+                .onFullscreenMagnificationActivationChanged(TEST_DISPLAY, /* activated= */ true);
+
+        verify(mMockConnection.getConnection())
+                .onFullscreenMagnificationActivationChanged(eq(TEST_DISPLAY), eq(true));
+    }
+
     private MotionEvent generatePointersDownEvent(PointF[] pointersLocation) {
         final int len = pointersLocation.length;
 
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionWrapperTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionWrapperTest.java
index 07f3036..2120b2e 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionWrapperTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationConnectionWrapperTest.java
@@ -131,6 +131,14 @@
     }
 
     @Test
+    public void onFullscreenMagnificationActivationChanged() throws RemoteException {
+        mConnectionWrapper
+                .onFullscreenMagnificationActivationChanged(TEST_DISPLAY, /* activated= */ true);
+        verify(mConnection)
+                .onFullscreenMagnificationActivationChanged(eq(TEST_DISPLAY), eq(true));
+    }
+
+    @Test
     public void setMirrorWindowCallback() throws RemoteException {
         mConnectionWrapper.setConnectionCallback(mCallback);
         verify(mConnection).setConnectionCallback(mCallback);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
index a0c4b5e..1a51c45 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
@@ -53,6 +53,10 @@
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.provider.Settings;
 import android.test.mock.MockContentResolver;
 import android.testing.DexmakerShareClassLoaderRule;
@@ -73,6 +77,7 @@
 import com.android.server.accessibility.AccessibilityTraceManager;
 import com.android.server.accessibility.test.MessageCapturingHandler;
 import com.android.server.wm.WindowManagerInternal;
+import com.android.window.flags.Flags;
 
 import org.junit.After;
 import org.junit.Before;
@@ -91,6 +96,9 @@
 @RunWith(AndroidJUnit4.class)
 public class MagnificationControllerTest {
 
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
     private static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY;
     private static final int TEST_SERVICE_ID = 1;
     private static final Region INITIAL_SCREEN_MAGNIFICATION_REGION =
@@ -1263,6 +1271,27 @@
         verify(mService).changeMagnificationMode(TEST_DISPLAY, MODE_WINDOW);
     }
 
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_MAGNIFICATION_ALWAYS_DRAW_FULLSCREEN_BORDER)
+    public void onFullscreenMagnificationActivationState_systemUiBorderFlagOn_notifyConnection() {
+        mMagnificationController.onFullScreenMagnificationActivationState(
+                TEST_DISPLAY, /* activated= */ true);
+
+        verify(mMagnificationConnectionManager)
+                .onFullscreenMagnificationActivationChanged(TEST_DISPLAY, /* activated= */ true);
+    }
+
+    @Test
+    @RequiresFlagsDisabled(Flags.FLAG_MAGNIFICATION_ALWAYS_DRAW_FULLSCREEN_BORDER)
+    public void
+            onFullscreenMagnificationActivationState_systemUiBorderFlagOff_neverNotifyConnection() {
+        mMagnificationController.onFullScreenMagnificationActivationState(
+                TEST_DISPLAY, /* activated= */ true);
+
+        verify(mMagnificationConnectionManager, never())
+                .onFullscreenMagnificationActivationChanged(TEST_DISPLAY, /* activated= */ true);
+    }
+
     private void setMagnificationEnabled(int mode) throws RemoteException {
         setMagnificationEnabled(mode, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y);
     }
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
index a6e05dd..5520897 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
@@ -364,6 +364,30 @@
     }
 
     @Test
+    public void systemAudioControlOnPowerOn_singleActionStarted() throws Exception {
+        mHdmiCecLocalDeviceAudioSystem.removeAction(SystemAudioInitiationActionFromAvr.class);
+        mHdmiCecLocalDeviceAudioSystem.systemAudioControlOnPowerOn(
+                Constants.ALWAYS_SYSTEM_AUDIO_CONTROL_ON_POWER_ON, true);
+        mHdmiCecLocalDeviceAudioSystem.systemAudioControlOnPowerOn(
+                Constants.ALWAYS_SYSTEM_AUDIO_CONTROL_ON_POWER_ON, true);
+        assertThat(
+                mHdmiCecLocalDeviceAudioSystem.getActions(
+                        SystemAudioInitiationActionFromAvr.class))
+                .hasSize(1);
+    }
+
+    @Test
+    public void onSystemAudioControlFeatureSupportChanged_singleActionStarted() throws Exception {
+        mHdmiCecLocalDeviceAudioSystem.removeAction(SystemAudioInitiationActionFromAvr.class);
+        mHdmiCecLocalDeviceAudioSystem.onSystemAudioControlFeatureSupportChanged(true);
+        mHdmiCecLocalDeviceAudioSystem.onSystemAudioControlFeatureSupportChanged(true);
+        assertThat(
+                mHdmiCecLocalDeviceAudioSystem.getActions(
+                        SystemAudioInitiationActionFromAvr.class))
+                .hasSize(1);
+    }
+
+    @Test
     public void handleActiveSource_updateActiveSource() throws Exception {
         HdmiCecMessage message = HdmiCecMessageBuilder.buildActiveSource(ADDR_TV, 0x0000);
         ActiveSource expectedActiveSource = new ActiveSource(ADDR_TV, 0x0000);
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 5c6f3c9..15cd511 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -149,6 +149,7 @@
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkPolicy;
+import android.net.NetworkPolicyManager;
 import android.net.NetworkStateSnapshot;
 import android.net.NetworkTemplate;
 import android.net.TelephonyNetworkSpecifier;
@@ -1619,6 +1620,12 @@
         verify(mActivityManagerInternal).notifyNetworkPolicyRulesUpdated(UID_A, procStateSeq);
     }
 
+    private void callAndWaitOnUidGone(int uid) throws Exception {
+        // The disabled argument is used only for ephemeral apps and does not matter here.
+        mUidObserver.onUidGone(uid, false /* disabled */);
+        waitForUidEventHandlerIdle();
+    }
+
     private void callAndWaitOnUidStateChanged(int uid, int procState, long procStateSeq)
             throws Exception {
         callAndWaitOnUidStateChanged(uid, procState, procStateSeq,
@@ -2245,6 +2252,15 @@
         assertTrue(mService.isUidNetworkingBlocked(UID_A, false));
     }
 
+    private boolean isUidState(int uid, int procState, int procStateSeq, int capability) {
+        final NetworkPolicyManager.UidState uidState = mService.getUidStateForTest(uid);
+        if (uidState == null) {
+            return false;
+        }
+        return uidState.uid == uid && uidState.procStateSeq == procStateSeq
+                && uidState.procState == procState && uidState.capability == capability;
+    }
+
     @Test
     @RequiresFlagsEnabled(Flags.FLAG_NETWORK_BLOCKED_FOR_TOP_SLEEPING_AND_ABOVE)
     public void testUidObserverFiltersProcStateChanges() throws Exception {
@@ -2363,6 +2379,31 @@
     }
 
     @Test
+    public void testUidStateChangeAfterUidGone() throws Exception {
+        final int testProcStateSeq = 51;
+        final int testProcState = PROCESS_STATE_IMPORTANT_FOREGROUND;
+
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // First callback for uid.
+            callOnUidStatechanged(UID_B, testProcState, testProcStateSeq, PROCESS_CAPABILITY_NONE);
+            assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+        assertTrue(isUidState(UID_B, testProcState, testProcStateSeq, PROCESS_CAPABILITY_NONE));
+
+        callAndWaitOnUidGone(UID_B);
+        try (SyncBarrier b = new SyncBarrier(mService.mUidEventHandler)) {
+            // Even though the procState is the same, the uid had exited - so this should be
+            // processed as a fresh callback.
+            callOnUidStatechanged(UID_B, testProcState, testProcStateSeq + 1,
+                    PROCESS_CAPABILITY_NONE);
+            assertTrue(mService.mUidEventHandler.hasMessages(UID_MSG_STATE_CHANGED));
+        }
+        waitForUidEventHandlerIdle();
+        assertTrue(isUidState(UID_B, testProcState, testProcStateSeq + 1, PROCESS_CAPABILITY_NONE));
+    }
+
+    @Test
     public void testLowPowerStandbyAllowlist() throws Exception {
         // Chain background is also enabled but these procstates are important enough to be exempt.
         callAndWaitOnUidStateChanged(UID_A, PROCESS_STATE_TOP, 0);
diff --git a/services/tests/servicestests/src/com/android/server/search/SearchablesTest.java b/services/tests/servicestests/src/com/android/server/search/SearchablesTest.java
index f5c6795..771a765 100644
--- a/services/tests/servicestests/src/com/android/server/search/SearchablesTest.java
+++ b/services/tests/servicestests/src/com/android/server/search/SearchablesTest.java
@@ -92,7 +92,7 @@
     public void testNonSearchable() {
         // test basic array & hashmap
         Searchables searchables = new Searchables(mContext, 0);
-        searchables.updateSearchableList();
+        searchables.updateSearchableListIfNeeded();
 
         // confirm that we return null for non-searchy activities
         ComponentName nonActivity = new ComponentName("com.android.frameworks.servicestests",
@@ -121,7 +121,7 @@
         doReturn(true).when(mPackageManagerInternal).canAccessComponent(anyInt(), any(), anyInt());
 
         Searchables searchables = new Searchables(mContext, 0);
-        searchables.updateSearchableList();
+        searchables.updateSearchableListIfNeeded();
         // tests with "real" searchables (deprecate, this should be a unit test)
         ArrayList<SearchableInfo> searchablesList = searchables.getSearchablesList();
         int count = searchablesList.size();
@@ -139,7 +139,7 @@
         doReturn(false).when(mPackageManagerInternal).canAccessComponent(anyInt(), any(), anyInt());
 
         Searchables searchables = new Searchables(mContext, 0);
-        searchables.updateSearchableList();
+        searchables.updateSearchableListIfNeeded();
         ArrayList<SearchableInfo> searchablesList = searchables.getSearchablesList();
         assertNotNull(searchablesList);
         MoreAsserts.assertEmpty(searchablesList);
diff --git a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
index 65662d6..2039f93 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
@@ -83,6 +83,13 @@
         }
     }
 
+    @Override
+    public void installExistingPackageForAllUsers(Context context, String packageName) {
+        for (int userId : mUsers) {
+            installPackageForUser(packageName, userId);
+        }
+    }
+
     private void enablePackageForUser(String packageName, boolean enable, int userId) {
         Map<Integer, PackageInfo> userPackages = mPackages.get(packageName);
         if (userPackages == null) {
@@ -93,6 +100,17 @@
         setPackageInfoForUser(userId, packageInfo);
     }
 
+    private void installPackageForUser(String packageName, int userId) {
+        Map<Integer, PackageInfo> userPackages = mPackages.get(packageName);
+        if (userPackages == null) {
+            return;
+        }
+        PackageInfo packageInfo = userPackages.get(userId);
+        packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED;
+        packageInfo.applicationInfo.privateFlags &= (~ApplicationInfo.PRIVATE_FLAG_HIDDEN);
+        setPackageInfoForUser(userId, packageInfo);
+    }
+
     @Override
     public boolean systemIsDebuggable() { return mIsDebuggable; }
 
diff --git a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
index 5a06327..53c172a 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
@@ -1549,6 +1549,31 @@
                         Matchers.anyObject(), Mockito.eq(testPackage), Mockito.eq(true));
     }
 
+    @Test
+    @RequiresFlagsEnabled("android.webkit.update_service_v2")
+    public void testDefaultWebViewPackageInstalling() {
+        String testPackage = "testDefault";
+        WebViewProviderInfo[] packages =
+                new WebViewProviderInfo[] {
+                    new WebViewProviderInfo(
+                            testPackage,
+                            "",
+                            true /* default available */,
+                            false /* fallback */,
+                            null)
+                };
+        setupWithPackages(packages);
+        mTestSystemImpl.setPackageInfo(
+                createPackageInfo(
+                        testPackage, true /* enabled */, true /* valid */, false /* installed */));
+
+        // Check that the boot time logic tries to install the default package.
+        runWebViewBootPreparationOnMainSync();
+        Mockito.verify(mTestSystemImpl)
+                .installExistingPackageForAllUsers(
+                        Matchers.anyObject(), Mockito.eq(testPackage));
+    }
+
     private void testDefaultPackageChosen(PackageInfo packageInfo) {
         WebViewProviderInfo[] packages =
                 new WebViewProviderInfo[] {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index cff7f46..715c9d4 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -12008,7 +12008,7 @@
 
         // style + self managed call - bypasses block
         when(mTelecomManager.isInSelfManagedCall(
-                r.getSbn().getPackageName(), r.getUser(), true)).thenReturn(true);
+                r.getSbn().getPackageName(), true)).thenReturn(true);
         assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
                 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue();
 
@@ -12091,7 +12091,7 @@
         // style + self managed call - bypasses block
         mService.clearNotifications();
         reset(mUsageStats);
-        when(mTelecomManager.isInSelfManagedCall(r.getSbn().getPackageName(), r.getUser(), true))
+        when(mTelecomManager.isInSelfManagedCall(r.getSbn().getPackageName(), true))
                 .thenReturn(true);
 
         mService.addEnqueuedNotification(r);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 8c50ef4..8c2fd10 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -4420,13 +4420,13 @@
     @EnableFlags(Flags.FLAG_MODES_API)
     public void updateAutomaticZenRule_nullDeviceEffectsUpdate() {
         // Adds a starting rule with empty zen policies and device effects
+        ZenDeviceEffects zde = new ZenDeviceEffects.Builder().setShouldUseNightMode(true).build();
         AutomaticZenRule azrBase = new AutomaticZenRule.Builder(NAME, CONDITION_ID)
-                .setDeviceEffects(new ZenDeviceEffects.Builder().build())
+                .setDeviceEffects(zde)
                 .build();
         // Adds the rule using the app, to avoid having any user modified bits set.
         String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(),
                 azrBase, UPDATE_ORIGIN_APP, "reason", Process.SYSTEM_UID);
-        AutomaticZenRule rule = mZenModeHelper.getAutomaticZenRule(ruleId);
 
         AutomaticZenRule azr = new AutomaticZenRule.Builder(azrBase)
                 // Sets Device Effects to null
@@ -4437,10 +4437,10 @@
         // user modified, it can be updated.
         mZenModeHelper.updateAutomaticZenRule(ruleId, azr, UPDATE_ORIGIN_APP, "reason",
                 Process.SYSTEM_UID);
-        rule = mZenModeHelper.getAutomaticZenRule(ruleId);
+        AutomaticZenRule rule = mZenModeHelper.getAutomaticZenRule(ruleId);
 
-        // When AZR's ZenDeviceEffects is null, the updated rule's device effects will be null.
-        assertThat(rule.getDeviceEffects()).isNull();
+        // When AZR's ZenDeviceEffects is null, the updated rule's device effects are kept.
+        assertThat(rule.getDeviceEffects()).isEqualTo(zde);
     }
 
     @Test
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibrationScalerTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibrationScalerTest.java
index b431888..3e59878 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibrationScalerTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibrationScalerTest.java
@@ -35,8 +35,8 @@
 import android.content.ContentResolver;
 import android.content.ContextWrapper;
 import android.content.pm.PackageManagerInternal;
+import android.os.ExternalVibrationScale;
 import android.os.Handler;
-import android.os.IExternalVibratorService;
 import android.os.PowerManagerInternal;
 import android.os.UserHandle;
 import android.os.VibrationAttributes;
@@ -49,6 +49,7 @@
 import android.os.vibrator.StepSegment;
 import android.os.vibrator.VibrationConfig;
 import android.os.vibrator.VibrationEffectSegment;
+import android.platform.test.annotations.RequiresFlagsDisabled;
 import android.platform.test.annotations.RequiresFlagsEnabled;
 import android.platform.test.flag.junit.CheckFlagsRule;
 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
@@ -119,29 +120,65 @@
     public void testGetExternalVibrationScale() {
         setDefaultIntensity(USAGE_TOUCH, Vibrator.VIBRATION_INTENSITY_LOW);
         setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_HIGH);
-        assertEquals(IExternalVibratorService.SCALE_VERY_HIGH,
-                mVibrationScaler.getExternalVibrationScale(USAGE_TOUCH));
+        assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_VERY_HIGH,
+                mVibrationScaler.getExternalVibrationScaleLevel(USAGE_TOUCH));
 
         setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_MEDIUM);
-        assertEquals(IExternalVibratorService.SCALE_HIGH,
-                mVibrationScaler.getExternalVibrationScale(USAGE_TOUCH));
+        assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_HIGH,
+                mVibrationScaler.getExternalVibrationScaleLevel(USAGE_TOUCH));
 
         setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_LOW);
-        assertEquals(IExternalVibratorService.SCALE_NONE,
-                mVibrationScaler.getExternalVibrationScale(USAGE_TOUCH));
+        assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_NONE,
+                mVibrationScaler.getExternalVibrationScaleLevel(USAGE_TOUCH));
 
         setDefaultIntensity(USAGE_TOUCH, VIBRATION_INTENSITY_MEDIUM);
-        assertEquals(IExternalVibratorService.SCALE_LOW,
-                mVibrationScaler.getExternalVibrationScale(USAGE_TOUCH));
+        assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_LOW,
+                mVibrationScaler.getExternalVibrationScaleLevel(USAGE_TOUCH));
 
         setDefaultIntensity(USAGE_TOUCH, VIBRATION_INTENSITY_HIGH);
-        assertEquals(IExternalVibratorService.SCALE_VERY_LOW,
-                mVibrationScaler.getExternalVibrationScale(USAGE_TOUCH));
+        assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_VERY_LOW,
+                mVibrationScaler.getExternalVibrationScaleLevel(USAGE_TOUCH));
 
         setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF);
         // Vibration setting being bypassed will use default setting and not scale.
-        assertEquals(IExternalVibratorService.SCALE_NONE,
-                mVibrationScaler.getExternalVibrationScale(USAGE_TOUCH));
+        assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_NONE,
+                mVibrationScaler.getExternalVibrationScaleLevel(USAGE_TOUCH));
+    }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_ADAPTIVE_HAPTICS_ENABLED)
+    public void testAdaptiveHapticsScale_withAdaptiveHapticsAvailable() {
+        setDefaultIntensity(USAGE_TOUCH, Vibrator.VIBRATION_INTENSITY_LOW);
+        setDefaultIntensity(USAGE_RINGTONE, Vibrator.VIBRATION_INTENSITY_LOW);
+        setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_HIGH);
+        setUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_HIGH);
+
+        mVibrationScaler.updateAdaptiveHapticsScale(USAGE_TOUCH, 0.5f);
+        mVibrationScaler.updateAdaptiveHapticsScale(USAGE_RINGTONE, 0.2f);
+
+        assertEquals(0.5f, mVibrationScaler.getAdaptiveHapticsScale(USAGE_TOUCH));
+        assertEquals(0.2f, mVibrationScaler.getAdaptiveHapticsScale(USAGE_RINGTONE));
+        assertEquals(1f, mVibrationScaler.getAdaptiveHapticsScale(USAGE_NOTIFICATION));
+
+        setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_OFF);
+        // Vibration setting being bypassed will apply adaptive haptics scales.
+        assertEquals(0.2f, mVibrationScaler.getAdaptiveHapticsScale(USAGE_RINGTONE));
+    }
+
+    @Test
+    @RequiresFlagsDisabled(Flags.FLAG_ADAPTIVE_HAPTICS_ENABLED)
+    public void testAdaptiveHapticsScale_flagDisabled_adaptiveHapticScaleAlwaysNone() {
+        setDefaultIntensity(USAGE_TOUCH, Vibrator.VIBRATION_INTENSITY_LOW);
+        setDefaultIntensity(USAGE_RINGTONE, Vibrator.VIBRATION_INTENSITY_LOW);
+        setUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, VIBRATION_INTENSITY_HIGH);
+        setUserSetting(Settings.System.RING_VIBRATION_INTENSITY, VIBRATION_INTENSITY_HIGH);
+
+        mVibrationScaler.updateAdaptiveHapticsScale(USAGE_TOUCH, 0.5f);
+        mVibrationScaler.updateAdaptiveHapticsScale(USAGE_RINGTONE, 0.2f);
+
+        assertEquals(1f, mVibrationScaler.getAdaptiveHapticsScale(USAGE_TOUCH));
+        assertEquals(1f, mVibrationScaler.getAdaptiveHapticsScale(USAGE_RINGTONE));
+        assertEquals(1f, mVibrationScaler.getAdaptiveHapticsScale(USAGE_NOTIFICATION));
     }
 
     @Test
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java
index 2823223..0d5bf95 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControlServiceTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -35,7 +35,6 @@
 import android.content.ComponentName;
 import android.content.pm.PackageManagerInternal;
 import android.frameworks.vibrator.ScaleParam;
-import android.frameworks.vibrator.VibrationParam;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
@@ -55,8 +54,6 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
-import java.util.ArrayList;
-import java.util.List;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
 
@@ -70,6 +67,7 @@
     @Mock
     private PackageManagerInternal mPackageManagerInternalMock;
 
+    private TestLooper mTestLooper;
     private FakeVibratorController mFakeVibratorController;
     private VibratorControlService mVibratorControlService;
     private VibrationSettings mVibrationSettings;
@@ -77,6 +75,7 @@
 
     @Before
     public void setUp() throws Exception {
+        mTestLooper = new TestLooper();
         when(mPackageManagerInternalMock.getSystemUiServiceComponent())
                 .thenReturn(new ComponentName("", ""));
         LocalServices.removeServiceForTest(PackageManagerInternal.class);
@@ -86,7 +85,7 @@
         mVibrationSettings = new VibrationSettings(
                 ApplicationProvider.getApplicationContext(), new Handler(testLooper.getLooper()));
 
-        mFakeVibratorController = new FakeVibratorController();
+        mFakeVibratorController = new FakeVibratorController(mTestLooper.getLooper());
         mVibratorControlService = new VibratorControlService(new VibratorControllerHolder(),
                 mMockVibrationScaler, mVibrationSettings, mLock);
     }
@@ -111,13 +110,13 @@
     @Test
     public void testUnregisterVibratorController_providingAnInvalidController_ignoresRequest()
             throws RemoteException {
-        FakeVibratorController fakeController1 = new FakeVibratorController();
-        FakeVibratorController fakeController2 = new FakeVibratorController();
-        mVibratorControlService.registerVibratorController(fakeController1);
-        mVibratorControlService.unregisterVibratorController(fakeController2);
+        FakeVibratorController controller1 = new FakeVibratorController(mTestLooper.getLooper());
+        FakeVibratorController controller2 = new FakeVibratorController(mTestLooper.getLooper());
+        mVibratorControlService.registerVibratorController(controller1);
+        mVibratorControlService.unregisterVibratorController(controller2);
 
         verifyZeroInteractions(mMockVibrationScaler);
-        assertThat(fakeController1.isLinkedToDeath).isTrue();
+        assertThat(controller1.isLinkedToDeath).isTrue();
     }
 
     @Test
@@ -135,7 +134,7 @@
         vibrationScales.put(ScaleParam.TYPE_NOTIFICATION, 0.4f);
 
         mVibratorControlService.onRequestVibrationParamsComplete(token,
-                generateVibrationParams(vibrationScales));
+                VibrationParamGenerator.generateVibrationParams(vibrationScales));
 
         verify(mMockVibrationScaler).updateAdaptiveHapticsScale(USAGE_ALARM, 0.7f);
         verify(mMockVibrationScaler).updateAdaptiveHapticsScale(USAGE_NOTIFICATION, 0.4f);
@@ -162,7 +161,7 @@
         vibrationScales.put(ScaleParam.TYPE_NOTIFICATION, 0.4f);
 
         mVibratorControlService.onRequestVibrationParamsComplete(new Binder(),
-                generateVibrationParams(vibrationScales));
+                VibrationParamGenerator.generateVibrationParams(vibrationScales));
 
         verifyZeroInteractions(mMockVibrationScaler);
     }
@@ -175,7 +174,8 @@
         vibrationScales.put(ScaleParam.TYPE_ALARM, 0.7f);
         vibrationScales.put(ScaleParam.TYPE_NOTIFICATION, 0.4f);
 
-        mVibratorControlService.setVibrationParams(generateVibrationParams(vibrationScales),
+        mVibratorControlService.setVibrationParams(
+                VibrationParamGenerator.generateVibrationParams(vibrationScales),
                 mFakeVibratorController);
 
         verify(mMockVibrationScaler).updateAdaptiveHapticsScale(USAGE_ALARM, 0.7f);
@@ -193,7 +193,8 @@
         vibrationScales.put(ScaleParam.TYPE_ALARM, 0.7f);
         vibrationScales.put(ScaleParam.TYPE_NOTIFICATION, 0.4f);
 
-        mVibratorControlService.setVibrationParams(generateVibrationParams(vibrationScales),
+        mVibratorControlService.setVibrationParams(
+                VibrationParamGenerator.generateVibrationParams(vibrationScales),
                 mFakeVibratorController);
 
         verifyZeroInteractions(mMockVibrationScaler);
@@ -268,28 +269,6 @@
         }
     }
 
-    private VibrationParam[] generateVibrationParams(SparseArray<Float> vibrationScales) {
-        List<VibrationParam> vibrationParamList = new ArrayList<>();
-        for (int i = 0; i < vibrationScales.size(); i++) {
-            int type = vibrationScales.keyAt(i);
-            float scale = vibrationScales.valueAt(i);
-
-            vibrationParamList.add(generateVibrationParam(type, scale));
-        }
-
-        return vibrationParamList.toArray(new VibrationParam[0]);
-    }
-
-    private VibrationParam generateVibrationParam(int type, float scale) {
-        ScaleParam scaleParam = new ScaleParam();
-        scaleParam.typesMask = type;
-        scaleParam.scale = scale;
-        VibrationParam vibrationParam = new VibrationParam();
-        vibrationParam.setScale(scaleParam);
-
-        return vibrationParam;
-    }
-
     private int buildVibrationTypesMask(int... types) {
         int typesMask = 0;
         for (int type : types) {
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerHolderTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerHolderTest.java
index 79abe21..db823d6 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerHolderTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorControllerHolderTest.java
@@ -18,23 +18,26 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import android.os.RemoteException;
+import android.os.test.TestLooper;
 
 import org.junit.Before;
 import org.junit.Test;
 
 public class VibratorControllerHolderTest {
 
-    private final FakeVibratorController mFakeVibratorController = new FakeVibratorController();
+    private TestLooper mTestLooper;
+    private FakeVibratorController mFakeVibratorController;
     private VibratorControllerHolder mVibratorControllerHolder;
 
     @Before
     public void setUp() throws Exception {
+        mTestLooper = new TestLooper();
+        mFakeVibratorController = new FakeVibratorController(mTestLooper.getLooper());
         mVibratorControllerHolder = new VibratorControllerHolder();
     }
 
     @Test
-    public void testSetVibratorController_linksVibratorControllerToDeath() throws RemoteException {
+    public void testSetVibratorController_linksVibratorControllerToDeath() {
         mVibratorControllerHolder.setVibratorController(mFakeVibratorController);
         assertThat(mVibratorControllerHolder.getVibratorController())
                 .isEqualTo(mFakeVibratorController);
@@ -42,8 +45,7 @@
     }
 
     @Test
-    public void testSetVibratorController_setControllerToNull_unlinksVibratorControllerToDeath()
-            throws RemoteException {
+    public void testSetVibratorController_setControllerToNull_unlinksVibratorControllerToDeath() {
         mVibratorControllerHolder.setVibratorController(mFakeVibratorController);
         mVibratorControllerHolder.setVibratorController(null);
         assertThat(mFakeVibratorController.isLinkedToDeath).isFalse();
@@ -51,8 +53,7 @@
     }
 
     @Test
-    public void testBinderDied_withValidController_unlinksVibratorControllerToDeath()
-            throws RemoteException {
+    public void testBinderDied_withValidController_unlinksVibratorControllerToDeath() {
         mVibratorControllerHolder.setVibratorController(mFakeVibratorController);
         mVibratorControllerHolder.binderDied(mFakeVibratorController);
         assertThat(mFakeVibratorController.isLinkedToDeath).isFalse();
@@ -60,10 +61,10 @@
     }
 
     @Test
-    public void testBinderDied_withInvalidController_ignoresRequest()
-            throws RemoteException {
+    public void testBinderDied_withInvalidController_ignoresRequest() {
         mVibratorControllerHolder.setVibratorController(mFakeVibratorController);
-        FakeVibratorController imposterVibratorController = new FakeVibratorController();
+        FakeVibratorController imposterVibratorController =
+                new FakeVibratorController(mTestLooper.getLooper());
         mVibratorControllerHolder.binderDied(imposterVibratorController);
         assertThat(mFakeVibratorController.isLinkedToDeath).isTrue();
         assertThat(mVibratorControllerHolder.getVibratorController())
diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
index e7571ef..d2ad61f 100644
--- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
+++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java
@@ -50,6 +50,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.res.Resources;
+import android.frameworks.vibrator.ScaleParam;
 import android.hardware.input.IInputManager;
 import android.hardware.input.InputManager;
 import android.hardware.input.InputManagerGlobal;
@@ -59,16 +60,17 @@
 import android.media.AudioManager;
 import android.os.CombinedVibration;
 import android.os.ExternalVibration;
+import android.os.ExternalVibrationScale;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.IExternalVibrationController;
-import android.os.IExternalVibratorService;
 import android.os.IVibratorStateListener;
 import android.os.Looper;
 import android.os.PowerManager;
 import android.os.PowerManagerInternal;
 import android.os.PowerSaveState;
 import android.os.Process;
+import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.VibrationAttributes;
@@ -82,6 +84,10 @@
 import android.os.vibrator.StepSegment;
 import android.os.vibrator.VibrationConfig;
 import android.os.vibrator.VibrationEffectSegment;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.Settings;
 import android.util.SparseArray;
@@ -91,7 +97,6 @@
 import android.view.flags.Flags;
 
 import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.FlakyTest;
 
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.util.FrameworkStatsLog;
@@ -111,6 +116,7 @@
 import org.mockito.junit.MockitoRule;
 
 import java.time.Duration;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
@@ -122,9 +128,7 @@
 public class VibratorManagerServiceTest {
 
     private static final int TEST_TIMEOUT_MILLIS = 1_000;
-    // Time to allow for a cancellation to complete (notably including system ramp down), but not so
-    // long that tests easily get really slow or flaky. If a vibration is close to this, it should
-    // be cancelled in the body of the individual test.
+    // Time to allow for a cancellation to complete and the vibrators to become idle.
     private static final int CLEANUP_TIMEOUT_MILLIS = 100;
     private static final int UID = Process.ROOT_UID;
     private static final int VIRTUAL_DEVICE_ID = 1;
@@ -153,6 +157,8 @@
     public MockitoRule rule = MockitoJUnit.rule();
     @Rule
     public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
 
     @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
 
@@ -178,15 +184,17 @@
     private AudioManager mAudioManagerMock;
 
     private final Map<Integer, FakeVibratorControllerProvider> mVibratorProviders = new HashMap<>();
-
-    private SparseArray<VibrationEffect>  mHapticFeedbackVibrationMap = new SparseArray<>();
+    private final SparseArray<VibrationEffect>  mHapticFeedbackVibrationMap = new SparseArray<>();
+    private final List<HalVibration> mPendingVibrations = new ArrayList<>();
 
     private VibratorManagerService mService;
     private Context mContextSpy;
     private TestLooper mTestLooper;
     private FakeVibrator mVibrator;
+    private FakeVibratorController mFakeVibratorController;
     private PowerManagerInternal.LowPowerModeListener mRegisteredPowerModeListener;
     private VibratorManagerService.ExternalVibratorService mExternalVibratorService;
+    private VibratorControlService mVibratorControlService;
     private VibrationConfig mVibrationConfig;
     private InputManagerGlobal.TestSession mInputManagerGlobalSession;
     private InputManager mInputManager;
@@ -197,6 +205,7 @@
         mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
         mInputManagerGlobalSession = InputManagerGlobal.createTestSession(mIInputManagerMock);
         mVibrationConfig = new VibrationConfig(mContextSpy.getResources());
+        mFakeVibratorController = new FakeVibratorController(mTestLooper.getLooper());
 
         ContentResolver contentResolver = mSettingsProviderRule.mockContentResolver(mContextSpy);
         when(mContextSpy.getContentResolver()).thenReturn(contentResolver);
@@ -242,12 +251,15 @@
     @After
     public void tearDown() throws Exception {
         if (mService != null) {
-            // Wait until all vibrators have stopped vibrating, with a bit of flexibility for tests
-            // that just do a click or have cancelled at the end (waiting for ramp-down).
-            //
-            // Note: if a test is flaky here, check whether a VibrationEffect duration is close to
-            // CLEANUP_TIMEOUT_MILLIS - in which case it's probably best to just cancel that effect
-            // explicitly at the end of the test case (rather than letting it run and race flakily).
+            if (!mPendingVibrations.stream().allMatch(HalVibration::hasEnded)) {
+                // Cancel any pending vibration from tests.
+                cancelVibrate(mService);
+                for (HalVibration vibration : mPendingVibrations) {
+                    vibration.waitForEnd();
+                }
+            }
+            // Wait until all vibrators have stopped vibrating, waiting for ramp-down.
+            // Note: if a test is flaky here something is wrong with the vibration finalization.
             assertTrue(waitUntil(s -> {
                 for (int vibratorId : mService.getVibratorIds()) {
                     if (s.isVibrating(vibratorId)) {
@@ -255,7 +267,7 @@
                     }
                 }
                 return true;
-            }, mService, CLEANUP_TIMEOUT_MILLIS));
+            }, mService, mVibrationConfig.getRampDownDurationMs() + CLEANUP_TIMEOUT_MILLIS));
         }
 
         LocalServices.removeServiceForTest(PackageManagerInternal.class);
@@ -310,20 +322,31 @@
                         if (service instanceof VibratorManagerService.ExternalVibratorService) {
                             mExternalVibratorService =
                                     (VibratorManagerService.ExternalVibratorService) service;
+                        } else if (service instanceof VibratorControlService) {
+                            mVibratorControlService = (VibratorControlService) service;
+                            mFakeVibratorController.setVibratorControlService(
+                                    mVibratorControlService);
                         }
                     }
 
+                    @Override
                     HapticFeedbackVibrationProvider createHapticFeedbackVibrationProvider(
                             Resources resources, VibratorInfo vibratorInfo) {
                         return new HapticFeedbackVibrationProvider(
                                 resources, vibratorInfo, mHapticFeedbackVibrationMap);
                     }
 
+                    @Override
                     VibratorControllerHolder createVibratorControllerHolder() {
                         VibratorControllerHolder holder = new VibratorControllerHolder();
-                        holder.setVibratorController(new FakeVibratorController());
+                        holder.setVibratorController(mFakeVibratorController);
                         return holder;
                     }
+
+                    @Override
+                    boolean isServiceDeclared(String name) {
+                        return true;
+                    }
                 });
         return mService;
     }
@@ -469,8 +492,9 @@
         InOrder inOrderVerifier = inOrder(listenerMock);
         // First notification done when listener is registered.
         inOrderVerifier.verify(listenerMock).onVibrating(eq(false));
+        // Vibrator on notification done before vibration ended, no need to wait.
         inOrderVerifier.verify(listenerMock).onVibrating(eq(true));
-        // The last notification is after the vibration has completed.
+        // Vibrator off notification done after vibration completed, wait for notification.
         inOrderVerifier.verify(listenerMock, timeout(TEST_TIMEOUT_MILLIS)).onVibrating(eq(false));
         inOrderVerifier.verifyNoMoreInteractions();
 
@@ -500,6 +524,7 @@
         InOrder inOrderVerifier = inOrder(listenerMock);
         // First notification done when listener is registered.
         inOrderVerifier.verify(listenerMock).onVibrating(eq(false));
+        // Vibrator on notification done before vibration ended, no need to wait.
         inOrderVerifier.verify(listenerMock).onVibrating(eq(true));
         inOrderVerifier.verify(listenerMock, atLeastOnce()).asBinder(); // unregister
         inOrderVerifier.verifyNoMoreInteractions();
@@ -524,7 +549,6 @@
         verify(listeners[0]).onVibrating(eq(true));
         verify(listeners[1]).onVibrating(eq(true));
         verify(listeners[2], never()).onVibrating(eq(true));
-        cancelVibrate(service); // Clean up long-ish effect.
     }
 
     @Test
@@ -872,21 +896,24 @@
                         eq(AudioAttributes.USAGE_UNKNOWN), anyInt(), anyString());
     }
 
-    @FlakyTest
     @Test
     public void vibrate_withOngoingRepeatingVibration_ignoresEffect() throws Exception {
         mockVibrators(1);
-        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1);
+        fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
         VibratorManagerService service = createSystemReadyService();
 
         VibrationEffect repeatingEffect = VibrationEffect.createWaveform(
-                new long[]{10_000, 10_000}, new int[]{128, 255}, 1);
-        vibrate(service, repeatingEffect, new VibrationAttributes.Builder().setUsage(
-                VibrationAttributes.USAGE_UNKNOWN).build());
+                new long[]{10, 10_000}, new int[]{128, 255}, 1);
+        vibrate(service, repeatingEffect,
+                new VibrationAttributes.Builder()
+                        .setUsage(VibrationAttributes.USAGE_UNKNOWN)
+                        .build());
 
-        // VibrationThread will start this vibration async, wait until it has started.
-        assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(),
-                service, TEST_TIMEOUT_MILLIS));
+        // VibrationThread will start this vibration async.
+        // Wait until second step started to ensure the noteVibratorOn was triggered.
+        assertTrue(waitUntil(s -> fakeVibrator.getAmplitudes().size() == 2, service,
+                TEST_TIMEOUT_MILLIS));
 
         vibrateAndWaitUntilFinished(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK),
                 HAPTIC_FEEDBACK_ATTRS);
@@ -897,9 +924,8 @@
         // The second vibration shouldn't have recorded that the vibrators were turned on.
         verify(mBatteryStatsMock, times(1)).noteVibratorOn(anyInt(), anyLong());
         // No segment played is the prebaked CLICK from the second vibration.
-        assertFalse(mVibratorProviders.get(1).getAllEffectSegments().stream()
+        assertFalse(fakeVibrator.getAllEffectSegments().stream()
                 .anyMatch(PrebakedSegment.class::isInstance));
-        cancelVibrate(service);  // Clean up repeating effect.
     }
 
     @Test
@@ -913,11 +939,13 @@
         VibratorManagerService service = createSystemReadyService();
 
         VibrationEffect repeatingEffect = VibrationEffect.createWaveform(
-                new long[]{10, 10_000}, new int[]{255, 0}, 1);
+                new long[]{10, 10_000}, new int[]{128, 255}, 1);
         vibrate(service, repeatingEffect, ALARM_ATTRS);
 
-        // VibrationThread will start this vibration async, wait until the off waveform step.
-        assertTrue(waitUntil(s -> fakeVibrator.getOffCount() > 0, service, TEST_TIMEOUT_MILLIS));
+        // VibrationThread will start this vibration async.
+        // Wait until second step started to ensure the noteVibratorOn was triggered.
+        assertTrue(waitUntil(s -> fakeVibrator.getAmplitudes().size() == 2, service,
+                TEST_TIMEOUT_MILLIS));
 
         // Cancel vibration right before requesting a new one.
         // This should trigger slow IVibrator.off before setting the vibration status to cancelled.
@@ -925,6 +953,8 @@
         vibrateAndWaitUntilFinished(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK),
                 ALARM_ATTRS);
 
+        // The second vibration should have recorded that the vibrators were turned on.
+        verify(mBatteryStatsMock, times(2)).noteVibratorOn(anyInt(), anyLong());
         // Check that second vibration was played.
         assertTrue(fakeVibrator.getAllEffectSegments().stream()
                 .anyMatch(PrebakedSegment.class::isInstance));
@@ -934,45 +964,47 @@
     public void vibrate_withNewSameImportanceVibrationAndBothRepeating_cancelsOngoingEffect()
             throws Exception {
         mockVibrators(1);
-        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1);
+        fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
         VibratorManagerService service = createSystemReadyService();
 
         VibrationEffect repeatingEffect = VibrationEffect.createWaveform(
-                new long[]{10_000, 10_000}, new int[]{128, 255}, 1);
+                new long[]{10, 10_000}, new int[]{128, 255}, 1);
         vibrate(service, repeatingEffect, ALARM_ATTRS);
 
-        // VibrationThread will start this vibration async, wait until it has started.
-        assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(),
-                service, TEST_TIMEOUT_MILLIS));
+        // VibrationThread will start this vibration async.
+        // Wait until second step started to ensure the noteVibratorOn was triggered.
+        assertTrue(waitUntil(s -> fakeVibrator.getAmplitudes().size() == 2, service,
+                TEST_TIMEOUT_MILLIS));
 
         VibrationEffect repeatingEffect2 = VibrationEffect.createWaveform(
-                new long[]{10_000, 10_000}, new int[]{128, 255}, 1);
+                new long[]{10, 10_000}, new int[]{255, 128}, 1);
         vibrate(service, repeatingEffect2, ALARM_ATTRS);
 
-        // VibrationThread will start this vibration async, so wait before checking it started.
-        assertTrue(waitUntil(s -> mVibratorProviders.get(1).getAllEffectSegments().size() == 2,
-                service, TEST_TIMEOUT_MILLIS));
+        // VibrationThread will start this vibration async.
+        // Wait until second step started to ensure the noteVibratorOn was triggered.
+        assertTrue(waitUntil(s -> fakeVibrator.getAmplitudes().size() == 4, service,
+                TEST_TIMEOUT_MILLIS));
 
         // The second vibration should have recorded that the vibrators were turned on.
         verify(mBatteryStatsMock, times(2)).noteVibratorOn(anyInt(), anyLong());
-
-        cancelVibrate(service);  // Clean up repeating effect.
     }
 
-    @FlakyTest
     @Test
     public void vibrate_withNewSameImportanceVibrationButOngoingIsRepeating_ignoreNewVibration()
             throws Exception {
         mockVibrators(1);
         FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1);
+        fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
         VibratorManagerService service = createSystemReadyService();
 
         VibrationEffect repeatingEffect = VibrationEffect.createWaveform(
-                new long[]{10, 10_000}, new int[]{255, 0}, 1);
+                new long[]{10, 10_000}, new int[]{128, 255}, 1);
         vibrate(service, repeatingEffect, ALARM_ATTRS);
 
-        // VibrationThread will start this vibration async, wait until it has started.
-        assertTrue(waitUntil(s -> !fakeVibrator.getAllEffectSegments().isEmpty(), service,
+        // VibrationThread will start this vibration async.
+        // Wait until second step started to ensure the noteVibratorOn was triggered.
+        assertTrue(waitUntil(s -> fakeVibrator.getAmplitudes().size() == 2, service,
                 TEST_TIMEOUT_MILLIS));
 
         vibrateAndWaitUntilFinished(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK),
@@ -981,53 +1013,55 @@
         // The second vibration shouldn't have recorded that the vibrators were turned on.
         verify(mBatteryStatsMock, times(1)).noteVibratorOn(anyInt(), anyLong());
         // The second vibration shouldn't have played any prebaked segment.
-        assertFalse(mVibratorProviders.get(1).getAllEffectSegments().stream()
+        assertFalse(fakeVibrator.getAllEffectSegments().stream()
                 .anyMatch(PrebakedSegment.class::isInstance));
-        cancelVibrate(service);  // Clean up long effect.
     }
 
     @Test
     public void vibrate_withNewUnknownUsageVibrationAndRepeating_cancelsOngoingEffect()
             throws Exception {
         mockVibrators(1);
+        FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1);
+        fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
         VibratorManagerService service = createSystemReadyService();
 
         VibrationEffect repeatingEffect = VibrationEffect.createWaveform(
-                new long[]{10_000, 10_000}, new int[]{128, 255}, 1);
+                new long[]{10, 10_000}, new int[]{128, 255}, 1);
         vibrate(service, repeatingEffect, ALARM_ATTRS);
 
-        // VibrationThread will start this vibration async, wait until it has started.
-        assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(),
-                service, TEST_TIMEOUT_MILLIS));
+        // VibrationThread will start this vibration async.
+        // Wait until second step started to ensure the noteVibratorOn was triggered.
+        assertTrue(waitUntil(s -> fakeVibrator.getAmplitudes().size() == 2, service,
+                TEST_TIMEOUT_MILLIS));
 
         VibrationEffect repeatingEffect2 = VibrationEffect.createWaveform(
-                new long[]{10_000, 10_000}, new int[]{128, 255}, 1);
+                new long[]{10, 10_000}, new int[]{255, 128}, 1);
         vibrate(service, repeatingEffect2, UNKNOWN_ATTRS);
 
-        // VibrationThread will start this vibration async, so wait before checking it started.
-        assertTrue(waitUntil(s -> mVibratorProviders.get(1).getAllEffectSegments().size() == 2,
-                service, TEST_TIMEOUT_MILLIS));
+        // VibrationThread will start this vibration async.
+        // Wait until second step started to ensure the noteVibratorOn was triggered.
+        assertTrue(waitUntil(s -> fakeVibrator.getAmplitudes().size() == 4, service,
+                TEST_TIMEOUT_MILLIS));
 
         // The second vibration should have recorded that the vibrators were turned on.
         verify(mBatteryStatsMock, times(2)).noteVibratorOn(anyInt(), anyLong());
-
-        cancelVibrate(service);  // Clean up repeating effect.
     }
 
-    @FlakyTest
     @Test
     public void vibrate_withNewUnknownUsageVibrationAndNotRepeating_ignoreNewVibration()
             throws Exception {
         mockVibrators(1);
         FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1);
+        fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
         VibratorManagerService service = createSystemReadyService();
 
         VibrationEffect alarmEffect = VibrationEffect.createWaveform(
-                new long[]{10, 10_000}, new int[]{255, 0}, -1);
+                new long[]{10, 10_000}, new int[]{128, 255}, -1);
         vibrate(service, alarmEffect, ALARM_ATTRS);
 
-        // VibrationThread will start this vibration async, wait until it has started.
-        assertTrue(waitUntil(s -> !fakeVibrator.getAllEffectSegments().isEmpty(), service,
+        // VibrationThread will start this vibration async.
+        // Wait until second step started to ensure the noteVibratorOn was triggered.
+        assertTrue(waitUntil(s -> fakeVibrator.getAmplitudes().size() == 2, service,
                 TEST_TIMEOUT_MILLIS));
 
         vibrateAndWaitUntilFinished(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK),
@@ -1036,23 +1070,24 @@
         // The second vibration shouldn't have recorded that the vibrators were turned on.
         verify(mBatteryStatsMock, times(1)).noteVibratorOn(anyInt(), anyLong());
         // The second vibration shouldn't have played any prebaked segment.
-        assertFalse(mVibratorProviders.get(1).getAllEffectSegments().stream()
+        assertFalse(fakeVibrator.getAllEffectSegments().stream()
                 .anyMatch(PrebakedSegment.class::isInstance));
-        cancelVibrate(service);  // Clean up long effect.
     }
 
     @Test
     public void vibrate_withOngoingHigherImportanceVibration_ignoresEffect() throws Exception {
         mockVibrators(1);
-        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1);
+        fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
         VibratorManagerService service = createSystemReadyService();
 
         VibrationEffect effect = VibrationEffect.createWaveform(
-                new long[]{10_000, 10_000}, new int[]{128, 255}, -1);
+                new long[]{10, 10_000}, new int[]{128, 255}, -1);
         vibrate(service, effect, ALARM_ATTRS);
 
-        // VibrationThread will start this vibration async, so wait before checking it started.
-        assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(),
+        // VibrationThread will start this vibration async.
+        // Wait until second step started to ensure the noteVibratorOn was triggered.
+        assertTrue(waitUntil(s -> fakeVibrator.getAmplitudes().size() == 2,
                 service, TEST_TIMEOUT_MILLIS));
 
         vibrateAndWaitUntilFinished(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK),
@@ -1061,26 +1096,27 @@
         // The second vibration shouldn't have recorded that the vibrators were turned on.
         verify(mBatteryStatsMock, times(1)).noteVibratorOn(anyInt(), anyLong());
         // The second vibration shouldn't have played any prebaked segment.
-        assertFalse(mVibratorProviders.get(1).getAllEffectSegments().stream()
+        assertFalse(fakeVibrator.getAllEffectSegments().stream()
                 .anyMatch(PrebakedSegment.class::isInstance));
-        cancelVibrate(service);  // Clean up long effect.
     }
 
     @Test
     public void vibrate_withOngoingLowerImportanceVibration_cancelsOngoingEffect()
             throws Exception {
         mockVibrators(1);
-        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
-        mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
+        FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1);
+        fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        fakeVibrator.setSupportedEffects(VibrationEffect.EFFECT_CLICK);
         VibratorManagerService service = createSystemReadyService();
 
         VibrationEffect effect = VibrationEffect.createWaveform(
-                new long[]{10_000, 10_000}, new int[]{128, 255}, -1);
+                new long[]{10, 10_000}, new int[]{128, 255}, -1);
         vibrate(service, effect, HAPTIC_FEEDBACK_ATTRS);
 
-        // VibrationThread will start this vibration async, so wait before checking it started.
-        assertTrue(waitUntil(s -> !mVibratorProviders.get(1).getAllEffectSegments().isEmpty(),
-                service, TEST_TIMEOUT_MILLIS));
+        // VibrationThread will start this vibration async.
+        // Wait until second step started to ensure the noteVibratorOn was triggered.
+        assertTrue(waitUntil(s -> fakeVibrator.getAmplitudes().size() == 2, service,
+                TEST_TIMEOUT_MILLIS));
 
         vibrateAndWaitUntilFinished(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK),
                 RINGTONE_ATTRS);
@@ -1088,10 +1124,8 @@
         // The second vibration should have recorded that the vibrators were turned on.
         verify(mBatteryStatsMock, times(2)).noteVibratorOn(anyInt(), anyLong());
         // One segment played is the prebaked CLICK from the second vibration.
-        assertEquals(1,
-                mVibratorProviders.get(1).getAllEffectSegments().stream()
-                        .filter(PrebakedSegment.class::isInstance)
-                        .count());
+        assertEquals(1, fakeVibrator.getAllEffectSegments().stream()
+                .filter(PrebakedSegment.class::isInstance).count());
     }
 
     @Test
@@ -1108,12 +1142,13 @@
         ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME,
                 AUDIO_ALARM_ATTRS,
                 controller, firstToken);
-        int scale = mExternalVibratorService.onExternalVibrationStart(externalVibration);
+        ExternalVibrationScale scale =
+                mExternalVibratorService.onExternalVibrationStart(externalVibration);
 
         vibrateAndWaitUntilFinished(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK),
                 RINGTONE_ATTRS);
 
-        assertNotEquals(IExternalVibratorService.SCALE_MUTE, scale);
+        assertNotEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel);
         // The external vibration should have been cancelled
         verify(controller).mute();
         assertEquals(Arrays.asList(false, true, false),
@@ -1121,10 +1156,8 @@
         // The new vibration should have recorded that the vibrators were turned on.
         verify(mBatteryStatsMock, times(1)).noteVibratorOn(anyInt(), anyLong());
         // One segment played is the prebaked CLICK from the new vibration.
-        assertEquals(1,
-                mVibratorProviders.get(1).getAllEffectSegments().stream()
-                        .filter(PrebakedSegment.class::isInstance)
-                        .count());
+        assertEquals(1, mVibratorProviders.get(1).getAllEffectSegments().stream()
+                .filter(PrebakedSegment.class::isInstance).count());
     }
 
     @Test
@@ -1135,8 +1168,9 @@
                 .build();
 
         mockVibrators(1);
-        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
-        mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
+        FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1);
+        fakeVibrator.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
+        fakeVibrator.setSupportedEffects(VibrationEffect.EFFECT_CLICK);
         VibratorManagerService service = createSystemReadyService();
 
         VibrationEffect effect = VibrationEffect.createWaveform(
@@ -1155,7 +1189,7 @@
         verify(mBatteryStatsMock, times(2)).noteVibratorOn(anyInt(), anyLong());
         // One step segment (with several amplitudes) and one click should have played. Notably
         // there is no primitive segment.
-        List<VibrationEffectSegment> played = mVibratorProviders.get(1).getAllEffectSegments();
+        List<VibrationEffectSegment> played = fakeVibrator.getAllEffectSegments();
         assertEquals(2, played.size());
         assertEquals(1, played.stream().filter(StepSegment.class::isInstance).count());
         assertEquals(1, played.stream().filter(PrebakedSegment.class::isInstance).count());
@@ -1164,8 +1198,9 @@
     @Test
     public void vibrate_withInputDevices_vibratesInputDevices() throws Exception {
         mockVibrators(1);
-        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
-        mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
+        FakeVibratorControllerProvider fakeVibrator = mVibratorProviders.get(1);
+        fakeVibrator.setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
+        fakeVibrator.setSupportedEffects(VibrationEffect.EFFECT_CLICK);
         when(mIInputManagerMock.getInputDeviceIds()).thenReturn(new int[]{1});
         when(mIInputManagerMock.getVibratorIds(eq(1))).thenReturn(new int[]{1});
         when(mIInputManagerMock.getInputDevice(eq(1))).thenReturn(createInputDeviceWithVibrator(1));
@@ -1180,7 +1215,7 @@
         vibrateAndWaitUntilFinished(service, effect, ALARM_ATTRS);
 
         verify(mIInputManagerMock).vibrateCombined(eq(1), eq(effect), any());
-        assertTrue(mVibratorProviders.get(1).getAllEffectSegments().isEmpty());
+        assertTrue(fakeVibrator.getAllEffectSegments().isEmpty());
     }
 
     @Test
@@ -1479,8 +1514,6 @@
         // Alarm vibration will be scaled with SCALE_NONE.
         assertEquals(1f,
                 ((PrimitiveSegment) fakeVibrator.getAllEffectSegments().get(2)).getScale(), 1e-5);
-
-        cancelVibrate(service); // Clean up long-ish effect.
     }
 
     @Test
@@ -1515,8 +1548,6 @@
         assertEquals(1, fakeVibrator.getAllEffectSegments().size());
 
         assertEquals(defaultAmplitude / 255f, fakeVibrator.getAmplitudes().get(0), 1e-5);
-
-        cancelVibrate(service); // Clean up long-ish effect.
     }
 
     @Test
@@ -1552,7 +1583,6 @@
 
         // Vibration is not stopped nearly after updating service.
         assertFalse(waitUntil(s -> !s.isVibrating(1), service, 50));
-        cancelVibrate(service); // Clean up long effect.
     }
 
     @Test
@@ -1578,8 +1608,6 @@
                 HAPTIC_FEEDBACK_ATTRS);
         // Haptic feedback played normally when it's from the default device.
         assertTrue(waitUntil(s -> s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
-
-        cancelVibrate(service);  // Clean up long-ish effect.
     }
 
     @Test
@@ -1708,13 +1736,14 @@
         ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME,
                 AUDIO_ALARM_ATTRS,
                 mock(IExternalVibrationController.class), binderToken);
-        int scale = mExternalVibratorService.onExternalVibrationStart(externalVibration);
-        assertNotEquals(IExternalVibratorService.SCALE_MUTE, scale);
+        ExternalVibrationScale scale = mExternalVibratorService.onExternalVibrationStart(
+                externalVibration);
+        assertNotEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel);
 
         when(mVirtualDeviceManagerInternalMock.isAppRunningOnAnyVirtualDevice(UID))
                 .thenReturn(true);
         scale = mExternalVibratorService.onExternalVibrationStart(externalVibration);
-        assertEquals(IExternalVibratorService.SCALE_MUTE, scale);
+        assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel);
     }
 
     @Test
@@ -1727,10 +1756,11 @@
         ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME,
                 AUDIO_ALARM_ATTRS,
                 mock(IExternalVibrationController.class), binderToken);
-        int scale = mExternalVibratorService.onExternalVibrationStart(externalVibration);
+        ExternalVibrationScale scale = mExternalVibratorService.onExternalVibrationStart(
+                externalVibration);
         mExternalVibratorService.onExternalVibrationStop(externalVibration);
 
-        assertNotEquals(IExternalVibratorService.SCALE_MUTE, scale);
+        assertNotEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel);
         assertEquals(Arrays.asList(false, true, false),
                 mVibratorProviders.get(1).getExternalControlStates());
 
@@ -1753,17 +1783,19 @@
         ExternalVibration firstVibration = new ExternalVibration(UID, PACKAGE_NAME,
                 AUDIO_ALARM_ATTRS,
                 firstController, firstToken);
-        int firstScale = mExternalVibratorService.onExternalVibrationStart(firstVibration);
+        ExternalVibrationScale firstScale =
+                mExternalVibratorService.onExternalVibrationStart(firstVibration);
 
         AudioAttributes ringtoneAudioAttrs = new AudioAttributes.Builder()
                 .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
                 .build();
         ExternalVibration secondVibration = new ExternalVibration(UID, PACKAGE_NAME,
                 ringtoneAudioAttrs, secondController, secondToken);
-        int secondScale = mExternalVibratorService.onExternalVibrationStart(secondVibration);
+        ExternalVibrationScale secondScale =
+                mExternalVibratorService.onExternalVibrationStart(secondVibration);
 
-        assertNotEquals(IExternalVibratorService.SCALE_MUTE, firstScale);
-        assertNotEquals(IExternalVibratorService.SCALE_MUTE, secondScale);
+        assertNotEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, firstScale.scaleLevel);
+        assertNotEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, secondScale.scaleLevel);
         verify(firstController).mute();
         verify(secondController, never()).mute();
         // Set external control called only once.
@@ -1799,8 +1831,9 @@
         ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME,
                 AUDIO_ALARM_ATTRS,
                 mock(IExternalVibrationController.class));
-        int scale = mExternalVibratorService.onExternalVibrationStart(externalVibration);
-        assertNotEquals(IExternalVibratorService.SCALE_MUTE, scale);
+        ExternalVibrationScale scale =
+                mExternalVibratorService.onExternalVibrationStart(externalVibration);
+        assertNotEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel);
 
         // Vibration is cancelled.
         assertTrue(waitUntil(s -> !s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
@@ -1825,14 +1858,13 @@
         ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME,
                 AUDIO_ALARM_ATTRS,
                 mock(IExternalVibrationController.class));
-        int scale = mExternalVibratorService.onExternalVibrationStart(externalVibration);
+        ExternalVibrationScale scale =
+                mExternalVibratorService.onExternalVibrationStart(externalVibration);
         // External vibration is ignored.
-        assertEquals(IExternalVibratorService.SCALE_MUTE, scale);
+        assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel);
 
         // Vibration is not cancelled.
-        assertFalse(waitUntil(s -> !s.isVibrating(1), service, CLEANUP_TIMEOUT_MILLIS));
         assertEquals(Arrays.asList(false), mVibratorProviders.get(1).getExternalControlStates());
-        cancelVibrate(service);  // Clean up long effect.
     }
 
     @Test
@@ -1852,8 +1884,9 @@
 
         ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME,
                 AUDIO_ALARM_ATTRS, mock(IExternalVibrationController.class));
-        int scale = mExternalVibratorService.onExternalVibrationStart(externalVibration);
-        assertNotEquals(IExternalVibratorService.SCALE_MUTE, scale);
+        ExternalVibrationScale scale =
+                mExternalVibratorService.onExternalVibrationStart(externalVibration);
+        assertNotEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel);
 
         // Vibration is cancelled.
         assertTrue(waitUntil(s -> !s.isVibrating(1), service, TEST_TIMEOUT_MILLIS));
@@ -1879,14 +1912,13 @@
         ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME,
                 AUDIO_NOTIFICATION_ATTRS,
                 mock(IExternalVibrationController.class));
-        int scale = mExternalVibratorService.onExternalVibrationStart(externalVibration);
+        ExternalVibrationScale scale =
+                mExternalVibratorService.onExternalVibrationStart(externalVibration);
         // New vibration is ignored.
-        assertEquals(IExternalVibratorService.SCALE_MUTE, scale);
+        assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel);
 
         // Vibration is not cancelled.
-        assertFalse(waitUntil(s -> !s.isVibrating(1), service, CLEANUP_TIMEOUT_MILLIS));
         assertEquals(Arrays.asList(false), mVibratorProviders.get(1).getExternalControlStates());
-        cancelVibrate(service);  // Clean up long effect.
     }
 
     @Test
@@ -1901,18 +1933,19 @@
 
         setRingerMode(AudioManager.RINGER_MODE_SILENT);
         createSystemReadyService();
-        int scale = mExternalVibratorService.onExternalVibrationStart(externalVibration);
-        assertEquals(IExternalVibratorService.SCALE_MUTE, scale);
+        ExternalVibrationScale scale =
+                mExternalVibratorService.onExternalVibrationStart(externalVibration);
+        assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel);
 
         setRingerMode(AudioManager.RINGER_MODE_NORMAL);
         createSystemReadyService();
         scale = mExternalVibratorService.onExternalVibrationStart(externalVibration);
-        assertNotEquals(IExternalVibratorService.SCALE_MUTE, scale);
+        assertNotEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel);
 
         setRingerMode(AudioManager.RINGER_MODE_VIBRATE);
         createSystemReadyService();
         scale = mExternalVibratorService.onExternalVibrationStart(externalVibration);
-        assertNotEquals(IExternalVibratorService.SCALE_MUTE, scale);
+        assertNotEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel);
     }
 
     @Test
@@ -1935,14 +1968,14 @@
 
         ExternalVibration vib = new ExternalVibration(UID, PACKAGE_NAME, audioAttrs,
                 mock(IExternalVibrationController.class));
-        int scale = mExternalVibratorService.onExternalVibrationStart(vib);
-        assertEquals(IExternalVibratorService.SCALE_MUTE, scale);
+        ExternalVibrationScale scale = mExternalVibratorService.onExternalVibrationStart(vib);
+        assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel);
 
         mExternalVibratorService.onExternalVibrationStop(vib);
         scale = mExternalVibratorService.onExternalVibrationStart(
                 new ExternalVibration(UID, PACKAGE_NAME, flaggedAudioAttrs,
                         mock(IExternalVibrationController.class)));
-        assertNotEquals(IExternalVibratorService.SCALE_MUTE, scale);
+        assertNotEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel);
     }
 
     @Test
@@ -1956,10 +1989,91 @@
                 .build();
         createSystemReadyService();
 
-        int scale = mExternalVibratorService.onExternalVibrationStart(
-                new ExternalVibration(/* uid= */ 123, PACKAGE_NAME, flaggedAudioAttrs,
-                        mock(IExternalVibrationController.class)));
-        assertEquals(IExternalVibratorService.SCALE_MUTE, scale);
+        ExternalVibrationScale scale =
+                mExternalVibratorService.onExternalVibrationStart(
+                        new ExternalVibration(/* uid= */ 123, PACKAGE_NAME, flaggedAudioAttrs,
+                                mock(IExternalVibrationController.class)));
+        assertEquals(ExternalVibrationScale.ScaleLevel.SCALE_MUTE, scale.scaleLevel);
+    }
+
+    @Test
+    @RequiresFlagsEnabled(android.os.vibrator.Flags.FLAG_ADAPTIVE_HAPTICS_ENABLED)
+    public void onExternalVibration_withAdaptiveHaptics_returnsCorrectAdaptiveScales()
+            throws RemoteException {
+        mockVibrators(1);
+        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL,
+                IVibrator.CAP_AMPLITUDE_CONTROL);
+        createSystemReadyService();
+
+        SparseArray<Float> vibrationScales = new SparseArray<>();
+        vibrationScales.put(ScaleParam.TYPE_ALARM, 0.7f);
+        vibrationScales.put(ScaleParam.TYPE_NOTIFICATION, 0.4f);
+
+        mVibratorControlService.setVibrationParams(
+                VibrationParamGenerator.generateVibrationParams(vibrationScales),
+                mFakeVibratorController);
+        ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME,
+                AUDIO_ALARM_ATTRS,
+                mock(IExternalVibrationController.class));
+        ExternalVibrationScale scale =
+                mExternalVibratorService.onExternalVibrationStart(externalVibration);
+        mExternalVibratorService.onExternalVibrationStop(externalVibration);
+
+        assertEquals(scale.adaptiveHapticsScale, 0.7f, 0);
+
+        externalVibration = new ExternalVibration(UID, PACKAGE_NAME,
+                AUDIO_NOTIFICATION_ATTRS,
+                mock(IExternalVibrationController.class));
+        scale = mExternalVibratorService.onExternalVibrationStart(externalVibration);
+        mExternalVibratorService.onExternalVibrationStop(externalVibration);
+
+        assertEquals(scale.adaptiveHapticsScale, 0.4f, 0);
+
+        AudioAttributes ringtoneAudioAttrs = new AudioAttributes.Builder()
+                .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
+                .build();
+        externalVibration = new ExternalVibration(UID, PACKAGE_NAME,
+                ringtoneAudioAttrs,
+                mock(IExternalVibrationController.class));
+        scale = mExternalVibratorService.onExternalVibrationStart(externalVibration);
+
+        assertEquals(scale.adaptiveHapticsScale, 1f, 0);
+    }
+
+    @Test
+    @RequiresFlagsDisabled(android.os.vibrator.Flags.FLAG_ADAPTIVE_HAPTICS_ENABLED)
+    public void onExternalVibration_withAdaptiveHapticsFlagDisabled_alwaysReturnScaleNone()
+            throws RemoteException {
+        mockVibrators(1);
+        mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL,
+                IVibrator.CAP_AMPLITUDE_CONTROL);
+        createSystemReadyService();
+
+        SparseArray<Float> vibrationScales = new SparseArray<>();
+        vibrationScales.put(ScaleParam.TYPE_ALARM, 0.7f);
+        vibrationScales.put(ScaleParam.TYPE_NOTIFICATION, 0.4f);
+
+        mVibratorControlService.setVibrationParams(
+                VibrationParamGenerator.generateVibrationParams(vibrationScales),
+                mFakeVibratorController);
+        ExternalVibration externalVibration = new ExternalVibration(UID, PACKAGE_NAME,
+                AUDIO_ALARM_ATTRS,
+                mock(IExternalVibrationController.class));
+        ExternalVibrationScale scale =
+                mExternalVibratorService.onExternalVibrationStart(externalVibration);
+        mExternalVibratorService.onExternalVibrationStop(externalVibration);
+
+        assertEquals(scale.adaptiveHapticsScale, 1f, 0);
+
+        mVibratorControlService.setVibrationParams(
+                VibrationParamGenerator.generateVibrationParams(vibrationScales),
+                mFakeVibratorController);
+        externalVibration = new ExternalVibration(UID, PACKAGE_NAME,
+                AUDIO_NOTIFICATION_ATTRS,
+                mock(IExternalVibrationController.class));
+        scale = mExternalVibratorService.onExternalVibrationStart(externalVibration);
+
+        assertEquals(scale.adaptiveHapticsScale, 1f, 0);
     }
 
     @Test
@@ -2428,29 +2542,29 @@
 
     private HalVibration vibrateAndWaitUntilFinished(VibratorManagerService service,
             CombinedVibration effect, VibrationAttributes attrs) throws InterruptedException {
-        HalVibration vib =
-                service.vibrateWithPermissionCheck(UID, Context.DEVICE_ID_DEFAULT, PACKAGE_NAME,
-                        effect, attrs, "some reason", service);
+        HalVibration vib = vibrate(service, effect, attrs);
         if (vib != null) {
             vib.waitForEnd();
         }
-
         return vib;
     }
 
-    private void vibrate(VibratorManagerService service, VibrationEffect effect,
+    private HalVibration vibrate(VibratorManagerService service, VibrationEffect effect,
             VibrationAttributes attrs) {
-        vibrate(service, CombinedVibration.createParallel(effect), attrs);
+        return vibrate(service, CombinedVibration.createParallel(effect), attrs);
     }
 
-    private void vibrate(VibratorManagerService service, CombinedVibration effect,
+    private HalVibration vibrate(VibratorManagerService service, CombinedVibration effect,
             VibrationAttributes attrs) {
-        vibrateWithDevice(service, Context.DEVICE_ID_DEFAULT, effect, attrs);
+        return vibrateWithDevice(service, Context.DEVICE_ID_DEFAULT, effect, attrs);
     }
 
-    private void vibrateWithDevice(VibratorManagerService service, int deviceId,
+    private HalVibration vibrateWithDevice(VibratorManagerService service, int deviceId,
             CombinedVibration effect, VibrationAttributes attrs) {
-        service.vibrate(UID, deviceId, PACKAGE_NAME, effect, attrs, "some reason", service);
+        HalVibration vib = service.vibrateWithPermissionCheck(UID, deviceId, PACKAGE_NAME, effect,
+                attrs, "some reason", service);
+        mPendingVibrations.add(vib);
+        return vib;
     }
 
     private boolean waitUntil(Predicate<VibratorManagerService> predicate,
diff --git a/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorController.java b/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorController.java
index 3912206..2a010f0 100644
--- a/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorController.java
+++ b/services/tests/vibrator/utils/com/android/server/vibrator/FakeVibratorController.java
@@ -18,7 +18,10 @@
 
 import android.annotation.NonNull;
 import android.frameworks.vibrator.IVibratorController;
+import android.frameworks.vibrator.VibrationParam;
+import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
 import android.os.RemoteException;
 import android.os.VibrationAttributes;
 
@@ -28,17 +31,42 @@
  */
 public final class FakeVibratorController extends IVibratorController.Stub {
 
+    private final Handler mHandler;
+    private VibratorControlService mVibratorControlService;
+    private VibrationParam[] mRequestResult = new VibrationParam[0];
+
     public boolean isLinkedToDeath = false;
     public boolean didRequestVibrationParams = false;
     public int requestVibrationType = VibrationAttributes.USAGE_UNKNOWN;
     public long requestTimeoutInMillis = 0;
 
+    public FakeVibratorController(Looper looper) {
+        mHandler = new Handler(looper);
+    }
+
+    public void setVibratorControlService(VibratorControlService service) {
+        mVibratorControlService = service;
+    }
+
+    public void setRequestResult(VibrationParam... params) {
+        mRequestResult = params;
+    }
+
     @Override
-    public void requestVibrationParams(int vibrationType, long timeoutInMillis, IBinder iBinder)
+    public void requestVibrationParams(int vibrationType, long timeoutInMillis, IBinder token)
             throws RemoteException {
         didRequestVibrationParams = true;
         requestVibrationType = vibrationType;
         requestTimeoutInMillis = timeoutInMillis;
+        mHandler.post(() -> {
+            if (mVibratorControlService != null) {
+                try {
+                    mVibratorControlService.onRequestVibrationParamsComplete(token, mRequestResult);
+                } catch (RemoteException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        });
     }
 
     @Override
diff --git a/services/tests/vibrator/utils/com/android/server/vibrator/VibrationParamGenerator.java b/services/tests/vibrator/utils/com/android/server/vibrator/VibrationParamGenerator.java
new file mode 100644
index 0000000..a606388
--- /dev/null
+++ b/services/tests/vibrator/utils/com/android/server/vibrator/VibrationParamGenerator.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2024 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.server.vibrator;
+
+import android.frameworks.vibrator.ScaleParam;
+import android.frameworks.vibrator.VibrationParam;
+import android.util.SparseArray;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A helper class that can be used to generate arrays of {@link VibrationParam}.
+ */
+public final class VibrationParamGenerator {
+    /**
+     * Generates an array of {@link VibrationParam}.
+     */
+    public static VibrationParam[] generateVibrationParams(SparseArray<Float> vibrationScales) {
+        List<VibrationParam> vibrationParamList = new ArrayList<>();
+        for (int i = 0; i < vibrationScales.size(); i++) {
+            int type = vibrationScales.keyAt(i);
+            float scale = vibrationScales.valueAt(i);
+
+            vibrationParamList.add(generateVibrationParam(type, scale));
+        }
+
+        return vibrationParamList.toArray(new VibrationParam[0]);
+    }
+
+    private static VibrationParam generateVibrationParam(int type, float scale) {
+        ScaleParam scaleParam = new ScaleParam();
+        scaleParam.typesMask = type;
+        scaleParam.scale = scale;
+        VibrationParam vibrationParam = new VibrationParam();
+        vibrationParam.setScale(scaleParam);
+
+        return vibrationParam;
+    }
+}
diff --git a/services/tests/wmtests/Android.bp b/services/tests/wmtests/Android.bp
index e83f03d..b292294 100644
--- a/services/tests/wmtests/Android.bp
+++ b/services/tests/wmtests/Android.bp
@@ -22,16 +22,21 @@
 genrule {
     name: "wmtests.protologsrc",
     srcs: [
+        ":protolog-impl",
         ":protolog-groups",
         ":wmtests-sources",
     ],
     tools: ["protologtool"],
     cmd: "$(location protologtool) transform-protolog-calls " +
         "--protolog-class com.android.internal.protolog.common.ProtoLog " +
-        "--protolog-impl-class com.android.internal.protolog.ProtoLogImpl " +
-        "--protolog-cache-class 'com.android.server.wm.ProtoLogCache' " +
         "--loggroups-class com.android.internal.protolog.ProtoLogGroup " +
         "--loggroups-jar $(location :protolog-groups) " +
+        // Used for the ProtoLogIntegrationTest, where don't test decoding or writing to file
+        // so the parameters below are irrelevant.
+        "--viewer-config-file-path /some/unused/file/path.pb " +
+        "--legacy-viewer-config-file-path /some/unused/file/path.json.gz " +
+        "--legacy-output-file-path /some/unused/file/path.winscope " +
+        // END of irrelevant params.
         "--output-srcjar $(out) " +
         "$(locations :wmtests-sources)",
     out: ["wmtests.protolog.srcjar"],
@@ -42,7 +47,7 @@
 
     // We only want this apk build for tests.
     srcs: [
-        ":wmtests.protologsrc",
+        ":wmtests-sources",
         "src/**/*.aidl",
     ],
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java
index dc4e47d..ef36bff 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DesktopModeLaunchParamsModifierTests.java
@@ -20,8 +20,8 @@
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.util.DisplayMetrics.DENSITY_DEFAULT;
 
+import static com.android.server.wm.DesktopModeLaunchParamsModifier.DESKTOP_MODE_INITIAL_BOUNDS_SCALE;
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS;
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_DISPLAY;
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.RESULT_DONE;
@@ -30,6 +30,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.mock;
 
+import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
@@ -113,9 +114,14 @@
     public void testUsesDefaultBounds() {
         final Task task = new TaskBuilder(mSupervisor).setActivityType(
                 ACTIVITY_TYPE_STANDARD).build();
+        final int displayHeight = 1600;
+        final int displayWidth = 2560;
+        task.getDisplayArea().setBounds(new Rect(0, 0, displayWidth, displayHeight));
+        final int desiredWidth = (int) (displayWidth * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
+        final int desiredHeight = (int) (displayHeight * DESKTOP_MODE_INITIAL_BOUNDS_SCALE);
         assertEquals(RESULT_DONE, new CalculateRequestBuilder().setTask(task).calculate());
-        assertEquals(dpiToPx(task, 840), mResult.mBounds.width());
-        assertEquals(dpiToPx(task, 630), mResult.mBounds.height());
+        assertEquals(desiredWidth, mResult.mBounds.width());
+        assertEquals(desiredHeight, mResult.mBounds.height());
     }
 
     @Test
@@ -131,11 +137,6 @@
         assertEquals(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode);
     }
 
-    private int dpiToPx(Task task, int dpi) {
-        float density = (float) task.getConfiguration().densityDpi / DENSITY_DEFAULT;
-        return (int) (dpi * density + 0.5f);
-    }
-
     private class CalculateRequestBuilder {
         private Task mTask;
         private int mPhase = PHASE_BOUNDS;
diff --git a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index 4c32a58..a0461a6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -42,6 +42,7 @@
 import static org.junit.Assume.assumeTrue;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
@@ -541,7 +542,7 @@
     }
 
     @Test
-    public void testUnhandledDragListenerNotCalledForNormalDrags() throws RemoteException {
+    public void testUnhandledDragNotCalledForNormalDrags() throws RemoteException {
         assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags());
 
         final IGlobalDragListener listener = mock(IGlobalDragListener.class);
@@ -552,15 +553,16 @@
     }
 
     @Test
-    public void testUnhandledDragListenerReceivesUnhandledDropOverWindow() {
+    public void testUnhandledDragReceivesUnhandledDropOverWindow() {
         assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags());
 
         final IGlobalDragListener listener = mock(IGlobalDragListener.class);
         doReturn(mock(Binder.class)).when(listener).asBinder();
         mTarget.setGlobalDragListener(listener);
         final int invalidXY = 100_000;
-        startDrag(View.DRAG_FLAG_GLOBAL, ClipData.newPlainText("label", "Test"), () -> {
-            // Notify the unhandled drag listener
+        startDrag(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG,
+                ClipData.newPlainText("label", "Test"), () -> {
+            // Trigger an unhandled drop and verify the global drag listener was called
             mTarget.reportDropWindow(mWindow.mInputChannelToken, invalidXY, invalidXY);
             mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY);
             mTarget.reportDropResult(mWindow.mClient, false);
@@ -575,15 +577,16 @@
     }
 
     @Test
-    public void testUnhandledDragListenerReceivesUnhandledDropOverNoValidWindow() {
+    public void testUnhandledDragReceivesUnhandledDropOverNoValidWindow() {
         assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags());
 
         final IGlobalDragListener listener = mock(IGlobalDragListener.class);
         doReturn(mock(Binder.class)).when(listener).asBinder();
         mTarget.setGlobalDragListener(listener);
         final int invalidXY = 100_000;
-        startDrag(View.DRAG_FLAG_GLOBAL, ClipData.newPlainText("label", "Test"), () -> {
-            // Notify the unhandled drag listener
+        startDrag(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG,
+                ClipData.newPlainText("label", "Test"), () -> {
+            // Trigger an unhandled drop and verify the global drag listener was called
             mTarget.reportDropWindow(mock(IBinder.class), invalidXY, invalidXY);
             mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY);
             mTarget.onUnhandledDropCallback(true);
@@ -597,15 +600,38 @@
     }
 
     @Test
-    public void testUnhandledDragListenerCallbackTimeout() {
+    public void testUnhandledDragDoesNotReceiveUnhandledDropWithoutDragFlag() {
         assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags());
 
         final IGlobalDragListener listener = mock(IGlobalDragListener.class);
         doReturn(mock(Binder.class)).when(listener).asBinder();
         mTarget.setGlobalDragListener(listener);
         final int invalidXY = 100_000;
-        startDrag(View.DRAG_FLAG_GLOBAL, ClipData.newPlainText("label", "Test"), () -> {
-            // Notify the unhandled drag listener
+        startDrag(View.DRAG_FLAG_GLOBAL,
+                ClipData.newPlainText("label", "Test"), () -> {
+                    // Trigger an unhandled drop and verify the global drag listener was not called
+                    mTarget.reportDropWindow(mock(IBinder.class), invalidXY, invalidXY);
+                    mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY);
+                    mToken = null;
+                    try {
+                        verify(listener, never()).onUnhandledDrop(any(), any());
+                    } catch (RemoteException e) {
+                        fail("Failed to verify unhandled drop: " + e);
+                    }
+                });
+    }
+
+    @Test
+    public void testUnhandledDragCallbackTimeout() {
+        assumeTrue(com.android.window.flags.Flags.delegateUnhandledDrags());
+
+        final IGlobalDragListener listener = mock(IGlobalDragListener.class);
+        doReturn(mock(Binder.class)).when(listener).asBinder();
+        mTarget.setGlobalDragListener(listener);
+        final int invalidXY = 100_000;
+        startDrag(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG,
+                ClipData.newPlainText("label", "Test"), () -> {
+            // Trigger an unhandled drop and verify the global drag listener was called
             mTarget.reportDropWindow(mock(IBinder.class), invalidXY, invalidXY);
             mTarget.handleMotionEvent(false /* keepHandling */, invalidXY, invalidXY);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java b/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java
index af0d32c..c5bf78b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ProtoLogIntegrationTest.java
@@ -27,6 +27,8 @@
 
 import com.android.internal.protolog.ProtoLogGroup;
 import com.android.internal.protolog.ProtoLogImpl;
+import com.android.internal.protolog.common.IProtoLog;
+import com.android.internal.protolog.common.LogLevel;
 import com.android.internal.protolog.common.ProtoLog;
 
 import org.junit.After;
@@ -47,9 +49,9 @@
     @Ignore("b/163095037")
     @Test
     public void testProtoLogToolIntegration() {
-        ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class);
+        IProtoLog mockedProtoLog = mock(IProtoLog.class);
         runWith(mockedProtoLog, this::testProtoLog);
-        verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.ERROR), eq(ProtoLogGroup.TEST_GROUP),
+        verify(mockedProtoLog).log(eq(LogLevel.ERROR), eq(ProtoLogGroup.TEST_GROUP),
                 anyInt(), eq(0b0010010111),
                 eq(com.android.internal.protolog.ProtoLogGroup.TEST_GROUP.isLogToLogcat()
                         ? "Test completed successfully: %b %d %x %f %% %s"
@@ -66,18 +68,13 @@
     /**
      * Starts protolog for the duration of {@code runnable}, with a ProtoLogImpl instance installed.
      */
-    private void runWith(ProtoLogImpl mockInstance, Runnable runnable) {
-        ProtoLogImpl original = ProtoLogImpl.getSingleInstance();
-        original.startProtoLog(null);
+    private void runWith(IProtoLog mockInstance, Runnable runnable) {
+        IProtoLog original = ProtoLog.getSingleInstance();
+        ProtoLogImpl.setSingleInstance(mockInstance);
         try {
-            ProtoLogImpl.setSingleInstance(mockInstance);
-            try {
-                runnable.run();
-            } finally {
-                ProtoLogImpl.setSingleInstance(original);
-            }
+            runnable.run();
         } finally {
-            original.stopProtoLog(null, false);
+            ProtoLogImpl.setSingleInstance(original);
         }
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 9930c88..f7c253d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -46,7 +46,6 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.mock;
@@ -73,6 +72,7 @@
 import android.os.UserManager;
 import android.platform.test.annotations.Presubmit;
 import android.util.ArraySet;
+import android.util.IntArray;
 import android.util.SparseBooleanArray;
 import android.view.Surface;
 import android.window.TaskSnapshot;
@@ -527,20 +527,20 @@
         mTaskPersister.mUserTaskIdsOverride.put(1, true);
         mTaskPersister.mUserTaskIdsOverride.put(2, true);
         mTaskPersister.mUserTasksOverride = new ArrayList<>();
-        mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask1").build());
-        mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask2").build());
+        mTaskPersister.mUserTasksOverride.add(mTasks.get(0));
+        mTaskPersister.mUserTasksOverride.add(mTasks.get(1));
 
         // Assert no user tasks are initially loaded
         assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).hasLength(0);
 
         // Load user 0 tasks
-        mRecentTasks.loadUserRecentsLocked(TEST_USER_0_ID);
+        mRecentTasks.loadRecentTasksIfNeeded(TEST_USER_0_ID);
         assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList().contains(TEST_USER_0_ID);
         assertTrue(mRecentTasks.containsTaskId(1, TEST_USER_0_ID));
         assertTrue(mRecentTasks.containsTaskId(2, TEST_USER_0_ID));
 
         // Load user 1 tasks
-        mRecentTasks.loadUserRecentsLocked(TEST_USER_1_ID);
+        mRecentTasks.loadRecentTasksIfNeeded(TEST_USER_1_ID);
         assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList().contains(TEST_USER_0_ID);
         assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList().contains(TEST_USER_1_ID);
         assertTrue(mRecentTasks.containsTaskId(1, TEST_USER_0_ID));
@@ -575,15 +575,15 @@
         mTaskPersister.mUserTaskIdsOverride.put(2, true);
         mTaskPersister.mUserTaskIdsOverride.put(3, true);
         mTaskPersister.mUserTasksOverride = new ArrayList<>();
-        mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask1").build());
-        mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask2").build());
-        mTaskPersister.mUserTasksOverride.add(createTaskBuilder(".UserTask3").build());
+        mTaskPersister.mUserTasksOverride.add(mTasks.get(0));
+        mTaskPersister.mUserTasksOverride.add(mTasks.get(1));
+        mTaskPersister.mUserTasksOverride.add(mTasks.get(2));
 
         // Assert no user tasks are initially loaded
         assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).hasLength(0);
 
         // Load tasks
-        mRecentTasks.loadUserRecentsLocked(TEST_USER_0_ID);
+        mRecentTasks.loadRecentTasksIfNeeded(TEST_USER_0_ID);
         assertThat(mRecentTasks.usersWithRecentsLoadedLocked()).asList().contains(TEST_USER_0_ID);
 
         // Sort the time descendingly so the order should be in-sync with task recency (most
@@ -1419,8 +1419,6 @@
     }
 
     private List<RecentTaskInfo> getRecentTasks(int flags) {
-        doNothing().when(mRecentTasks).loadUserRecentsLocked(anyInt());
-        doReturn(true).when(mRecentTasks).isUserRunning(anyInt(), anyInt());
         return mRecentTasks.getRecentTasks(MAX_VALUE, flags, true /* getTasksAllowed */,
                 TEST_USER_0_ID, 0 /* callingUid */).getList();
     }
@@ -1590,19 +1588,20 @@
         }
 
         @Override
-        SparseBooleanArray loadPersistedTaskIdsForUser(int userId) {
+        SparseBooleanArray readPersistedTaskIdsFromFileForUser(int userId) {
             if (mUserTaskIdsOverride != null) {
                 return mUserTaskIdsOverride;
             }
-            return super.loadPersistedTaskIdsForUser(userId);
+            return super.readPersistedTaskIdsFromFileForUser(userId);
         }
 
         @Override
-        List<Task> restoreTasksForUserLocked(int userId, SparseBooleanArray preaddedTasks) {
+        ArrayList<Task> restoreTasksForUserLocked(int userId, RecentTaskFiles recentTaskFiles,
+                IntArray existedTaskIds) {
             if (mUserTasksOverride != null) {
                 return mUserTasksOverride;
             }
-            return super.restoreTasksForUserLocked(userId, preaddedTasks);
+            return super.restoreTasksForUserLocked(userId, recentTaskFiles, existedTaskIds);
         }
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java
index 12ed3c2..319be89 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java
@@ -29,8 +29,6 @@
 import android.platform.test.annotations.Presubmit;
 import android.util.SparseBooleanArray;
 
-import androidx.test.filters.FlakyTest;
-
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -81,7 +79,7 @@
         }
         mTaskPersister.writePersistedTaskIdsForUser(taskIdsOnFile, mTestUserId);
         SparseBooleanArray newTaskIdsOnFile = mTaskPersister
-                .loadPersistedTaskIdsForUser(mTestUserId);
+                .readPersistedTaskIdsFromFileForUser(mTestUserId);
         assertEquals("TaskIds written differ from TaskIds read back from file",
                 taskIdsOnFile, newTaskIdsOnFile);
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index a0e64bf..12f46df 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -82,7 +82,10 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsDisabled;
 import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
 import android.util.ArraySet;
 import android.util.MergedConfiguration;
 import android.view.ContentRecordingSession;
@@ -109,6 +112,7 @@
 import com.android.server.LocalServices;
 import com.android.server.wm.SensitiveContentPackages.PackageInfo;
 import com.android.server.wm.WindowManagerService.WindowContainerInfo;
+import com.android.window.flags.Flags;
 
 import com.google.common.truth.Expect;
 
@@ -140,6 +144,9 @@
     @Rule
     public Expect mExpect = Expect.create();
 
+    @Rule
+    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
     @After
     public void tearDown() {
         mWm.mSensitiveContentPackages.clearBlockedApps();
@@ -1106,6 +1113,7 @@
                 argThat(h -> (h.inputConfig & InputConfig.SPY) == InputConfig.SPY));
     }
 
+    @RequiresFlagsDisabled(Flags.FLAG_MAGNIFICATION_ALWAYS_DRAW_FULLSCREEN_BORDER)
     @Test
     public void testDrawMagnifiedViewport() {
         final int displayId = mDisplayContent.mDisplayId;
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
index 0a1f3c7..ad7b9e6 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DetectorSession.java
@@ -411,7 +411,8 @@
                 audioFormat,
                 options,
                 callback,
-                /* shouldCloseAudioStreamWithDelayOnDetect= */ true);
+                /* shouldCloseAudioStreamWithDelayOnDetect= */ true,
+                /* shouldCheckPermissionsAndAppOpsOnDetected= */ true);
     }
 
     void startListeningFromWearableLocked(
@@ -481,12 +482,29 @@
                         return null;
                     }
                 };
+        /*
+         * By setting shouldCheckPermissionsAndAppOpsOnDetected to false, when the audio
+         * stream is sent from the sandboxed HotwordDetectionService to the non-sandboxed
+         * VoiceInteractionService as a result of second-stage hotword detection, audio-related
+         * permissions will not be checked against the VoiceInteractionService and the AppOpsManager
+         * will not be notified of the data flow to the VoiceInteractionService. These checks are
+         * not performed because the audio stream here originates from a remotely connected wearable
+         * device. It does not originate from the microphone of the device where this code runs on,
+         * or a microphone directly controlled by this system. Permission checks are expected to
+         * happen on the remote wearable device. From the perspective of this system, the audio
+         * stream is data received from an external source.
+         *
+         * Not notifying AppOpsManager allows this device's microphone indicator to remain off when
+         * this data flow happens. It avoids confusion since the audio does not originate from
+         * this device. The wearable is expected to turn on its own microphone indicator.
+         */
         handleExternalSourceHotwordDetectionLocked(
                 audioStream,
                 audioFormat,
                 options,
                 voiceInteractionCallback,
-                /* shouldCloseAudioStreamWithDelayOnDetect= */ false);
+                /* shouldCloseAudioStreamWithDelayOnDetect= */ false,
+                /* shouldCheckPermissionsAndAppOpsOnDetected= */ false);
     }
 
     @SuppressWarnings("GuardedBy")
@@ -495,7 +513,8 @@
             AudioFormat audioFormat,
             @Nullable PersistableBundle options,
             IMicrophoneHotwordDetectionVoiceInteractionCallback callback,
-            boolean shouldCloseAudioStreamWithDelayOnDetect) {
+            boolean shouldCloseAudioStreamWithDelayOnDetect,
+            boolean shouldCheckPermissionsAndAppOpsOnDetected) {
         if (DEBUG) {
             Slog.d(TAG, "#handleExternalSourceHotwordDetectionLocked");
         }
@@ -631,36 +650,39 @@
                                                     EXTERNAL_HOTWORD_CLEANUP_MILLIS,
                                                     TimeUnit.MILLISECONDS);
                                         }
-                                        try {
-                                            enforcePermissionsForDataDelivery();
-                                        } catch (SecurityException e) {
-                                            Slog.w(
-                                                    TAG,
-                                                    "Ignoring #onDetected due to a "
-                                                            + "SecurityException",
-                                                    e);
-                                            HotwordMetricsLogger.writeDetectorEvent(
-                                                    getDetectorType(),
-                                                    EXTERNAL_SOURCE_DETECT_SECURITY_EXCEPTION,
-                                                    mVoiceInteractionServiceUid);
+                                        if (shouldCheckPermissionsAndAppOpsOnDetected) {
                                             try {
-                                                callback.onHotwordDetectionServiceFailure(
+                                                enforcePermissionsForDataDelivery();
+                                            } catch (SecurityException e) {
+                                                Slog.w(
+                                                        TAG,
+                                                        "Ignoring #onDetected due to a "
+                                                                + "SecurityException",
+                                                        e);
+                                                HotwordMetricsLogger.writeDetectorEvent(
+                                                        getDetectorType(),
+                                                        EXTERNAL_SOURCE_DETECT_SECURITY_EXCEPTION,
+                                                        mVoiceInteractionServiceUid);
+                                                try {
+                                                    callback.onHotwordDetectionServiceFailure(
                                                         new HotwordDetectionServiceFailure(
                                                                 ONDETECTED_GOT_SECURITY_EXCEPTION,
                                                                 "Security exception occurs in "
                                                                         + "#onDetected method"));
-                                            } catch (RemoteException e1) {
-                                                notifyOnDetectorRemoteException();
-                                                throw e1;
+                                                } catch (RemoteException e1) {
+                                                    notifyOnDetectorRemoteException();
+                                                    throw e1;
+                                                }
+                                                return;
                                             }
-                                            return;
                                         }
                                         HotwordDetectedResult newResult;
                                         try {
                                             newResult =
-                                                    mHotwordAudioStreamCopier
-                                                            .startCopyingAudioStreams(
-                                                                    triggerResult);
+                                                mHotwordAudioStreamCopier
+                                                    .startCopyingAudioStreams(
+                                                        triggerResult,
+                                                        shouldCheckPermissionsAndAppOpsOnDetected);
                                         } catch (IOException e) {
                                             Slog.w(
                                                     TAG,
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java
index 65c95d1..6f00dc8 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java
@@ -87,19 +87,32 @@
     }
 
     /**
-     * Starts copying the audio streams in the given {@link HotwordDetectedResult}.
-     * <p>
-     * The returned {@link HotwordDetectedResult} is identical the one that was passed in, except
-     * that the {@link ParcelFileDescriptor}s within {@link HotwordDetectedResult#getAudioStreams()}
-     * are replaced with descriptors from pipes managed by {@link HotwordAudioStreamCopier}. The
-     * returned value should be passed on to the client (i.e., the voice interactor).
-     * </p>
-     *
-     * @throws IOException If there was an error creating the managed pipe.
+     * Calls {@link #startCopyingAudioStreams(HotwordDetectedResult, boolean)} and notifies
+     * AppOpsManager of the {@link AppOpsManager#OPSTR_RECORD_AUDIO_HOTWORD} operation.
      */
     @NonNull
     public HotwordDetectedResult startCopyingAudioStreams(@NonNull HotwordDetectedResult result)
             throws IOException {
+        return startCopyingAudioStreams(result, /* shouldNotifyAppOpsManager= */ true);
+    }
+
+    /**
+     * Starts copying the audio streams in the given {@link HotwordDetectedResult}.
+     *
+     * <p>The returned {@link HotwordDetectedResult} is identical the one that was passed in, except
+     * that the {@link ParcelFileDescriptor}s within {@link HotwordDetectedResult#getAudioStreams()}
+     * are replaced with descriptors from pipes managed by {@link HotwordAudioStreamCopier}. The
+     * returned value should be passed on to the client (i.e., the voice interactor).
+     *
+     * @param result The {@link HotwordDetectedResult} to copy from.
+     * @param shouldNotifyAppOpsManager Whether the {@link AppOpsManager} should be notified of the
+     *     {@link AppOpsManager#OPSTR_RECORD_AUDIO_HOTWORD} operation during the copy.
+     * @throws IOException If there was an error creating the managed pipe.
+     */
+    @NonNull
+    public HotwordDetectedResult startCopyingAudioStreams(
+            @NonNull HotwordDetectedResult result, boolean shouldNotifyAppOpsManager)
+            throws IOException {
         List<HotwordAudioStream> audioStreams = result.getAudioStreams();
         if (audioStreams.isEmpty()) {
             HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType,
@@ -154,8 +167,12 @@
 
         String resultTaskId = TASK_ID_PREFIX + System.identityHashCode(result);
         mExecutorService.execute(
-                new HotwordDetectedResultCopyTask(resultTaskId, copyTaskInfos,
-                        totalMetadataBundleSizeBytes, totalInitialAudioSizeBytes));
+                new HotwordDetectedResultCopyTask(
+                        resultTaskId,
+                        copyTaskInfos,
+                        totalMetadataBundleSizeBytes,
+                        totalInitialAudioSizeBytes,
+                        shouldNotifyAppOpsManager));
 
         return result.buildUpon().setAudioStreams(newAudioStreams).build();
     }
@@ -178,13 +195,19 @@
         private final int mTotalMetadataSizeBytes;
         private final int mTotalInitialAudioSizeBytes;
         private final ExecutorService mExecutorService = Executors.newCachedThreadPool();
+        private final boolean mShouldNotifyAppOpsManager;
 
-        HotwordDetectedResultCopyTask(String resultTaskId, List<CopyTaskInfo> copyTaskInfos,
-                int totalMetadataSizeBytes, int totalInitialAudioSizeBytes) {
+        HotwordDetectedResultCopyTask(
+                String resultTaskId,
+                List<CopyTaskInfo> copyTaskInfos,
+                int totalMetadataSizeBytes,
+                int totalInitialAudioSizeBytes,
+                boolean shouldNotifyAppOpsManager) {
             mResultTaskId = resultTaskId;
             mCopyTaskInfos = copyTaskInfos;
             mTotalMetadataSizeBytes = totalMetadataSizeBytes;
             mTotalInitialAudioSizeBytes = totalInitialAudioSizeBytes;
+            mShouldNotifyAppOpsManager = shouldNotifyAppOpsManager;
         }
 
         @Override
@@ -200,55 +223,14 @@
                         mVoiceInteractorUid));
             }
 
-            if (mAppOpsManager.startOpNoThrow(AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD,
-                    mVoiceInteractorUid, mVoiceInteractorPackageName,
-                    mVoiceInteractorAttributionTag, OP_MESSAGE) == MODE_ALLOWED) {
-                try {
-                    HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType,
-                            HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__STARTED,
-                            mVoiceInteractorUid, mTotalInitialAudioSizeBytes,
-                            mTotalMetadataSizeBytes, size);
-                    // TODO(b/244599891): Set timeout, close after inactivity
-                    mExecutorService.invokeAll(tasks);
-
-                    // We are including the non-streamed initial audio
-                    // (HotwordAudioStream.getInitialAudio()) bytes in the "stream" size metrics.
-                    int totalStreamSizeBytes = mTotalInitialAudioSizeBytes;
-                    for (SingleAudioStreamCopyTask task : tasks) {
-                        totalStreamSizeBytes += task.mTotalCopiedBytes;
-                    }
-
-                    Slog.i(TAG, mResultTaskId + ": Task was completed. Total bytes egressed: "
-                            + totalStreamSizeBytes + " (including " + mTotalInitialAudioSizeBytes
-                            + " bytes NOT streamed), total metadata bundle size bytes: "
-                            + mTotalMetadataSizeBytes);
-                    HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType,
-                            HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__ENDED,
-                            mVoiceInteractorUid, totalStreamSizeBytes, mTotalMetadataSizeBytes,
-                            size);
-                } catch (InterruptedException e) {
-                    // We are including the non-streamed initial audio
-                    // (HotwordAudioStream.getInitialAudio()) bytes in the "stream" size metrics.
-                    int totalStreamSizeBytes = mTotalInitialAudioSizeBytes;
-                    for (SingleAudioStreamCopyTask task : tasks) {
-                        totalStreamSizeBytes += task.mTotalCopiedBytes;
-                    }
-
-                    HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType,
-                            HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__INTERRUPTED_EXCEPTION,
-                            mVoiceInteractorUid, totalStreamSizeBytes, mTotalMetadataSizeBytes,
-                            size);
-                    Slog.i(TAG, mResultTaskId + ": Task was interrupted. Total bytes egressed: "
-                            + totalStreamSizeBytes + " (including " + mTotalInitialAudioSizeBytes
-                            + " bytes NOT streamed), total metadata bundle size bytes: "
-                            + mTotalMetadataSizeBytes);
-                    bestEffortPropagateError(e.getMessage());
-                } finally {
-                    mAppOpsManager.finishOp(AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD,
-                            mVoiceInteractorUid, mVoiceInteractorPackageName,
-                            mVoiceInteractorAttributionTag);
-                }
-            } else {
+            if (mShouldNotifyAppOpsManager
+                    && mAppOpsManager.startOpNoThrow(
+                                    AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD,
+                                    mVoiceInteractorUid,
+                                    mVoiceInteractorPackageName,
+                                    mVoiceInteractorAttributionTag,
+                                    OP_MESSAGE)
+                            != MODE_ALLOWED) {
                 HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType,
                         HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__NO_PERMISSION,
                         mVoiceInteractorUid, /* streamSizeBytes= */ 0, /* bundleSizeBytes= */ 0,
@@ -258,6 +240,56 @@
                                 + " uid=" + mVoiceInteractorUid
                                 + " packageName=" + mVoiceInteractorPackageName
                                 + " attributionTag=" + mVoiceInteractorAttributionTag);
+                return;
+            }
+            try {
+                HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType,
+                        HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__STARTED,
+                        mVoiceInteractorUid, mTotalInitialAudioSizeBytes,
+                        mTotalMetadataSizeBytes, size);
+                // TODO(b/244599891): Set timeout, close after inactivity
+                mExecutorService.invokeAll(tasks);
+
+                // We are including the non-streamed initial audio
+                // (HotwordAudioStream.getInitialAudio()) bytes in the "stream" size metrics.
+                int totalStreamSizeBytes = mTotalInitialAudioSizeBytes;
+                for (SingleAudioStreamCopyTask task : tasks) {
+                    totalStreamSizeBytes += task.mTotalCopiedBytes;
+                }
+
+                Slog.i(TAG, mResultTaskId + ": Task was completed. Total bytes egressed: "
+                        + totalStreamSizeBytes + " (including " + mTotalInitialAudioSizeBytes
+                        + " bytes NOT streamed), total metadata bundle size bytes: "
+                        + mTotalMetadataSizeBytes);
+                HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType,
+                        HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__ENDED,
+                        mVoiceInteractorUid, totalStreamSizeBytes, mTotalMetadataSizeBytes,
+                        size);
+            } catch (InterruptedException e) {
+                // We are including the non-streamed initial audio
+                // (HotwordAudioStream.getInitialAudio()) bytes in the "stream" size metrics.
+                int totalStreamSizeBytes = mTotalInitialAudioSizeBytes;
+                for (SingleAudioStreamCopyTask task : tasks) {
+                    totalStreamSizeBytes += task.mTotalCopiedBytes;
+                }
+
+                HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType,
+                        HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__INTERRUPTED_EXCEPTION,
+                        mVoiceInteractorUid, totalStreamSizeBytes, mTotalMetadataSizeBytes,
+                        size);
+                Slog.i(TAG, mResultTaskId + ": Task was interrupted. Total bytes egressed: "
+                        + totalStreamSizeBytes + " (including " + mTotalInitialAudioSizeBytes
+                        + " bytes NOT streamed), total metadata bundle size bytes: "
+                        + mTotalMetadataSizeBytes);
+                bestEffortPropagateError(e.getMessage());
+            } finally {
+                if (mShouldNotifyAppOpsManager) {
+                    mAppOpsManager.finishOp(
+                            AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD,
+                            mVoiceInteractorUid,
+                            mVoiceInteractorPackageName,
+                            mVoiceInteractorAttributionTag);
+                }
             }
         }
 
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 889f842..aef7158 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -16,15 +16,21 @@
 
 package com.android.server.voiceinteraction;
 
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION;
+import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION;
 
 import android.Manifest;
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
+import android.app.ActivityOptions;
 import android.app.AppGlobals;
+import android.app.admin.DevicePolicyManagerInternal;
 import android.app.role.OnRoleHoldersChangedListener;
 import android.app.role.RoleManager;
 import android.content.ComponentName;
@@ -41,6 +47,7 @@
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.database.ContentObserver;
+import android.graphics.Bitmap;
 import android.hardware.soundtrigger.IRecognitionStatusCallback;
 import android.hardware.soundtrigger.KeyphraseMetadata;
 import android.hardware.soundtrigger.ModelParams;
@@ -84,6 +91,7 @@
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.Slog;
+import android.window.ScreenCapture;
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
@@ -110,7 +118,9 @@
 import com.android.server.policy.AppOpsPolicy;
 import com.android.server.utils.Slogf;
 import com.android.server.utils.TimingsTraceAndSlog;
+import com.android.server.wm.ActivityAssistInfo;
 import com.android.server.wm.ActivityTaskManagerInternal;
+import com.android.server.wm.WindowManagerInternal;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -127,6 +137,19 @@
     static final String TAG = "VoiceInteractionManager";
     static final boolean DEBUG = false;
 
+    /** Static constants used by Contextual Search helper. */
+    private static final String CS_KEY_FLAG_SECURE_FOUND =
+            "com.android.contextualsearch.flag_secure_found";
+    private static final String CS_KEY_FLAG_SCREENSHOT =
+            "com.android.contextualsearch.screenshot";
+    private static final String CS_KEY_FLAG_IS_MANAGED_PROFILE_VISIBLE =
+            "com.android.contextualsearch.is_managed_profile_visible";
+    private static final String CS_KEY_FLAG_VISIBLE_PACKAGE_NAMES =
+            "com.android.contextualsearch.visible_package_names";
+    private static final String CS_INTENT_FILTER =
+            "com.android.contextualsearch.LAUNCH";
+
+
     final Context mContext;
     final ContentResolver mResolver;
     // Can be overridden for testing purposes
@@ -135,6 +158,8 @@
     final ActivityManagerInternal mAmInternal;
     final ActivityTaskManagerInternal mAtmInternal;
     final UserManagerInternal mUserManagerInternal;
+    final WindowManagerInternal mWmInternal;
+    final DevicePolicyManagerInternal mDpmInternal;
     final ArrayMap<Integer, VoiceInteractionManagerServiceStub.SoundTriggerSession>
             mLoadedKeyphraseIds = new ArrayMap<>();
     ShortcutServiceInternal mShortcutServiceInternal;
@@ -156,7 +181,10 @@
                 LocalServices.getService(ActivityManagerInternal.class));
         mAtmInternal = Objects.requireNonNull(
                 LocalServices.getService(ActivityTaskManagerInternal.class));
-
+        mWmInternal = Objects.requireNonNull(
+                LocalServices.getService(WindowManagerInternal.class));
+        mDpmInternal = Objects.requireNonNull(
+                LocalServices.getService(DevicePolicyManagerInternal.class));
         LegacyPermissionManagerInternal permissionManagerInternal = LocalServices.getService(
                 LegacyPermissionManagerInternal.class);
         permissionManagerInternal.setVoiceInteractionPackagesProvider(
@@ -1019,6 +1047,56 @@
         public boolean showSessionFromSession(@NonNull IBinder token, @Nullable Bundle sessionArgs,
                 int flags, @Nullable String attributionTag) {
             synchronized (this) {
+                final String csKey = mContext.getResources()
+                        .getString(R.string.config_defaultContextualSearchKey);
+                final String csEnabledKey = mContext.getResources()
+                        .getString(R.string.config_defaultContextualSearchEnabled);
+
+                // If the request is for Contextual Search, process it differently
+                if (sessionArgs != null && sessionArgs.containsKey(csKey)) {
+                    if (sessionArgs.getBoolean(csEnabledKey, true)) {
+                        // If Contextual Search is enabled, try to follow that path.
+                        Intent launchIntent = getContextualSearchIntent(sessionArgs);
+                        if (launchIntent != null) {
+                            // Hand over to contextual search helper.
+                            Slog.d(TAG, "Handed over to contextual search helper.");
+                            final long caller = Binder.clearCallingIdentity();
+                            try {
+                                return startContextualSearch(launchIntent);
+                            } finally {
+                                Binder.restoreCallingIdentity(caller);
+                            }
+                        }
+                    }
+
+                    // Since we are here, Contextual Search helper couldn't handle the request.
+                    final String visEnabledKey = mContext.getResources()
+                            .getString(R.string.config_defaultContextualSearchLegacyEnabled);
+                    if (sessionArgs.getBoolean(visEnabledKey, true)) {
+                        // If visEnabledKey is set to true (or absent), we try following VIS path.
+                        String csPkgName = mContext.getResources()
+                                .getString(R.string.config_defaultContextualSearchPackageName);
+                        if (!csPkgName.equals(getCurInteractor(
+                                Binder.getCallingUserHandle().getIdentifier()).getPackageName())) {
+                            // Check if the interactor can handle Contextual Search.
+                            // If not, return failure.
+                            Slog.w(TAG, "Contextual Search not supported yet. Returning failure.");
+                            return false;
+                        }
+                    } else {
+                        // If visEnabledKey is set to false AND the request was for Contextual
+                        // Search, return false.
+                        return false;
+                    }
+                    // Given that we haven't returned yet, we can say that
+                    // - Contextual Search Helper couldn't handle the request
+                    // - VIS path for Contextual Search is enabled
+                    // - The current interactor supports Contextual Search.
+                    // Hence, we will proceed with the VIS path.
+                    Slog.d(TAG, "Contextual search not supported yet. Proceeding with VIS.");
+
+                }
+
                 if (mImpl == null) {
                     Slog.w(TAG, "showSessionFromSession without running voice interaction service");
                     return false;
@@ -2582,7 +2660,6 @@
                         if (anyPackagesAppearing()) {
                             initRecognizer(userHandle);
                         }
-                        return;
                     }
 
                     if (curInteractor != null) {
@@ -2631,19 +2708,84 @@
                         }
                     }
 
-                    // There is no interactor, so just deal with a simple recognizer.
-                    int change = isPackageDisappearing(curRecognizer.getPackageName());
-                    if (change == PACKAGE_PERMANENT_CHANGE
-                            || change == PACKAGE_TEMPORARY_CHANGE) {
-                        setCurRecognizer(findAvailRecognizer(null, userHandle), userHandle);
+                    if (curRecognizer != null) {
+                        int change = isPackageDisappearing(curRecognizer.getPackageName());
+                        if (change == PACKAGE_PERMANENT_CHANGE
+                                || change == PACKAGE_TEMPORARY_CHANGE) {
+                            setCurRecognizer(findAvailRecognizer(null, userHandle), userHandle);
 
-                    } else if (isPackageModified(curRecognizer.getPackageName())) {
-                        setCurRecognizer(findAvailRecognizer(curRecognizer.getPackageName(),
-                                userHandle), userHandle);
+                        } else if (isPackageModified(curRecognizer.getPackageName())) {
+                            setCurRecognizer(findAvailRecognizer(curRecognizer.getPackageName(),
+                                    userHandle), userHandle);
+                        }
                     }
                 }
             }
         };
+
+        private Intent getContextualSearchIntent(Bundle args) {
+            String csPkgName = mContext.getResources()
+                    .getString(R.string.config_defaultContextualSearchPackageName);
+            if (csPkgName.isEmpty()) {
+                // Return null if csPackageName is not specified.
+                return null;
+            }
+            Intent launchIntent = new Intent(CS_INTENT_FILTER);
+            launchIntent.setPackage(csPkgName);
+            ResolveInfo resolveInfo = mContext.getPackageManager().resolveActivity(
+                    launchIntent, PackageManager.MATCH_FACTORY_ONLY);
+            if (resolveInfo == null) {
+                return null;
+            }
+            launchIntent.setComponent(resolveInfo.getComponentInfo().getComponentName());
+            launchIntent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NO_ANIMATION
+                    | FLAG_ACTIVITY_NO_USER_ACTION);
+            launchIntent.putExtras(args);
+            boolean isAssistDataAllowed = mAtmInternal.isAssistDataAllowed();
+            final List<ActivityAssistInfo> records = mAtmInternal.getTopVisibleActivities();
+            ArrayList<String> visiblePackageNames = new ArrayList<>();
+            boolean isManagedProfileVisible = false;
+            for (ActivityAssistInfo record: records) {
+                // Add the package name to the list only if assist data is allowed.
+                if (isAssistDataAllowed) {
+                    visiblePackageNames.add(record.getComponentName().getPackageName());
+                }
+                if (mDpmInternal.isUserOrganizationManaged(record.getUserId())) {
+                    isManagedProfileVisible = true;
+                }
+            }
+            final ScreenCapture.ScreenshotHardwareBuffer shb = mWmInternal.takeAssistScreenshot();
+            final Bitmap bm = shb != null ? shb.asBitmap() : null;
+            // Now that everything is fetched, putting it in the launchIntent.
+            if (bm != null) {
+                launchIntent.putExtra(CS_KEY_FLAG_SECURE_FOUND, shb.containsSecureLayers());
+                // Only put the screenshot if assist data is allowed
+                if (isAssistDataAllowed) {
+                    launchIntent.putExtra(CS_KEY_FLAG_SCREENSHOT, bm.asShared());
+                }
+            }
+            launchIntent.putExtra(CS_KEY_FLAG_IS_MANAGED_PROFILE_VISIBLE, isManagedProfileVisible);
+            // Only put the list of visible package names if assist data is allowed
+            if (isAssistDataAllowed) {
+                launchIntent.putExtra(CS_KEY_FLAG_VISIBLE_PACKAGE_NAMES, visiblePackageNames);
+            }
+
+            return launchIntent;
+        }
+
+        @RequiresPermission(android.Manifest.permission.START_TASKS_FROM_RECENTS)
+        private boolean startContextualSearch(Intent launchIntent) {
+            // Contextual search starts with a frozen screen - so we launch without
+            // any system animations or starting window.
+            final ActivityOptions opts = ActivityOptions.makeCustomTaskAnimation(mContext,
+                    /* enterResId= */ 0, /* exitResId= */ 0, null, null, null);
+            opts.setDisableStartingWindow(true);
+            int resultCode = mAtmInternal.startActivityWithScreenshot(launchIntent,
+                    mContext.getPackageName(), Binder.getCallingUid(), Binder.getCallingPid(), null,
+                    opts.toBundle(), Binder.getCallingUserHandle().getIdentifier());
+            return resultCode == ActivityManager.START_SUCCESS;
+        }
+
     }
 
     /**
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 08c76af..9792cdd 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -2797,13 +2797,10 @@
      * calls for a given {@code packageName} and {@code userHandle}.
      *
      * @param packageName the package name of the app to check calls for.
-     * @param userHandle the user handle on which to check for calls.
-     * @param detectForAllUsers indicates if calls should be detected across all users. If it is
-     *                          set to {@code true}, and the caller has the ability to interact
-     *                          across users, the userHandle parameter is disregarded.
+     * @param userHandle the user handle to check calls for.
      * @return {@code true} if there are ongoing calls, {@code false} otherwise.
-     * @throws SecurityException if detectForAllUsers is true or userHandle is not the calling user
-     * and the caller does not grant the ability to interact across users.
+     * @throws SecurityException if the userHandle is not the calling user and the caller does not
+     * grant the ability to interact across users.
      * @hide
      */
     @SystemApi
@@ -2811,11 +2808,45 @@
     @RequiresPermission(allOf = {Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
             Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true)
     public boolean isInSelfManagedCall(@NonNull String packageName,
-            @NonNull UserHandle userHandle, boolean detectForAllUsers) {
+            @NonNull UserHandle userHandle) {
         ITelecomService service = getTelecomService();
         if (service != null) {
             try {
                 return service.isInSelfManagedCall(packageName, userHandle,
+                        mContext.getOpPackageName(), false);
+            } catch (RemoteException e) {
+                Log.e(TAG, "RemoteException isInSelfManagedCall: " + e);
+                e.rethrowFromSystemServer();
+                return false;
+            }
+        } else {
+            throw new IllegalStateException("Telecom service is not present");
+        }
+    }
+
+    /**
+     * Determines whether there are any ongoing {@link PhoneAccount#CAPABILITY_SELF_MANAGED}
+     * calls for a given {@code packageName} amongst all users, given that detectForAllUsers is true
+     * and the caller has the ability to interact across users. If detectForAllUsers isn't enabled,
+     * the calls will be checked against the caller.
+     *
+     * @param packageName the package name of the app to check calls for.
+     * @param detectForAllUsers indicates if calls should be detected across all users.
+     * @return {@code true} if there are ongoing calls, {@code false} otherwise.
+     * @throws SecurityException if detectForAllUsers is true and the caller does not grant the
+     * ability to interact across users.
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_TELECOM_RESOLVE_HIDDEN_DEPENDENCIES)
+    @RequiresPermission(allOf = {Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+            Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true)
+    public boolean isInSelfManagedCall(@NonNull String packageName,
+            boolean detectForAllUsers) {
+        ITelecomService service = getTelecomService();
+        if (service != null) {
+            try {
+                return service.isInSelfManagedCall(packageName, null,
                         mContext.getOpPackageName(), detectForAllUsers);
             } catch (RemoteException e) {
                 Log.e(TAG, "RemoteException isInSelfManagedCall: " + e);
diff --git a/telephony/java/android/service/euicc/EuiccService.java b/telephony/java/android/service/euicc/EuiccService.java
index 5af2c34..5524541 100644
--- a/telephony/java/android/service/euicc/EuiccService.java
+++ b/telephony/java/android/service/euicc/EuiccService.java
@@ -856,10 +856,22 @@
                 int slotId, IGetAvailableMemoryInBytesCallback callback) {
             mExecutor.execute(
                     () -> {
-                        long availableMemoryInBytes =
-                                EuiccService.this.onGetAvailableMemoryInBytes(slotId);
+                        long availableMemoryInBytes = EuiccManager.EUICC_MEMORY_FIELD_UNAVAILABLE;
+                        String unsupportedOperationMessage = "";
                         try {
-                            callback.onSuccess(availableMemoryInBytes);
+                            availableMemoryInBytes =
+                                    EuiccService.this.onGetAvailableMemoryInBytes(slotId);
+                        } catch (UnsupportedOperationException e) {
+                            unsupportedOperationMessage = e.getMessage();
+                        }
+
+                        try {
+                            if (!unsupportedOperationMessage.isEmpty()) {
+                                callback.onUnsupportedOperationException(
+                                        unsupportedOperationMessage);
+                            } else {
+                                callback.onSuccess(availableMemoryInBytes);
+                            }
                         } catch (RemoteException e) {
                             // Can't communicate with the phone process; ignore.
                         }
diff --git a/telephony/java/android/service/euicc/IGetAvailableMemoryInBytesCallback.aidl b/telephony/java/android/service/euicc/IGetAvailableMemoryInBytesCallback.aidl
index bd6d19b..e550e77 100644
--- a/telephony/java/android/service/euicc/IGetAvailableMemoryInBytesCallback.aidl
+++ b/telephony/java/android/service/euicc/IGetAvailableMemoryInBytesCallback.aidl
@@ -19,4 +19,5 @@
 /** @hide */
 oneway interface IGetAvailableMemoryInBytesCallback {
     void onSuccess(long availableMemoryInBytes);
+    void onUnsupportedOperationException(String message);
 }
diff --git a/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java
index 217659e..700856c 100644
--- a/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java
+++ b/tests/CtsSurfaceControlTestsStaging/src/main/java/android/view/surfacecontroltests/GraphicsActivity.java
@@ -726,7 +726,7 @@
                                       .map(Object::toString)
                                       .collect(Collectors.joining(", ")));
             int initialNumEvents = mModeChangedEvents.size();
-            surface.setFrameRate(30.f, compatibility);
+            surface.setFrameRate(70.f, compatibility);
             verifyFrameRates(expectedFrameRates, surface);
             verifyModeSwitchesDontChangeResolution(initialNumEvents, mModeChangedEvents.size());
         });
@@ -824,7 +824,7 @@
         Display display = getDisplay();
         List<Float> expectedFrameRates = getRefreshRates(display.getMode(), display)
                                                  .stream()
-                                                 .filter(rate -> rate >= 30.f)
+                                                 .filter(rate -> rate >= 70.f)
                                                  .collect(Collectors.toList());
 
         assumeTrue("**** testSurfaceControlFrameRateCompatibility SKIPPED because no refresh rate "
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt
index 6209a08..ad39fa9 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt
@@ -17,8 +17,8 @@
 package com.android.server.wm.flicker.activityembedding
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
 import org.junit.Before
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt
index 0c36c59..46ad77e 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/close/CloseSecondaryActivityInSplitTest.kt
@@ -17,12 +17,12 @@
 package com.android.server.wm.flicker.activityembedding.close
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.Rect
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.datatypes.Rect
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
 import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt
index 955e801..af4f7a7 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/layoutchange/HorizontalSplitChangeRatioTest.kt
@@ -17,11 +17,11 @@
 package com.android.server.wm.flicker.activityembedding.layoutchange
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.Rect
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.datatypes.Rect
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt
index ce9c337..e511b72 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/MainActivityStartsSecondaryWithAlwaysExpandTest.kt
@@ -17,11 +17,11 @@
 package com.android.server.wm.flicker.activityembedding.open
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.Rect
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.datatypes.Rect
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt
index 59ff0c6..5009c7c 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingPlaceholderSplitTest.kt
@@ -17,10 +17,10 @@
 package com.android.server.wm.flicker.activityembedding.open
 
 import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
 import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt
index 3657820..000b457 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenActivityEmbeddingSecondaryToSplitTest.kt
@@ -17,11 +17,11 @@
 package com.android.server.wm.flicker.activityembedding.open
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
 import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt
index 9f9fc23..4352177 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenThirdActivityOverSplitTest.kt
@@ -17,11 +17,11 @@
 package com.android.server.wm.flicker.activityembedding.open
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.Rect
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.datatypes.Rect
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
 import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt
index 30e833f..62cf6cd 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/open/OpenTrampolineActivityTest.kt
@@ -17,12 +17,12 @@
 package com.android.server.wm.flicker.activityembedding.open
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.Rect
-import android.tools.common.flicker.subject.region.RegionSubject
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.datatypes.Rect
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.subject.region.RegionSubject
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
index c8cac8f..aa8b4ce 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/pip/SecondaryActivityEnterPipTest.kt
@@ -17,14 +17,14 @@
 package com.android.server.wm.flicker.activityembedding.pip
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.Rect
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.common.traces.component.ComponentNameMatcher.Companion.TRANSITION_SNAPSHOT
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.datatypes.Rect
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.subject.layers.LayersTraceSubject
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.component.ComponentNameMatcher.Companion.TRANSITION_SNAPSHOT
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
@@ -176,9 +176,7 @@
                 val secondaryVisibleRegion =
                     it.visibleRegion(ActivityEmbeddingAppHelper.SECONDARY_ACTIVITY_COMPONENT)
                 if (secondaryVisibleRegion.region.isNotEmpty) {
-                    check { "left" }
-                        .that(secondaryVisibleRegion.region.bounds.left)
-                        .isGreater(0)
+                    check { "left" }.that(secondaryVisibleRegion.region.bounds.left).isGreater(0)
                 }
             }
         }
@@ -217,7 +215,7 @@
         flicker.assertLayers {
             visibleLayersShownMoreThanOneConsecutiveEntry(
                 LayersTraceSubject.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS +
-                        listOf(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
+                    listOf(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
             )
         }
     }
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
index 0dce870..3d834c1 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotateSplitNoChangeTest.kt
@@ -17,11 +17,11 @@
 package com.android.server.wm.flicker.activityembedding.rotation
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
 import org.junit.FixMethodOrder
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt
index f6d51f9..511c948 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rotation/RotationTransition.kt
@@ -17,9 +17,9 @@
 package com.android.server.wm.flicker.activityembedding.rotation
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
 import com.android.server.wm.flicker.helpers.setRotation
 import org.junit.Test
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rtl/RTLStartSecondaryWithPlaceholderTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rtl/RTLStartSecondaryWithPlaceholderTest.kt
index 6be78f8..65a23e8 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rtl/RTLStartSecondaryWithPlaceholderTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/rtl/RTLStartSecondaryWithPlaceholderTest.kt
@@ -17,10 +17,10 @@
 package com.android.server.wm.flicker.activityembedding.rtl
 
 import android.platform.test.annotations.Presubmit
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
 import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
diff --git a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt
index 576eec8..7298e5f 100644
--- a/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt
+++ b/tests/FlickerTests/ActivityEmbedding/src/com/android/server/wm/flicker/activityembedding/splitscreen/EnterSystemSplitTest.kt
@@ -18,12 +18,12 @@
 
 import android.platform.test.annotations.Presubmit
 import android.platform.test.annotations.RequiresDevice
-import android.tools.common.datatypes.Rect
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.datatypes.Rect
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.parsers.toFlickerComponent
 import com.android.server.wm.flicker.activityembedding.ActivityEmbeddingTestBase
 import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
 import com.android.server.wm.flicker.testapp.ActivityOptions
diff --git a/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index 64dd44d..e19e1ce 100644
--- a/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -16,11 +16,11 @@
 
 package com.android.server.wm.flicker.close
 
-import android.tools.common.flicker.annotation.FlickerServiceCompatible
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.annotation.FlickerServiceCompatible
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import org.junit.FixMethodOrder
 import org.junit.Test
diff --git a/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
index eb256b5..47ed642 100644
--- a/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
+++ b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -16,11 +16,11 @@
 
 package com.android.server.wm.flicker.close
 
-import android.tools.common.flicker.annotation.FlickerServiceCompatible
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.annotation.FlickerServiceCompatible
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import org.junit.FixMethodOrder
 import org.junit.Test
diff --git a/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppTransition.kt b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
index ea025c7..65bc356 100644
--- a/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
+++ b/tests/FlickerTests/AppClose/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
@@ -17,12 +17,12 @@
 package com.android.server.wm.flicker.close
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.flicker.subject.layers.LayersTraceSubject.Companion.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.common.traces.component.ComponentNameMatcher.Companion.LAUNCHER
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.subject.layers.LayersTraceSubject.Companion.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.component.ComponentNameMatcher.Companion.LAUNCHER
 import androidx.test.filters.FlakyTest
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt
index 89ab41e..ffa90a3 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/ActivityTransitionTest.kt
@@ -17,12 +17,12 @@
 package com.android.server.wm.flicker.launch
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.toFlickerComponent
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.TwoActivitiesAppHelper
 import com.android.server.wm.flicker.testapp.ActivityOptions
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
index 413767c..8c285bd 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIconColdTest.kt
@@ -16,9 +16,9 @@
 
 package com.android.server.wm.flicker.launch
 
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import com.android.server.wm.flicker.launch.common.OpenAppFromIconTransition
 import org.junit.FixMethodOrder
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
index 4168bdc..d47329e 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdAfterCameraTest.kt
@@ -17,10 +17,10 @@
 package com.android.server.wm.flicker.launch
 
 import android.tools.device.apphelpers.CameraAppHelper
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import com.android.server.wm.flicker.launch.common.OpenAppFromLauncherTransition
 import org.junit.FixMethodOrder
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
index 9c55c98..267f282 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentColdTest.kt
@@ -18,12 +18,12 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.tools.common.flicker.annotation.FlickerServiceCompatible
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
+import android.tools.flicker.annotation.FlickerServiceCompatible
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.launch.common.OpenAppFromLauncherTransition
 import org.junit.FixMethodOrder
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
index fc6cdb1..83065de 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromIntentWarmTest.kt
@@ -17,11 +17,11 @@
 package com.android.server.wm.flicker.launch
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.flicker.annotation.FlickerServiceCompatible
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.annotation.FlickerServiceCompatible
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.launch.common.OpenAppFromLauncherTransition
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
index de666dd..44ae27c 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromLockscreenViaIntentTest.kt
@@ -17,13 +17,13 @@
 package com.android.server.wm.flicker.launch
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.flicker.annotation.FlickerServiceCompatible
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.annotation.FlickerServiceCompatible
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index f8a9961..6d3eaeb 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -17,12 +17,12 @@
 package com.android.server.wm.flicker.launch
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.flicker.annotation.FlickerServiceCompatible
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.flicker.annotation.FlickerServiceCompatible
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import androidx.test.filters.FlakyTest
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.launch.common.OpenAppFromLauncherTransition
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
index 0aceb35..bec02d0 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenCameraFromHomeOnDoubleClickPowerButtonTest.kt
@@ -18,15 +18,15 @@
 
 import android.os.SystemClock
 import android.platform.test.annotations.Postsubmit
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.CameraAppHelper
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.rules.RemoveAllTasksButHomeRule
+import android.tools.flicker.subject.layers.LayersTraceSubject
+import android.tools.traces.component.ComponentNameMatcher
 import android.view.KeyEvent
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.helpers.setRotation
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenTransferSplashscreenAppFromLauncherTransition.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenTransferSplashscreenAppFromLauncherTransition.kt
index f41a2a2..e0aef8d 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenTransferSplashscreenAppFromLauncherTransition.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OpenTransferSplashscreenAppFromLauncherTransition.kt
@@ -17,10 +17,10 @@
 package com.android.server.wm.flicker.launch
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.helpers.TransferSplashscreenAppHelper
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt
index 93ca41c..f114499 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt
@@ -20,15 +20,15 @@
 import android.os.Bundle
 import android.os.Handler
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.ConditionsFactory
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerBuilderProvider
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
-import android.tools.device.helpers.wakeUpAndGoToHomeScreen
+import android.tools.flicker.junit.FlickerBuilderProvider
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.rules.RemoveAllTasksButHomeRule
+import android.tools.helpers.wakeUpAndGoToHomeScreen
+import android.tools.traces.ConditionsFactory
+import android.tools.traces.component.ComponentNameMatcher
 import androidx.test.filters.RequiresDevice
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
index 3aee932..b1d78cb 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
@@ -20,20 +20,20 @@
 import android.app.WallpaperManager
 import android.content.res.Resources
 import android.platform.test.annotations.Presubmit
-import android.tools.common.datatypes.Region
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
-import android.tools.common.flicker.subject.layers.LayersTraceSubject.Companion.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.common.traces.component.ComponentNameMatcher.Companion.SPLASH_SCREEN
-import android.tools.common.traces.component.ComponentNameMatcher.Companion.WALLPAPER_BBQ_WRAPPER
-import android.tools.common.traces.component.ComponentSplashScreenMatcher
-import android.tools.common.traces.component.IComponentMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.WindowUtils
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.datatypes.Region
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.subject.layers.LayersTraceSubject
+import android.tools.flicker.subject.layers.LayersTraceSubject.Companion.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS
+import android.tools.helpers.WindowUtils
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.component.ComponentNameMatcher.Companion.SPLASH_SCREEN
+import android.tools.traces.component.ComponentNameMatcher.Companion.WALLPAPER_BBQ_WRAPPER
+import android.tools.traces.component.ComponentSplashScreenMatcher
+import android.tools.traces.component.IComponentMatcher
+import android.tools.traces.parsers.toFlickerComponent
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.BaseTest
@@ -215,9 +215,10 @@
             component: IComponentMatcher,
             expectedArea: Region,
             isOptional: Boolean = true
-        ): LayersTraceSubject = invoke("$component coversExactly $expectedArea", isOptional) {
-            it.visibleRegion(component).coversExactly(expectedArea)
-        }
+        ): LayersTraceSubject =
+            invoke("$component coversExactly $expectedArea", isOptional) {
+                it.visibleRegion(component).coversExactly(expectedArea)
+            }
 
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt
index 802c755..8a3304b 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromIconTransition.kt
@@ -16,10 +16,10 @@
 
 package com.android.server.wm.flicker.launch.common
 
-import android.tools.common.Rotation
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
+import android.tools.Rotation
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.rules.RemoveAllTasksButHomeRule
 
 abstract class OpenAppFromIconTransition(flicker: LegacyFlickerTest) :
     OpenAppFromLauncherTransition(flicker) {
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLauncherTransition.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLauncherTransition.kt
index 9d7096e..b56e9a5 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLauncherTransition.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLauncherTransition.kt
@@ -17,8 +17,8 @@
 package com.android.server.wm.flicker.launch.common
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.replacesLayer
 import org.junit.Test
 
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLockscreenTransition.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLockscreenTransition.kt
index 7b08843..f8fd3586 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLockscreenTransition.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppFromLockscreenTransition.kt
@@ -17,9 +17,9 @@
 package com.android.server.wm.flicker.launch.common
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.traces.component.ComponentNameMatcher
 import androidx.test.filters.FlakyTest
 import com.android.server.wm.flicker.navBarLayerPositionAtEnd
 import com.android.server.wm.flicker.statusBarLayerPositionAtEnd
diff --git a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppTransition.kt b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppTransition.kt
index 989619e..7ca336d 100644
--- a/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppTransition.kt
+++ b/tests/FlickerTests/AppLaunch/src/com/android/server/wm/flicker/launch/common/OpenAppTransition.kt
@@ -17,11 +17,11 @@
 package com.android.server.wm.flicker.launch.common
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.helpers.wakeUpAndGoToHomeScreen
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.helpers.wakeUpAndGoToHomeScreen
+import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import com.android.server.wm.flicker.helpers.setRotation
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/Utils.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/Utils.kt
index 8242e9a..8a241de 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/Utils.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/Utils.kt
@@ -20,12 +20,12 @@
 import android.platform.test.rule.NavigationModeRule
 import android.platform.test.rule.PressHomeRule
 import android.platform.test.rule.UnlockScreenRule
-import android.tools.common.NavBar
-import android.tools.common.Rotation
+import android.tools.NavBar
+import android.tools.Rotation
 import android.tools.device.apphelpers.MessagingAppHelper
-import android.tools.device.flicker.rules.ChangeDisplayOrientationRule
-import android.tools.device.flicker.rules.LaunchAppRule
-import android.tools.device.flicker.rules.RemoveAllTasksButHomeRule
+import android.tools.flicker.rules.ChangeDisplayOrientationRule
+import android.tools.flicker.rules.LaunchAppRule
+import android.tools.flicker.rules.RemoveAllTasksButHomeRule
 import androidx.test.platform.app.InstrumentationRegistry
 import org.junit.rules.RuleChain
 
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonLandscape.kt
index b3c9c96..8040610 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonLandscape.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.close.flicker
 
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.close.scenarios.CloseAppBackButton
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonPortrait.kt
index 29c11a4..aacccf4 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButton3ButtonPortrait.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.close.flicker
 
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.close.scenarios.CloseAppBackButton
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavLandscape.kt
index 1bb4a25..74ee460 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavLandscape.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.close.flicker
 
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.close.scenarios.CloseAppBackButton
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavPortrait.kt
index 17cb6e1..57463c3 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppBackButtonGesturalNavPortrait.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.close.flicker
 
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.close.scenarios.CloseAppBackButton
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonLandscape.kt
index 47c2529..3d5f0f2 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonLandscape.kt
@@ -16,13 +16,13 @@
 
 package com.android.server.wm.flicker.service.close.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.close.scenarios.CloseAppHomeButton
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonPortrait.kt
index b18148f..055cc72 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppHomeButton3ButtonPortrait.kt
@@ -16,13 +16,13 @@
 
 package com.android.server.wm.flicker.service.close.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.close.scenarios.CloseAppHomeButton
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavLandscape.kt
index 8543015..3877981 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 package com.android.server.wm.flicker.service.close.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.close.scenarios.CloseAppSwipeToHome
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavPortrait.kt
index f88963b..ef7755e 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/flicker/CloseAppSwipeToHomeGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 package com.android.server.wm.flicker.service.close.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.close.scenarios.CloseAppSwipeToHome
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppBackButton.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppBackButton.kt
index 2aaacde..17de268 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppBackButton.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppBackButton.kt
@@ -17,9 +17,9 @@
 package com.android.server.wm.flicker.service.close.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.tapl.LauncherInstrumentation
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppHomeButton.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppHomeButton.kt
index 08683a3..d8a88d4 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppHomeButton.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppHomeButton.kt
@@ -17,9 +17,9 @@
 package com.android.server.wm.flicker.service.close.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.tapl.LauncherInstrumentation
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppSwipeToHome.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppSwipeToHome.kt
index 360e114..f32f5ba 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppSwipeToHome.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/close/scenarios/CloseAppSwipeToHome.kt
@@ -17,9 +17,9 @@
 package com.android.server.wm.flicker.service.close.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.tapl.LauncherInstrumentation
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavLandscape.kt
index bb18770..8b08750 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavLandscape.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationCold
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavPortrait.kt
index 1c3cc21..cc7fe4d 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationCold3ButtonNavPortrait.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationCold
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavLandscape.kt
index 46d36db..f6414ca 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavLandscape.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationCold
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavPortrait.kt
index f6a668fe..4244900 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationColdGesturalNavPortrait.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationCold
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavLandscape.kt
index 93200ba..548acbe0 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavLandscape.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWarm
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavPortrait.kt
index f5d41d2..b231dd3 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarm3ButtonNavPortrait.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWarm
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavLandscape.kt
index 28f322b..14f680a 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavLandscape.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWarm
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavPortrait.kt
index beb3fae..6e07174 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWarmGesturalNavPortrait.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWarm
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavLandscape.kt
index 4adcc8b..de71b9a 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavLandscape.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWithOverlayApp
 import org.junit.Ignore
 import org.junit.Test
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavPortrait.kt
index f7211e7..714d5e8a 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayApp3ButtonNavPortrait.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWithOverlayApp
 import org.junit.Ignore
 import org.junit.Test
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavLandscape.kt
index 1ade956..4c1bae7 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavLandscape.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWithOverlayApp
 import org.junit.Ignore
 import org.junit.Test
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavPortrait.kt
index ea26f08..0321f77 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromLockscreenNotificationWithOverlayAppGesturalNavPortrait.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromLockscreenNotificationWithOverlayApp
 import org.junit.Ignore
 import org.junit.Test
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavLandscape.kt
index 866190f..e3b434d 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavLandscape.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationCold
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavPortrait.kt
index a8d6283..64bce2e 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationCold3ButtonNavPortrait.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationCold
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavLandscape.kt
index ef84c3f..83241bf 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavLandscape.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationCold
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavPortrait.kt
index 5bb6b37..06b89d3 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationColdGesturalNavPortrait.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationCold
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavLandscape.kt
index 39f25e9..8d3cf90 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavLandscape.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationWarm
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavPortrait.kt
index 28816bc..0d0adf2 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarm3ButtonNavPortrait.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationWarm
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavLandscape.kt
index 94ffe4e..1fbaddb 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavLandscape.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationWarm
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavPortrait.kt
index e5f5ec4..52df4bd 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/flicker/OpenAppFromNotificationWarmGesturalNavPortrait.kt
@@ -16,14 +16,14 @@
 
 package com.android.server.wm.flicker.service.notification.flicker
 
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.notification.scenarios.OpenAppFromNotificationWarm
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/NotificationUtils.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/NotificationUtils.kt
index ac4e169..79d6bb7 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/NotificationUtils.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/NotificationUtils.kt
@@ -17,7 +17,7 @@
 package com.android.server.wm.flicker.service.notification.scenarios
 
 import android.app.Instrumentation
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.traces.parsers.WindowManagerStateHelper
 import android.view.WindowInsets
 import android.view.WindowManager
 import androidx.test.platform.app.InstrumentationRegistry
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationCold.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationCold.kt
index 9c53ab3..e702f12 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationCold.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationCold.kt
@@ -17,10 +17,10 @@
 package com.android.server.wm.flicker.service.notification.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.helpers.wakeUpAndGoToHomeScreen
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.helpers.wakeUpAndGoToHomeScreen
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWarm.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWarm.kt
index 31f55d9..0a509f8 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWarm.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWarm.kt
@@ -17,10 +17,10 @@
 package com.android.server.wm.flicker.service.notification.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.helpers.wakeUpAndGoToHomeScreen
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.helpers.wakeUpAndGoToHomeScreen
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWithOverlayApp.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWithOverlayApp.kt
index b971555..ce6ee2f 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWithOverlayApp.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromLockscreenNotificationWithOverlayApp.kt
@@ -17,10 +17,10 @@
 package com.android.server.wm.flicker.service.notification.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.helpers.wakeUpAndGoToHomeScreen
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.helpers.wakeUpAndGoToHomeScreen
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationCold.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationCold.kt
index fed077e..e1cf322 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationCold.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationCold.kt
@@ -17,10 +17,10 @@
 package com.android.server.wm.flicker.service.notification.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.helpers.wakeUpAndGoToHomeScreen
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.helpers.wakeUpAndGoToHomeScreen
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationWarm.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationWarm.kt
index 403790e..4dd84bd 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationWarm.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/notification/scenarios/OpenAppFromNotificationWarm.kt
@@ -17,10 +17,10 @@
 package com.android.server.wm.flicker.service.notification.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.helpers.wakeUpAndGoToHomeScreen
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.helpers.wakeUpAndGoToHomeScreen
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavLandscape.kt
index d611a42..da9f4bb 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 package com.android.server.wm.flicker.service.quickswitch.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.quickswitch.scenarios.QuickSwitchBetweenTwoAppsBack
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavPortrait.kt
index e6bcbba..f3ae920 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsBackGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 package com.android.server.wm.flicker.service.quickswitch.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.quickswitch.scenarios.QuickSwitchBetweenTwoAppsBack
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavLandscape.kt
index 2a26d63..a26906c 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 package com.android.server.wm.flicker.service.quickswitch.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.quickswitch.scenarios.QuickSwitchBetweenTwoAppsForward
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavPortrait.kt
index 5ce7143..01def0e 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchBetweenTwoAppsForwardGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 package com.android.server.wm.flicker.service.quickswitch.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.quickswitch.scenarios.QuickSwitchBetweenTwoAppsForward
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavLandscape.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavLandscape.kt
index cff47bb..3f40e56 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavLandscape.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavLandscape.kt
@@ -16,13 +16,13 @@
 
 package com.android.server.wm.flicker.service.quickswitch.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.quickswitch.scenarios.QuickSwitchFromLauncher
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavPortrait.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavPortrait.kt
index 33095a6..70a95fe 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavPortrait.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/flicker/QuickSwitchFromLauncherGesturalNavPortrait.kt
@@ -16,13 +16,13 @@
 
 package com.android.server.wm.flicker.service.quickswitch.flicker
 
-import android.tools.common.Rotation
-import android.tools.common.flicker.FlickerConfig
-import android.tools.common.flicker.annotation.ExpectedScenarios
-import android.tools.common.flicker.annotation.FlickerConfigProvider
-import android.tools.common.flicker.config.FlickerConfig
-import android.tools.common.flicker.config.FlickerServiceConfig
-import android.tools.device.flicker.junit.FlickerServiceJUnit4ClassRunner
+import android.tools.Rotation
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
 import com.android.server.wm.flicker.service.quickswitch.scenarios.QuickSwitchFromLauncher
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsBack.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsBack.kt
index a1708fe..f0df37a 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsBack.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsBack.kt
@@ -17,10 +17,10 @@
 package com.android.server.wm.flicker.service.quickswitch.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.flicker.rules.ChangeDisplayOrientationRule
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.rules.ChangeDisplayOrientationRule
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.tapl.LauncherInstrumentation
 import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsForward.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsForward.kt
index fcf442a..a22bdce 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsForward.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchBetweenTwoAppsForward.kt
@@ -17,10 +17,10 @@
 package com.android.server.wm.flicker.service.quickswitch.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.flicker.rules.ChangeDisplayOrientationRule
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.rules.ChangeDisplayOrientationRule
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.tapl.LauncherInstrumentation
 import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
diff --git a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchFromLauncher.kt b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchFromLauncher.kt
index 7afe526..e5aa181 100644
--- a/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchFromLauncher.kt
+++ b/tests/FlickerTests/FlickerService/src/com/android/server/wm/flicker/service/quickswitch/scenarios/QuickSwitchFromLauncher.kt
@@ -17,9 +17,9 @@
 package com.android.server.wm.flicker.service.quickswitch.scenarios
 
 import android.app.Instrumentation
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.tapl.LauncherInstrumentation
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
index 99e8ef5..7e486ab 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnDismissPopupDialogTest.kt
@@ -17,13 +17,13 @@
 package com.android.server.wm.flicker.ime
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.flicker.subject.region.RegionSubject
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.subject.region.RegionSubject
+import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.ImeEditorPopupDialogAppHelper
 import org.junit.FixMethodOrder
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt
index 48c54ea..2f3ec63 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeOnGoHomeTest.kt
@@ -18,12 +18,12 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.ImeAppHelper
 import org.junit.FixMethodOrder
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt
index 31d5d7f..8821b69 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartOnGoHomeTest.kt
@@ -17,12 +17,12 @@
 package com.android.server.wm.flicker.ime
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
 import org.junit.FixMethodOrder
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt
index 180ae5d..d75eba6 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeShownOnAppStartToAppOnPressBackTest.kt
@@ -17,12 +17,12 @@
 package com.android.server.wm.flicker.ime
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
 import org.junit.FixMethodOrder
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
index a0573b7..41d9e30 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToAppOnPressBackTest.kt
@@ -18,11 +18,11 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.ImeAppHelper
 import com.android.server.wm.flicker.navBarLayerPositionAtStartAndEnd
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt
index be47ec7..0e7fb79 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/CloseImeToHomeOnFinishActivityTest.kt
@@ -18,13 +18,13 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.flicker.subject.layers.LayersTraceSubject.Companion.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.subject.layers.LayersTraceSubject.Companion.VISIBLE_FOR_MORE_THAN_ONE_ENTRY_IGNORE_LAYERS
+import android.tools.traces.parsers.toFlickerComponent
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.ImeAppHelper
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
index 994edc5..47a7e1b 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/OpenImeWindowToFixedPortraitAppTest.kt
@@ -16,15 +16,15 @@
 package com.android.server.wm.flicker.ime
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.flicker.subject.region.RegionSubject
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.WindowUtils
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.subject.region.RegionSubject
+import android.tools.helpers.WindowUtils
+import android.tools.traces.component.ComponentNameMatcher
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt
index ea7c7c4..e8249bc 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromFixedOrientationTest.kt
@@ -18,13 +18,13 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.flicker.subject.layers.LayerTraceEntrySubject
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.subject.layers.LayerTraceEntrySubject
+import android.tools.traces.component.ComponentNameMatcher
 import androidx.test.filters.FlakyTest
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
index b7a183d..617237d 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromOverviewTest.kt
@@ -17,12 +17,12 @@
 package com.android.server.wm.flicker.ime
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
 import com.android.server.wm.flicker.helpers.setRotation
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
index 6ee5a9a..7b62c89 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppFromQuickSwitchTest.kt
@@ -17,13 +17,13 @@
 package com.android.server.wm.flicker.ime
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
index 1ad5c0d..53bfb4e 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeOnAppStartWhenLaunchingAppTest.kt
@@ -17,12 +17,12 @@
 package com.android.server.wm.flicker.ime
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
 import com.android.server.wm.flicker.helpers.ImeStateInitializeHelper
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt
index 918e1ea..12290af 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhenFocusingOnInputFieldTest.kt
@@ -18,11 +18,11 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.ImeAppHelper
 import org.junit.FixMethodOrder
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
index 181a2a2..0948351 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileDismissingThemedPopupDialogTest.kt
@@ -17,13 +17,13 @@
 package com.android.server.wm.flicker.ime
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.Rotation
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.toFlickerComponent
 import android.view.WindowInsets.Type.ime
 import android.view.WindowInsets.Type.navigationBars
 import android.view.WindowInsets.Type.statusBars
@@ -55,10 +55,12 @@
             testApp.launchViaIntent(wmHelper)
             testApp.waitIMEShown(wmHelper)
             broadcastActionTrigger.doAction(ACTION_START_DIALOG_THEMED_ACTIVITY)
-            wmHelper.StateSyncBuilder()
-                    .withFullScreenApp(
-                        ActivityOptions.DialogThemedActivity.COMPONENT.toFlickerComponent())
-                    .waitForAndVerify()
+            wmHelper
+                .StateSyncBuilder()
+                .withFullScreenApp(
+                    ActivityOptions.DialogThemedActivity.COMPONENT.toFlickerComponent()
+                )
+                .waitForAndVerify()
             // Verify IME insets isn't visible on dialog since it's non-IME focusable window
             assertFalse(testApp.getInsetsVisibleFromDialog(ime()))
             assertTrue(testApp.getInsetsVisibleFromDialog(statusBars()))
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt
index f1bc125..a14dc62 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/ShowImeWhileEnteringOverviewTest.kt
@@ -17,13 +17,13 @@
 package com.android.server.wm.flicker.ime
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.ConditionsFactory
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.traces.parsers.WindowManagerStateHelper
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.ConditionsFactory
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.WindowManagerStateHelper
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.ImeShownOnAppStartHelper
 import com.android.server.wm.flicker.navBarLayerIsVisibleAtStartAndEnd
diff --git a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/common/CommonAssertions.kt b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/common/CommonAssertions.kt
index 777231e..bd3d1ce 100644
--- a/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/common/CommonAssertions.kt
+++ b/tests/FlickerTests/IME/src/com/android/server/wm/flicker/ime/common/CommonAssertions.kt
@@ -18,8 +18,8 @@
 
 package com.android.server.wm.flicker.ime
 
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.traces.component.ComponentNameMatcher
 
 fun LegacyFlickerTest.imeLayerBecomesVisible() {
     assertLayers {
diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/Consts.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/Consts.kt
index b81439e..edcee46 100644
--- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/Consts.kt
+++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/Consts.kt
@@ -16,7 +16,7 @@
 
 package com.android.server.wm.flicker.notification
 
-import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.traces.component.ComponentNameMatcher
 
 object Consts {
     val IMAGE_WALLPAPER = ComponentNameMatcher("", "com.android.systemui.wallpapers.ImageWallpaper")
diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt
index 620502e..ffaeead 100644
--- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt
+++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationColdTest.kt
@@ -20,12 +20,12 @@
 import android.platform.test.annotations.Presubmit
 import android.platform.test.rule.SettingOverrideRule
 import android.provider.Settings
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.wakeUpAndGoToHomeScreen
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.helpers.wakeUpAndGoToHomeScreen
+import android.tools.traces.component.ComponentNameMatcher
 import androidx.test.filters.RequiresDevice
 import org.junit.ClassRule
 import org.junit.FixMethodOrder
diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt
index 2a458ef8..6e67e19 100644
--- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt
+++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWarmTest.kt
@@ -19,11 +19,11 @@
 import android.platform.test.annotations.Presubmit
 import android.platform.test.rule.SettingOverrideRule
 import android.provider.Settings
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.statusBarLayerPositionAtEnd
diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt
index 00aad27..8e210d4 100644
--- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt
+++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromLockscreenNotificationWithOverlayAppTest.kt
@@ -18,12 +18,12 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.wakeUpAndGoToHomeScreen
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.helpers.wakeUpAndGoToHomeScreen
+import android.tools.traces.component.ComponentNameMatcher
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.helpers.ShowWhenLockedAppHelper
diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt
index f8d78b5..b6d09d0 100644
--- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt
+++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationColdTest.kt
@@ -18,12 +18,12 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.wakeUpAndGoToHomeScreen
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.helpers.wakeUpAndGoToHomeScreen
+import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.statusBarLayerPositionAtEnd
 import org.junit.FixMethodOrder
diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt
index 5c7ec46..1e607bf 100644
--- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt
+++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppFromNotificationWarmTest.kt
@@ -18,13 +18,13 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.FlickerTestData
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.device.helpers.wakeUpAndGoToHomeScreen
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.FlickerTestData
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.helpers.wakeUpAndGoToHomeScreen
+import android.tools.traces.component.ComponentNameMatcher
 import android.view.WindowInsets
 import android.view.WindowManager
 import androidx.test.uiautomator.By
diff --git a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppTransition.kt b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppTransition.kt
index 4e0e3c0..4ba444b 100644
--- a/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppTransition.kt
+++ b/tests/FlickerTests/Notification/src/com/android/server/wm/flicker/notification/OpenAppTransition.kt
@@ -17,9 +17,9 @@
 package com.android.server.wm.flicker.notification
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import org.junit.Test
diff --git a/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
index 13fcc2b..8b09b59 100644
--- a/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
+++ b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
@@ -17,13 +17,13 @@
 package com.android.server.wm.flicker.quickswitch
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
-import android.tools.common.datatypes.Rect
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.datatypes.Rect
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import androidx.test.filters.FlakyTest
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
diff --git a/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
index badd7c8..c54ddcf 100644
--- a/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
+++ b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
@@ -16,13 +16,13 @@
 
 package com.android.server.wm.flicker.quickswitch
 
-import android.tools.common.NavBar
-import android.tools.common.datatypes.Rect
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.datatypes.Rect
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import androidx.test.filters.FlakyTest
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
diff --git a/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
index f51be90..69a84a0 100644
--- a/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
+++ b/tests/FlickerTests/QuickSwitch/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
@@ -17,14 +17,14 @@
 package com.android.server.wm.flicker.quickswitch
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.NavBar
-import android.tools.common.Rotation
-import android.tools.common.datatypes.Rect
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.datatypes.Rect
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import androidx.test.filters.FlakyTest
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
diff --git a/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index bdbf0d2..05ab364 100644
--- a/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -18,11 +18,11 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import org.junit.FixMethodOrder
 import org.junit.Test
diff --git a/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/RotationTransition.kt b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
index 79d3a10..c7da778 100644
--- a/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
+++ b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
@@ -17,13 +17,13 @@
 package com.android.server.wm.flicker.rotation
 
 import android.platform.test.annotations.Presubmit
-import android.tools.common.flicker.subject.layers.LayerTraceEntrySubject
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.common.traces.component.IComponentMatcher
-import android.tools.common.traces.surfaceflinger.Display
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.subject.layers.LayerTraceEntrySubject
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.component.IComponentMatcher
+import android.tools.traces.surfaceflinger.Display
 import com.android.server.wm.flicker.BaseTest
 import com.android.server.wm.flicker.helpers.setRotation
 import org.junit.Test
@@ -76,9 +76,9 @@
     }
 
     private fun LayerTraceEntrySubject.getDisplay(componentMatcher: IComponentMatcher): Display {
-        val stackId = this.layer {
-            componentMatcher.layerMatchesAnyOf(it) && it.isVisible
-        }?.layer?.stackId ?: -1
+        val stackId =
+            this.layer { componentMatcher.layerMatchesAnyOf(it) && it.isVisible }?.layer?.stackId
+                ?: -1
 
         return this.entry.displays.firstOrNull { it.layerStackId == stackId }
             ?: error("Unable to find visible layer for $componentMatcher")
diff --git a/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index 6d3ae43..a413628 100644
--- a/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -18,13 +18,13 @@
 
 import android.platform.test.annotations.PlatinumTest
 import android.platform.test.annotations.Presubmit
-import android.tools.common.ScenarioBuilder
-import android.tools.common.ScenarioImpl
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerParametersRunnerFactory
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.ScenarioBuilder
+import android.tools.ScenarioImpl
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.legacy.LegacyFlickerTestFactory
+import android.tools.traces.component.ComponentNameMatcher
 import android.view.WindowManager
 import com.android.server.wm.flicker.helpers.SeamlessRotationAppHelper
 import com.android.server.wm.flicker.testapp.ActivityOptions
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt
index ce92eac..17f91eb 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt
@@ -19,10 +19,10 @@
 import android.app.Instrumentation
 import android.content.Intent
 import android.platform.test.annotations.Presubmit
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.flicker.junit.FlickerBuilderProvider
-import android.tools.device.flicker.legacy.FlickerBuilder
-import android.tools.device.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.junit.FlickerBuilderProvider
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.traces.component.ComponentNameMatcher
 import android.util.Log
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.tapl.LauncherInstrumentation
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
index 1abb8c2..8853c1d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -18,15 +18,15 @@
 
 package com.android.server.wm.flicker
 
-import android.tools.common.PlatformConsts
-import android.tools.common.Position
-import android.tools.common.flicker.subject.layers.LayerTraceEntrySubject
-import android.tools.common.flicker.subject.region.RegionSubject
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.common.traces.component.IComponentNameMatcher
-import android.tools.common.traces.wm.WindowManagerTrace
-import android.tools.device.flicker.legacy.LegacyFlickerTest
-import android.tools.device.helpers.WindowUtils
+import android.tools.PlatformConsts
+import android.tools.Position
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.flicker.subject.layers.LayerTraceEntrySubject
+import android.tools.flicker.subject.region.RegionSubject
+import android.tools.helpers.WindowUtils
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.component.IComponentNameMatcher
+import android.tools.traces.wm.WindowManagerTrace
 
 /**
  * Checks that [ComponentNameMatcher.STATUS_BAR] window is visible and above the app windows in all
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
index 11e6bbe..4a675be 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
@@ -17,12 +17,12 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.PlatformConsts
-import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.PlatformConsts
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.helpers.FIND_TIMEOUT
-import android.tools.device.traces.parsers.WindowManagerStateHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.helpers.FIND_TIMEOUT
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.WindowManagerStateHelper
+import android.tools.traces.parsers.toFlickerComponent
 import android.util.Log
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Until
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AppPairsHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AppPairsHelper.kt
index 94ac1a6..ec661d7 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AppPairsHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AppPairsHelper.kt
@@ -17,8 +17,8 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
+import android.tools.traces.component.ComponentNameMatcher
 
 class AppPairsHelper(
     instrumentation: Instrumentation,
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt
index fde0981..5333725 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt
@@ -19,7 +19,7 @@
 import android.app.Instrumentation
 import android.content.ComponentName
 import android.provider.Settings
-import android.tools.device.helpers.FIND_TIMEOUT
+import android.tools.helpers.FIND_TIMEOUT
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.UiDevice
 import androidx.test.uiautomator.Until
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt
index c6fa1bb..1915225 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt
@@ -17,9 +17,9 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.toFlickerComponent
 import com.android.server.wm.flicker.testapp.ActivityOptions
 
 class FixedOrientationAppHelper
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
index 5c8cbe4..926209f 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
@@ -18,9 +18,9 @@
 
 package com.android.server.wm.flicker.helpers
 
-import android.tools.common.Rotation
-import android.tools.device.flicker.legacy.FlickerTestData
-import android.tools.device.flicker.rules.ChangeDisplayOrientationRule
+import android.tools.Rotation
+import android.tools.flicker.legacy.FlickerTestData
+import android.tools.flicker.rules.ChangeDisplayOrientationRule
 
 /**
  * Changes the device [rotation] and wait for the rotation animation to complete
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
index 3146139..0c60f28 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
@@ -17,10 +17,10 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.traces.parsers.WindowManagerStateHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.WindowManagerStateHelper
+import android.tools.traces.parsers.toFlickerComponent
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Direction
 import androidx.test.uiautomator.Until
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
index cb1aab0..495fbce 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
@@ -17,11 +17,11 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.helpers.FIND_TIMEOUT
-import android.tools.device.traces.parsers.WindowManagerStateHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.helpers.FIND_TIMEOUT
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.WindowManagerStateHelper
+import android.tools.traces.parsers.toFlickerComponent
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Until
 import com.android.server.wm.flicker.testapp.ActivityOptions
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt
index 7a8d780..6fe7c29 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeEditorPopupDialogAppHelper.kt
@@ -17,10 +17,10 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.device.helpers.FIND_TIMEOUT
-import android.tools.device.traces.parsers.WindowManagerStateHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.helpers.FIND_TIMEOUT
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.WindowManagerStateHelper
+import android.tools.traces.parsers.toFlickerComponent
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Until
 import com.android.server.wm.flicker.testapp.ActivityOptions
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt
index 0ee7aee..f5c88e3 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeShownOnAppStartHelper.kt
@@ -17,13 +17,13 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.Rotation
-import android.tools.common.traces.component.ComponentNameMatcher
-import android.tools.common.traces.component.IComponentMatcher
-import android.tools.device.helpers.FIND_TIMEOUT
-import android.tools.device.helpers.IME_PACKAGE
-import android.tools.device.traces.parsers.WindowManagerStateHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.Rotation
+import android.tools.helpers.FIND_TIMEOUT
+import android.tools.helpers.IME_PACKAGE
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.component.IComponentMatcher
+import android.tools.traces.parsers.WindowManagerStateHelper
+import android.tools.traces.parsers.toFlickerComponent
 import android.view.WindowInsets.Type.ime
 import android.view.WindowInsets.Type.navigationBars
 import android.view.WindowInsets.Type.statusBars
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt
index b2aeb14..db93bf7 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt
@@ -17,9 +17,9 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.toFlickerComponent
 import com.android.server.wm.flicker.testapp.ActivityOptions
 
 class ImeStateInitializeHelper
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LaunchBubbleHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LaunchBubbleHelper.kt
index b95d86b..d6ead85 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LaunchBubbleHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LaunchBubbleHelper.kt
@@ -18,7 +18,7 @@
 
 import android.app.Instrumentation
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.traces.parsers.toFlickerComponent
 import com.android.server.wm.flicker.testapp.ActivityOptions
 
 class LaunchBubbleHelper(instrumentation: Instrumentation) :
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
index 9b539c8..b09e53b 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/LetterboxAppHelper.kt
@@ -17,14 +17,14 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.datatypes.Rect
-import android.tools.common.datatypes.Region
-import android.tools.common.traces.component.ComponentNameMatcher
+import android.tools.datatypes.Rect
+import android.tools.datatypes.Region
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.helpers.FIND_TIMEOUT
-import android.tools.device.helpers.SYSTEMUI_PACKAGE
-import android.tools.device.traces.parsers.WindowManagerStateHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.helpers.FIND_TIMEOUT
+import android.tools.helpers.SYSTEMUI_PACKAGE
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.WindowManagerStateHelper
+import android.tools.traces.parsers.toFlickerComponent
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Until
 import com.android.server.wm.flicker.testapp.ActivityOptions
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt
index 9895bda..d4075e9 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt
@@ -17,10 +17,10 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.helpers.FIND_TIMEOUT
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.helpers.FIND_TIMEOUT
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.toFlickerComponent
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Direction
 import androidx.test.uiautomator.UiObject2
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MultiWindowUtils.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MultiWindowUtils.kt
index 65175ef..29c1cde 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MultiWindowUtils.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/MultiWindowUtils.kt
@@ -19,8 +19,8 @@
 import android.app.Instrumentation
 import android.content.Context
 import android.provider.Settings
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
+import android.tools.traces.component.ComponentNameMatcher
 import android.util.Log
 import com.android.compatibility.common.util.SystemUtil
 import java.io.IOException
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt
index b2f8d47..ea4ea0a 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt
@@ -17,11 +17,11 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.helpers.FIND_TIMEOUT
-import android.tools.device.traces.parsers.WindowManagerStateHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.helpers.FIND_TIMEOUT
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.WindowManagerStateHelper
+import android.tools.traces.parsers.toFlickerComponent
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.UiDevice
 import androidx.test.uiautomator.Until
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt
index ee65004..ebf3487 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt
@@ -17,9 +17,9 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.toFlickerComponent
 import com.android.server.wm.flicker.testapp.ActivityOptions
 
 class NonResizeableAppHelper
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt
index e60c20d..c559d0f 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt
@@ -17,11 +17,11 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.helpers.FIND_TIMEOUT
-import android.tools.device.traces.parsers.WindowManagerStateHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.helpers.FIND_TIMEOUT
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.WindowManagerStateHelper
+import android.tools.traces.parsers.toFlickerComponent
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Until
 import com.android.server.wm.flicker.testapp.ActivityOptions
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
index 452c98c..db933b3 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
@@ -20,15 +20,15 @@
 import android.content.Intent
 import android.media.session.MediaController
 import android.media.session.MediaSessionManager
-import android.tools.common.datatypes.Rect
-import android.tools.common.datatypes.Region
-import android.tools.common.traces.ConditionsFactory
-import android.tools.common.traces.component.IComponentMatcher
+import android.tools.datatypes.Rect
+import android.tools.datatypes.Region
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.helpers.FIND_TIMEOUT
-import android.tools.device.helpers.SYSTEMUI_PACKAGE
-import android.tools.device.traces.parsers.WindowManagerStateHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.helpers.FIND_TIMEOUT
+import android.tools.helpers.SYSTEMUI_PACKAGE
+import android.tools.traces.ConditionsFactory
+import android.tools.traces.component.IComponentMatcher
+import android.tools.traces.parsers.WindowManagerStateHelper
+import android.tools.traces.parsers.toFlickerComponent
 import android.util.Log
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Until
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt
index cac3530..55d43e6 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt
@@ -17,9 +17,9 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.toFlickerComponent
 import com.android.server.wm.flicker.testapp.ActivityOptions
 
 class SeamlessRotationAppHelper
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt
index 8366a7a..05856cc 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt
@@ -17,9 +17,9 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.toFlickerComponent
 import com.android.server.wm.flicker.testapp.ActivityOptions
 
 class ShowWhenLockedAppHelper
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt
index 89c6c35..82ef398 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt
@@ -17,9 +17,9 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.toFlickerComponent
 import com.android.server.wm.flicker.testapp.ActivityOptions
 
 class SimpleAppHelper
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TransferSplashscreenAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TransferSplashscreenAppHelper.kt
index 6311678..ffe077e 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TransferSplashscreenAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TransferSplashscreenAppHelper.kt
@@ -17,9 +17,9 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.toFlickerComponent
 import com.android.server.wm.flicker.testapp.ActivityOptions
 
 class TransferSplashscreenAppHelper
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
index 8be5769..867bcb6 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
@@ -17,11 +17,11 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.tools.common.traces.component.ComponentNameMatcher
 import android.tools.device.apphelpers.StandardAppHelper
-import android.tools.device.helpers.FIND_TIMEOUT
-import android.tools.device.traces.parsers.WindowManagerStateHelper
-import android.tools.device.traces.parsers.toFlickerComponent
+import android.tools.helpers.FIND_TIMEOUT
+import android.tools.traces.component.ComponentNameMatcher
+import android.tools.traces.parsers.WindowManagerStateHelper
+import android.tools.traces.parsers.toFlickerComponent
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.UiDevice
 import androidx.test.uiautomator.Until
diff --git a/tests/Internal/Android.bp b/tests/Internal/Android.bp
index a487799..827ff4f 100644
--- a/tests/Internal/Android.bp
+++ b/tests/Internal/Android.bp
@@ -21,6 +21,9 @@
         "mockito-target-minus-junit4",
         "truth",
         "platform-test-annotations",
+        "flickerlib-parsers",
+        "perfetto_trace_java_protos",
+        "flickerlib-trace_processor_shell",
     ],
     java_resource_dirs: ["res"],
     certificate: "platform",
diff --git a/tests/Internal/AndroidManifest.xml b/tests/Internal/AndroidManifest.xml
index dbba245..9a3fe61 100644
--- a/tests/Internal/AndroidManifest.xml
+++ b/tests/Internal/AndroidManifest.xml
@@ -19,7 +19,11 @@
      package="com.android.internal.tests">
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.BIND_WALLPAPER"/>
-    <application>
+    <!-- Allow the test to connect to perfetto trace processor -->
+    <uses-permission android:name="android.permission.INTERNET"/>
+    <application
+        android:requestLegacyExternalStorage="true"
+        android:networkSecurityConfig="@xml/network_security_config">
         <uses-library android:name="android.test.runner"/>
 
         <service android:name="stub.DummyWallpaperService"
diff --git a/tests/Internal/res/xml/network_security_config.xml b/tests/Internal/res/xml/network_security_config.xml
new file mode 100644
index 0000000..fdf1dbb
--- /dev/null
+++ b/tests/Internal/res/xml/network_security_config.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 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.
+  -->
+<network-security-config>
+    <domain-config cleartextTrafficPermitted="true">
+        <domain includeSubdomains="true">localhost</domain>
+    </domain-config>
+</network-security-config>
diff --git a/tests/Internal/src/com/android/internal/protolog/LegacyProtoLogImplTest.java b/tests/Internal/src/com/android/internal/protolog/LegacyProtoLogImplTest.java
new file mode 100644
index 0000000..a64996c
--- /dev/null
+++ b/tests/Internal/src/com/android/internal/protolog/LegacyProtoLogImplTest.java
@@ -0,0 +1,396 @@
+/*
+ * Copyright (C) 2019 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.internal.protolog;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.internal.protolog.LegacyProtoLogImpl.PROTOLOG_VERSION;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.SystemClock;
+import android.platform.test.annotations.Presubmit;
+import android.util.proto.ProtoInputStream;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.protolog.common.IProtoLogGroup;
+import com.android.internal.protolog.common.LogLevel;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.util.LinkedList;
+
+/**
+ * Test class for {@link ProtoLogImpl}.
+ */
+@SuppressWarnings("ConstantConditions")
+@SmallTest
+@Presubmit
+@RunWith(JUnit4.class)
+public class LegacyProtoLogImplTest {
+
+    private static final byte[] MAGIC_HEADER = new byte[]{
+            0x9, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x4c, 0x4f, 0x47
+    };
+
+    private LegacyProtoLogImpl mProtoLog;
+    private File mFile;
+
+    @Mock
+    private LegacyProtoLogViewerConfigReader mReader;
+
+    private final String mViewerConfigFilename = "unused/file/path";
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        final Context testContext = getInstrumentation().getContext();
+        mFile = testContext.getFileStreamPath("tracing_test.dat");
+        //noinspection ResultOfMethodCallIgnored
+        mFile.delete();
+        mProtoLog = new LegacyProtoLogImpl(mFile, mViewerConfigFilename,
+                1024 * 1024, mReader, 1024);
+    }
+
+    @After
+    public void tearDown() {
+        if (mFile != null) {
+            //noinspection ResultOfMethodCallIgnored
+            mFile.delete();
+        }
+        ProtoLogImpl.setSingleInstance(null);
+    }
+
+    @Test
+    public void isEnabled_returnsFalseByDefault() {
+        assertFalse(mProtoLog.isProtoEnabled());
+    }
+
+    @Test
+    public void isEnabled_returnsTrueAfterStart() {
+        mProtoLog.startProtoLog(mock(PrintWriter.class));
+        assertTrue(mProtoLog.isProtoEnabled());
+    }
+
+    @Test
+    public void isEnabled_returnsFalseAfterStop() {
+        mProtoLog.startProtoLog(mock(PrintWriter.class));
+        mProtoLog.stopProtoLog(mock(PrintWriter.class), true);
+        assertFalse(mProtoLog.isProtoEnabled());
+    }
+
+    @Test
+    public void logFile_startsWithMagicHeader() throws Exception {
+        mProtoLog.startProtoLog(mock(PrintWriter.class));
+        mProtoLog.stopProtoLog(mock(PrintWriter.class), true);
+
+        assertTrue("Log file should exist", mFile.exists());
+
+        byte[] header = new byte[MAGIC_HEADER.length];
+        try (InputStream is = new FileInputStream(mFile)) {
+            assertEquals(MAGIC_HEADER.length, is.read(header));
+            assertArrayEquals(MAGIC_HEADER, header);
+        }
+    }
+
+    @Test
+    public void log_logcatEnabledExternalMessage() {
+        when(mReader.getViewerString(anyLong())).thenReturn("test %b %d %% 0x%x %s %f");
+        LegacyProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
+        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+
+        implSpy.log(
+                LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null,
+                new Object[]{true, 10000, 30000, "test", 0.000003});
+
+        verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
+                LogLevel.INFO),
+                eq("test true 10000 % 0x7530 test 3.0E-6"));
+        verify(mReader).getViewerString(eq(1234L));
+    }
+
+    @Test
+    public void log_logcatEnabledInvalidMessage() {
+        when(mReader.getViewerString(anyLong())).thenReturn("test %b %d %% %x %s %f");
+        LegacyProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
+        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+
+        implSpy.log(
+                LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null,
+                new Object[]{true, 10000, 0.0001, 0.00002, "test"});
+
+        verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
+                LogLevel.INFO),
+                eq("UNKNOWN MESSAGE (1234) true 10000 1.0E-4 2.0E-5 test"));
+        verify(mReader).getViewerString(eq(1234L));
+    }
+
+    @Test
+    public void log_logcatEnabledInlineMessage() {
+        when(mReader.getViewerString(anyLong())).thenReturn("test %d");
+        LegacyProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
+        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+
+        implSpy.log(
+                LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d",
+                new Object[]{5});
+
+        verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
+                LogLevel.INFO), eq("test 5"));
+        verify(mReader, never()).getViewerString(anyLong());
+    }
+
+    @Test
+    public void log_logcatEnabledNoMessage() {
+        when(mReader.getViewerString(anyLong())).thenReturn(null);
+        LegacyProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
+        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+
+        implSpy.log(
+                LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null,
+                new Object[]{5});
+
+        verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
+                LogLevel.INFO), eq("UNKNOWN MESSAGE (1234) 5"));
+        verify(mReader).getViewerString(eq(1234L));
+    }
+
+    @Test
+    public void log_logcatDisabled() {
+        when(mReader.getViewerString(anyLong())).thenReturn("test %d");
+        LegacyProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false);
+        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+
+        implSpy.log(
+                LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d",
+                new Object[]{5});
+
+        verify(implSpy, never()).passToLogcat(any(), any(), any());
+        verify(mReader, never()).getViewerString(anyLong());
+    }
+
+    private static class ProtoLogData {
+        Long mMessageHash = null;
+        Long mElapsedTime = null;
+        LinkedList<String> mStrParams = new LinkedList<>();
+        LinkedList<Long> mSint64Params = new LinkedList<>();
+        LinkedList<Double> mDoubleParams = new LinkedList<>();
+        LinkedList<Boolean> mBooleanParams = new LinkedList<>();
+    }
+
+    private ProtoLogData readProtoLogSingle(ProtoInputStream ip) throws IOException {
+        while (ip.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+            if (ip.getFieldNumber() == (int) ProtoLogFileProto.VERSION) {
+                assertEquals(PROTOLOG_VERSION, ip.readString(ProtoLogFileProto.VERSION));
+                continue;
+            }
+            if (ip.getFieldNumber() != (int) ProtoLogFileProto.LOG) {
+                continue;
+            }
+            long token = ip.start(ProtoLogFileProto.LOG);
+            ProtoLogData data = new ProtoLogData();
+            while (ip.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
+                switch (ip.getFieldNumber()) {
+                    case (int) ProtoLogMessage.MESSAGE_HASH: {
+                        data.mMessageHash = ip.readLong(ProtoLogMessage.MESSAGE_HASH);
+                        break;
+                    }
+                    case (int) ProtoLogMessage.ELAPSED_REALTIME_NANOS: {
+                        data.mElapsedTime = ip.readLong(ProtoLogMessage.ELAPSED_REALTIME_NANOS);
+                        break;
+                    }
+                    case (int) ProtoLogMessage.STR_PARAMS: {
+                        data.mStrParams.add(ip.readString(ProtoLogMessage.STR_PARAMS));
+                        break;
+                    }
+                    case (int) ProtoLogMessage.SINT64_PARAMS: {
+                        data.mSint64Params.add(ip.readLong(ProtoLogMessage.SINT64_PARAMS));
+                        break;
+                    }
+                    case (int) ProtoLogMessage.DOUBLE_PARAMS: {
+                        data.mDoubleParams.add(ip.readDouble(ProtoLogMessage.DOUBLE_PARAMS));
+                        break;
+                    }
+                    case (int) ProtoLogMessage.BOOLEAN_PARAMS: {
+                        data.mBooleanParams.add(ip.readBoolean(ProtoLogMessage.BOOLEAN_PARAMS));
+                        break;
+                    }
+                }
+            }
+            ip.end(token);
+            return data;
+        }
+        return null;
+    }
+
+    @Test
+    public void log_protoEnabled() throws Exception {
+        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false);
+        TestProtoLogGroup.TEST_GROUP.setLogToProto(true);
+        mProtoLog.startProtoLog(mock(PrintWriter.class));
+        long before = SystemClock.elapsedRealtimeNanos();
+        mProtoLog.log(
+                LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234,
+                0b1110101001010100, null,
+                new Object[]{"test", 1, 2, 3, 0.4, 0.5, 0.6, true});
+        long after = SystemClock.elapsedRealtimeNanos();
+        mProtoLog.stopProtoLog(mock(PrintWriter.class), true);
+        try (InputStream is = new FileInputStream(mFile)) {
+            ProtoInputStream ip = new ProtoInputStream(is);
+            ProtoLogData data = readProtoLogSingle(ip);
+            assertNotNull(data);
+            assertEquals(1234, data.mMessageHash.longValue());
+            assertTrue(before <= data.mElapsedTime && data.mElapsedTime <= after);
+            assertArrayEquals(new String[]{"test"}, data.mStrParams.toArray());
+            assertArrayEquals(new Long[]{1L, 2L, 3L}, data.mSint64Params.toArray());
+            assertArrayEquals(new Double[]{0.4, 0.5, 0.6}, data.mDoubleParams.toArray());
+            assertArrayEquals(new Boolean[]{true}, data.mBooleanParams.toArray());
+        }
+    }
+
+    @Test
+    public void log_invalidParamsMask() throws Exception {
+        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false);
+        TestProtoLogGroup.TEST_GROUP.setLogToProto(true);
+        mProtoLog.startProtoLog(mock(PrintWriter.class));
+        long before = SystemClock.elapsedRealtimeNanos();
+        mProtoLog.log(
+                LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234,
+                0b01100100, null,
+                new Object[]{"test", 1, 0.1, true});
+        long after = SystemClock.elapsedRealtimeNanos();
+        mProtoLog.stopProtoLog(mock(PrintWriter.class), true);
+        try (InputStream is = new FileInputStream(mFile)) {
+            ProtoInputStream ip = new ProtoInputStream(is);
+            ProtoLogData data = readProtoLogSingle(ip);
+            assertNotNull(data);
+            assertEquals(1234, data.mMessageHash.longValue());
+            assertTrue(before <= data.mElapsedTime && data.mElapsedTime <= after);
+            assertArrayEquals(new String[]{"test", "(INVALID PARAMS_MASK) true"},
+                    data.mStrParams.toArray());
+            assertArrayEquals(new Long[]{1L}, data.mSint64Params.toArray());
+            assertArrayEquals(new Double[]{0.1}, data.mDoubleParams.toArray());
+            assertArrayEquals(new Boolean[]{}, data.mBooleanParams.toArray());
+        }
+    }
+
+    @Test
+    public void log_protoDisabled() throws Exception {
+        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false);
+        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+        mProtoLog.startProtoLog(mock(PrintWriter.class));
+        mProtoLog.log(LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234,
+                0b11, null, new Object[]{true});
+        mProtoLog.stopProtoLog(mock(PrintWriter.class), true);
+        try (InputStream is = new FileInputStream(mFile)) {
+            ProtoInputStream ip = new ProtoInputStream(is);
+            ProtoLogData data = readProtoLogSingle(ip);
+            assertNull(data);
+        }
+    }
+
+    private enum TestProtoLogGroup implements IProtoLogGroup {
+        TEST_GROUP(true, true, false, "WindowManagetProtoLogTest");
+
+        private final boolean mEnabled;
+        private volatile boolean mLogToProto;
+        private volatile boolean mLogToLogcat;
+        private final String mTag;
+
+        /**
+         * @param enabled     set to false to exclude all log statements for this group from
+         *                    compilation,
+         *                    they will not be available in runtime.
+         * @param logToProto  enable binary logging for the group
+         * @param logToLogcat enable text logging for the group
+         * @param tag         name of the source of the logged message
+         */
+        TestProtoLogGroup(boolean enabled, boolean logToProto, boolean logToLogcat, String tag) {
+            this.mEnabled = enabled;
+            this.mLogToProto = logToProto;
+            this.mLogToLogcat = logToLogcat;
+            this.mTag = tag;
+        }
+
+        @Override
+        public boolean isEnabled() {
+            return mEnabled;
+        }
+
+        @Override
+        public boolean isLogToProto() {
+            return mLogToProto;
+        }
+
+        @Override
+        public boolean isLogToLogcat() {
+            return mLogToLogcat;
+        }
+
+        @Override
+        public boolean isLogToAny() {
+            return mLogToLogcat || mLogToProto;
+        }
+
+        @Override
+        public String getTag() {
+            return mTag;
+        }
+
+        @Override
+        public void setLogToProto(boolean logToProto) {
+            this.mLogToProto = logToProto;
+        }
+
+        @Override
+        public void setLogToLogcat(boolean logToLogcat) {
+            this.mLogToLogcat = logToLogcat;
+        }
+
+    }
+}
diff --git a/tests/Internal/src/com/android/internal/protolog/PerfettoDataSourceTest.java b/tests/Internal/src/com/android/internal/protolog/PerfettoDataSourceTest.java
new file mode 100644
index 0000000..b9f1738
--- /dev/null
+++ b/tests/Internal/src/com/android/internal/protolog/PerfettoDataSourceTest.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2024 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.internal.protolog;
+
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeTrue;
+
+import android.tracing.perfetto.CreateTlsStateArgs;
+import android.util.proto.ProtoInputStream;
+
+import com.android.internal.protolog.common.LogLevel;
+
+import com.google.common.truth.Truth;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import perfetto.protos.DataSourceConfigOuterClass;
+import perfetto.protos.ProtologCommon;
+import perfetto.protos.ProtologConfig;
+
+public class PerfettoDataSourceTest {
+    @Before
+    public void before() {
+        assumeTrue(android.tracing.Flags.perfettoProtolog());
+    }
+
+    @Test
+    public void noConfig() {
+        final ProtoLogDataSource.TlsState tlsState = createTlsState(
+                DataSourceConfigOuterClass.DataSourceConfig.newBuilder().build());
+
+        Truth.assertThat(tlsState.getLogFromLevel("SOME_TAG")).isEqualTo(LogLevel.WTF);
+        Truth.assertThat(tlsState.getShouldCollectStacktrace("SOME_TAG")).isFalse();
+    }
+
+    @Test
+    public void defaultTraceMode() {
+        final ProtoLogDataSource.TlsState tlsState = createTlsState(
+                DataSourceConfigOuterClass.DataSourceConfig.newBuilder()
+                        .setProtologConfig(
+                                ProtologConfig.ProtoLogConfig.newBuilder()
+                                        .setTracingMode(
+                                                ProtologConfig.ProtoLogConfig.TracingMode
+                                                        .ENABLE_ALL)
+                                        .build()
+                        ).build());
+
+        Truth.assertThat(tlsState.getLogFromLevel("SOME_TAG")).isEqualTo(LogLevel.DEBUG);
+        Truth.assertThat(tlsState.getShouldCollectStacktrace("SOME_TAG")).isFalse();
+    }
+
+    @Test
+    public void allEnabledTraceMode() {
+        final ProtoLogDataSource ds = new ProtoLogDataSource(() -> {}, () -> {}, () -> {});
+
+        final ProtoLogDataSource.TlsState tlsState = createTlsState(
+                DataSourceConfigOuterClass.DataSourceConfig.newBuilder().setProtologConfig(
+                        ProtologConfig.ProtoLogConfig.newBuilder()
+                                .setTracingMode(
+                                        ProtologConfig.ProtoLogConfig.TracingMode.ENABLE_ALL)
+                                .build()
+                ).build()
+        );
+
+        Truth.assertThat(tlsState.getLogFromLevel("SOME_TAG")).isEqualTo(LogLevel.DEBUG);
+        Truth.assertThat(tlsState.getShouldCollectStacktrace("SOME_TAG")).isFalse();
+    }
+
+    @Test
+    public void requireGroupTagInOverrides() {
+        Exception exception = assertThrows(RuntimeException.class, () -> {
+            createTlsState(DataSourceConfigOuterClass.DataSourceConfig.newBuilder()
+                    .setProtologConfig(
+                            ProtologConfig.ProtoLogConfig.newBuilder()
+                                    .addGroupOverrides(
+                                            ProtologConfig.ProtoLogGroup.newBuilder()
+                                                    .setLogFrom(
+                                                            ProtologCommon.ProtoLogLevel
+                                                                    .PROTOLOG_LEVEL_WARN)
+                                                    .setCollectStacktrace(true)
+                                    )
+                                    .build()
+                    ).build());
+        });
+
+        Truth.assertThat(exception).hasMessageThat().contains("group override without a group tag");
+    }
+
+    @Test
+    public void stackTraceCollection() {
+        final ProtoLogDataSource.TlsState tlsState = createTlsState(
+                DataSourceConfigOuterClass.DataSourceConfig.newBuilder().setProtologConfig(
+                        ProtologConfig.ProtoLogConfig.newBuilder()
+                                .addGroupOverrides(
+                                        ProtologConfig.ProtoLogGroup.newBuilder()
+                                                .setGroupName("SOME_TAG")
+                                                .setCollectStacktrace(true)
+                                )
+                                .build()
+                ).build());
+
+        Truth.assertThat(tlsState.getShouldCollectStacktrace("SOME_TAG")).isTrue();
+    }
+
+    @Test
+    public void groupLogFromOverrides() {
+        final ProtoLogDataSource.TlsState tlsState = createTlsState(
+                DataSourceConfigOuterClass.DataSourceConfig.newBuilder().setProtologConfig(
+                        ProtologConfig.ProtoLogConfig.newBuilder()
+                                .addGroupOverrides(
+                                        ProtologConfig.ProtoLogGroup.newBuilder()
+                                                .setGroupName("SOME_TAG")
+                                                .setLogFrom(
+                                                        ProtologCommon.ProtoLogLevel
+                                                                .PROTOLOG_LEVEL_DEBUG)
+                                                .setCollectStacktrace(true)
+                                )
+                                .addGroupOverrides(
+                                        ProtologConfig.ProtoLogGroup.newBuilder()
+                                                .setGroupName("SOME_OTHER_TAG")
+                                                .setLogFrom(
+                                                        ProtologCommon.ProtoLogLevel
+                                                                .PROTOLOG_LEVEL_WARN)
+                                )
+                                .build()
+                ).build());
+
+        Truth.assertThat(tlsState.getLogFromLevel("SOME_TAG")).isEqualTo(LogLevel.DEBUG);
+        Truth.assertThat(tlsState.getShouldCollectStacktrace("SOME_TAG")).isTrue();
+
+        Truth.assertThat(tlsState.getLogFromLevel("SOME_OTHER_TAG")).isEqualTo(LogLevel.WARN);
+        Truth.assertThat(tlsState.getShouldCollectStacktrace("SOME_OTHER_TAG")).isFalse();
+
+        Truth.assertThat(tlsState.getLogFromLevel("UNKNOWN_TAG")).isEqualTo(LogLevel.WTF);
+        Truth.assertThat(tlsState.getShouldCollectStacktrace("UNKNOWN_TAG")).isFalse();
+    }
+
+    private ProtoLogDataSource.TlsState createTlsState(
+            DataSourceConfigOuterClass.DataSourceConfig config) {
+        final ProtoLogDataSource ds =
+                Mockito.spy(new ProtoLogDataSource(() -> {}, () -> {}, () -> {}));
+
+        ProtoInputStream configStream = new ProtoInputStream(config.toByteArray());
+        final ProtoLogDataSource.Instance dsInstance = Mockito.spy(
+                ds.createInstance(configStream, 8));
+        Mockito.doNothing().when(dsInstance).release();
+        final CreateTlsStateArgs mockCreateTlsStateArgs = Mockito.mock(CreateTlsStateArgs.class);
+        Mockito.when(mockCreateTlsStateArgs.getDataSourceInstanceLocked()).thenReturn(dsInstance);
+        return ds.createTlsState(mockCreateTlsStateArgs);
+    }
+}
diff --git a/tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java b/tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java
new file mode 100644
index 0000000..270f595
--- /dev/null
+++ b/tests/Internal/src/com/android/internal/protolog/PerfettoProtoLogImplTest.java
@@ -0,0 +1,586 @@
+/*
+ * Copyright (C) 2024 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.internal.protolog;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import static java.io.File.createTempFile;
+import static java.nio.file.Files.createTempDirectory;
+
+import android.content.Context;
+import android.os.SystemClock;
+import android.platform.test.annotations.Presubmit;
+import android.tools.ScenarioBuilder;
+import android.tools.traces.TraceConfig;
+import android.tools.traces.TraceConfigs;
+import android.tools.traces.io.ResultReader;
+import android.tools.traces.io.ResultWriter;
+import android.tools.traces.monitors.PerfettoTraceMonitor;
+import android.tools.traces.protolog.ProtoLogTrace;
+import android.tracing.perfetto.DataSource;
+import android.util.proto.ProtoInputStream;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.protolog.common.IProtoLogGroup;
+import com.android.internal.protolog.common.LogDataType;
+import com.android.internal.protolog.common.LogLevel;
+
+import com.google.common.truth.Truth;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Random;
+
+import perfetto.protos.Protolog;
+import perfetto.protos.ProtologCommon;
+
+/**
+ * Test class for {@link ProtoLogImpl}.
+ */
+@SuppressWarnings("ConstantConditions")
+@SmallTest
+@Presubmit
+@RunWith(JUnit4.class)
+public class PerfettoProtoLogImplTest {
+    private final File mTracingDirectory = createTempDirectory("temp").toFile();
+
+    private final ResultWriter mWriter = new ResultWriter()
+            .forScenario(new ScenarioBuilder()
+                    .forClass(createTempFile("temp", "").getName()).build())
+            .withOutputDir(mTracingDirectory)
+            .setRunComplete();
+
+    private final TraceConfigs mTraceConfig = new TraceConfigs(
+            new TraceConfig(false, true, false),
+            new TraceConfig(false, true, false),
+            new TraceConfig(false, true, false),
+            new TraceConfig(false, true, false)
+    );
+
+    private PerfettoProtoLogImpl mProtoLog;
+    private Protolog.ProtoLogViewerConfig.Builder mViewerConfigBuilder;
+    private File mFile;
+
+    private ProtoLogViewerConfigReader mReader;
+
+    public PerfettoProtoLogImplTest() throws IOException {
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        final Context testContext = getInstrumentation().getContext();
+        mFile = testContext.getFileStreamPath("tracing_test.dat");
+        //noinspection ResultOfMethodCallIgnored
+        mFile.delete();
+
+        mViewerConfigBuilder = Protolog.ProtoLogViewerConfig.newBuilder()
+                .addGroups(
+                        Protolog.ProtoLogViewerConfig.Group.newBuilder()
+                                .setId(1)
+                                .setName(TestProtoLogGroup.TEST_GROUP.toString())
+                                .setTag(TestProtoLogGroup.TEST_GROUP.getTag())
+                ).addMessages(
+                        Protolog.ProtoLogViewerConfig.MessageData.newBuilder()
+                                .setMessageId(1)
+                                .setMessage("My Test Debug Log Message %b")
+                                .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_DEBUG)
+                                .setGroupId(1)
+                ).addMessages(
+                        Protolog.ProtoLogViewerConfig.MessageData.newBuilder()
+                                .setMessageId(2)
+                                .setMessage("My Test Verbose Log Message %b")
+                                .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_VERBOSE)
+                                .setGroupId(1)
+                ).addMessages(
+                        Protolog.ProtoLogViewerConfig.MessageData.newBuilder()
+                                .setMessageId(3)
+                                .setMessage("My Test Warn Log Message %b")
+                                .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_WARN)
+                                .setGroupId(1)
+                ).addMessages(
+                        Protolog.ProtoLogViewerConfig.MessageData.newBuilder()
+                                .setMessageId(4)
+                                .setMessage("My Test Error Log Message %b")
+                                .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_ERROR)
+                                .setGroupId(1)
+                ).addMessages(
+                        Protolog.ProtoLogViewerConfig.MessageData.newBuilder()
+                                .setMessageId(5)
+                                .setMessage("My Test WTF Log Message %b")
+                                .setLevel(ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_WTF)
+                                .setGroupId(1)
+                );
+
+        ViewerConfigInputStreamProvider viewerConfigInputStreamProvider = Mockito.mock(
+                ViewerConfigInputStreamProvider.class);
+        Mockito.when(viewerConfigInputStreamProvider.getInputStream())
+                .thenAnswer(it -> new ProtoInputStream(mViewerConfigBuilder.build().toByteArray()));
+
+        mReader = Mockito.spy(new ProtoLogViewerConfigReader(viewerConfigInputStreamProvider));
+        mProtoLog = new PerfettoProtoLogImpl(viewerConfigInputStreamProvider, mReader);
+    }
+
+    @After
+    public void tearDown() {
+        if (mFile != null) {
+            //noinspection ResultOfMethodCallIgnored
+            mFile.delete();
+        }
+        ProtoLogImpl.setSingleInstance(null);
+    }
+
+    @Test
+    public void isEnabled_returnsFalseByDefault() {
+        assertFalse(mProtoLog.isProtoEnabled());
+    }
+
+    @Test
+    public void isEnabled_returnsTrueAfterStart() {
+        PerfettoTraceMonitor traceMonitor =
+                PerfettoTraceMonitor.newBuilder().enableProtoLog().build();
+        try {
+            traceMonitor.start();
+            assertTrue(mProtoLog.isProtoEnabled());
+        } finally {
+            traceMonitor.stop(mWriter);
+        }
+    }
+
+    @Test
+    public void isEnabled_returnsFalseAfterStop() {
+        PerfettoTraceMonitor traceMonitor =
+                PerfettoTraceMonitor.newBuilder().enableProtoLog().build();
+        try {
+            traceMonitor.start();
+            assertTrue(mProtoLog.isProtoEnabled());
+        } finally {
+            traceMonitor.stop(mWriter);
+        }
+
+        assertFalse(mProtoLog.isProtoEnabled());
+    }
+
+    @Test
+    public void defaultMode() throws IOException {
+        PerfettoTraceMonitor traceMonitor =
+                PerfettoTraceMonitor.newBuilder().enableProtoLog(false).build();
+        try {
+            traceMonitor.start();
+            // Shouldn't be logging anything except WTF unless explicitly requested in the group
+            // override.
+            mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.VERBOSE, TestProtoLogGroup.TEST_GROUP, 2,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.WARN, TestProtoLogGroup.TEST_GROUP, 3,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.ERROR, TestProtoLogGroup.TEST_GROUP, 4,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.WTF, TestProtoLogGroup.TEST_GROUP, 5,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+        } finally {
+            traceMonitor.stop(mWriter);
+        }
+
+        final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig);
+        final ProtoLogTrace protolog = reader.readProtoLogTrace();
+
+        Truth.assertThat(protolog.messages).hasSize(1);
+        Truth.assertThat(protolog.messages.getFirst().getLevel()).isEqualTo(LogLevel.WTF);
+    }
+
+    @Test
+    public void respectsOverrideConfigs_defaultMode() throws IOException {
+        PerfettoTraceMonitor traceMonitor =
+                PerfettoTraceMonitor.newBuilder().enableProtoLog(true,
+                        List.of(new PerfettoTraceMonitor.Builder.ProtoLogGroupOverride(
+                                TestProtoLogGroup.TEST_GROUP.toString(), LogLevel.DEBUG, true)))
+                        .build();
+        try {
+            traceMonitor.start();
+            mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.VERBOSE, TestProtoLogGroup.TEST_GROUP, 2,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.WARN, TestProtoLogGroup.TEST_GROUP, 3,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.ERROR, TestProtoLogGroup.TEST_GROUP, 4,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.WTF, TestProtoLogGroup.TEST_GROUP, 5,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+        } finally {
+            traceMonitor.stop(mWriter);
+        }
+
+        final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig);
+        final ProtoLogTrace protolog = reader.readProtoLogTrace();
+
+        Truth.assertThat(protolog.messages).hasSize(5);
+        Truth.assertThat(protolog.messages.get(0).getLevel()).isEqualTo(LogLevel.DEBUG);
+        Truth.assertThat(protolog.messages.get(1).getLevel()).isEqualTo(LogLevel.VERBOSE);
+        Truth.assertThat(protolog.messages.get(2).getLevel()).isEqualTo(LogLevel.WARN);
+        Truth.assertThat(protolog.messages.get(3).getLevel()).isEqualTo(LogLevel.ERROR);
+        Truth.assertThat(protolog.messages.get(4).getLevel()).isEqualTo(LogLevel.WTF);
+    }
+
+    @Test
+    public void respectsOverrideConfigs_allEnabledMode() throws IOException {
+        PerfettoTraceMonitor traceMonitor =
+                PerfettoTraceMonitor.newBuilder().enableProtoLog(true,
+                        List.of(new PerfettoTraceMonitor.Builder.ProtoLogGroupOverride(
+                                TestProtoLogGroup.TEST_GROUP.toString(), LogLevel.WARN, false)))
+                        .build();
+        try {
+            traceMonitor.start();
+            mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.VERBOSE, TestProtoLogGroup.TEST_GROUP, 2,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.WARN, TestProtoLogGroup.TEST_GROUP, 3,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.ERROR, TestProtoLogGroup.TEST_GROUP, 4,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.WTF, TestProtoLogGroup.TEST_GROUP, 5,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+        } finally {
+            traceMonitor.stop(mWriter);
+        }
+
+        final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig);
+        final ProtoLogTrace protolog = reader.readProtoLogTrace();
+
+        Truth.assertThat(protolog.messages).hasSize(3);
+        Truth.assertThat(protolog.messages.get(0).getLevel()).isEqualTo(LogLevel.WARN);
+        Truth.assertThat(protolog.messages.get(1).getLevel()).isEqualTo(LogLevel.ERROR);
+        Truth.assertThat(protolog.messages.get(2).getLevel()).isEqualTo(LogLevel.WTF);
+    }
+
+    @Test
+    public void respectsAllEnabledMode() throws IOException {
+        PerfettoTraceMonitor traceMonitor =
+                PerfettoTraceMonitor.newBuilder().enableProtoLog(true, List.of())
+                        .build();
+        try {
+            traceMonitor.start();
+            mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.VERBOSE, TestProtoLogGroup.TEST_GROUP, 2,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.WARN, TestProtoLogGroup.TEST_GROUP, 3,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.ERROR, TestProtoLogGroup.TEST_GROUP, 4,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+            mProtoLog.log(LogLevel.WTF, TestProtoLogGroup.TEST_GROUP, 5,
+                    LogDataType.BOOLEAN, null, new Object[]{true});
+        } finally {
+            traceMonitor.stop(mWriter);
+        }
+
+        final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig);
+        final ProtoLogTrace protolog = reader.readProtoLogTrace();
+
+        Truth.assertThat(protolog.messages).hasSize(5);
+        Truth.assertThat(protolog.messages.get(0).getLevel()).isEqualTo(LogLevel.DEBUG);
+        Truth.assertThat(protolog.messages.get(1).getLevel()).isEqualTo(LogLevel.VERBOSE);
+        Truth.assertThat(protolog.messages.get(2).getLevel()).isEqualTo(LogLevel.WARN);
+        Truth.assertThat(protolog.messages.get(3).getLevel()).isEqualTo(LogLevel.ERROR);
+        Truth.assertThat(protolog.messages.get(4).getLevel()).isEqualTo(LogLevel.WTF);
+    }
+
+    @Test
+    public void log_logcatEnabledExternalMessage() {
+        when(mReader.getViewerString(anyLong())).thenReturn("test %b %d %% 0x%x %s %f");
+        PerfettoProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
+        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+
+        implSpy.log(
+                LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null,
+                new Object[]{true, 10000, 30000, "test", 0.000003});
+
+        verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
+                LogLevel.INFO),
+                eq("test true 10000 % 0x7530 test 3.0E-6"));
+        verify(mReader).getViewerString(eq(1234L));
+    }
+
+    @Test
+    public void log_logcatEnabledInvalidMessage() {
+        when(mReader.getViewerString(anyLong())).thenReturn("test %b %d %% %x %s %f");
+        PerfettoProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
+        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+
+        implSpy.log(
+                LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null,
+                new Object[]{true, 10000, 0.0001, 0.00002, "test"});
+
+        verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
+                LogLevel.INFO),
+                eq("UNKNOWN MESSAGE (1234) true 10000 1.0E-4 2.0E-5 test"));
+        verify(mReader).getViewerString(eq(1234L));
+    }
+
+    @Test
+    public void log_logcatEnabledInlineMessage() {
+        when(mReader.getViewerString(anyLong())).thenReturn("test %d");
+        PerfettoProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
+        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+
+        implSpy.log(
+                LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d",
+                new Object[]{5});
+
+        verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
+                LogLevel.INFO), eq("test 5"));
+        verify(mReader, never()).getViewerString(anyLong());
+    }
+
+    @Test
+    public void log_logcatEnabledNoMessage() {
+        when(mReader.getViewerString(anyLong())).thenReturn(null);
+        PerfettoProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
+        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
+
+        implSpy.log(
+                LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null,
+                new Object[]{5});
+
+        verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
+                LogLevel.INFO), eq("UNKNOWN MESSAGE (1234) 5"));
+        verify(mReader).getViewerString(eq(1234L));
+    }
+
+    @Test
+    public void log_logcatDisabled() {
+        when(mReader.getViewerString(anyLong())).thenReturn("test %d");
+        PerfettoProtoLogImpl implSpy = Mockito.spy(mProtoLog);
+        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false);
+
+        implSpy.log(
+                LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d",
+                new Object[]{5});
+
+        verify(implSpy, never()).passToLogcat(any(), any(), any());
+        verify(mReader, never()).getViewerString(anyLong());
+    }
+
+    @Test
+    public void log_protoEnabled() throws Exception {
+        final long messageHash = addMessageToConfig(
+                ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_INFO,
+                "My test message :: %s, %d, %o, %x, %f, %e, %g, %b");
+
+        PerfettoTraceMonitor traceMonitor =
+                PerfettoTraceMonitor.newBuilder().enableProtoLog().build();
+        long before;
+        long after;
+        try {
+            traceMonitor.start();
+            assertTrue(mProtoLog.isProtoEnabled());
+
+            before = SystemClock.elapsedRealtimeNanos();
+            mProtoLog.log(
+                    LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, messageHash,
+                    0b1110101001010100, null,
+                    new Object[]{"test", 1, 2, 3, 0.4, 0.5, 0.6, true});
+            after = SystemClock.elapsedRealtimeNanos();
+        } finally {
+            traceMonitor.stop(mWriter);
+        }
+
+        final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig);
+        final ProtoLogTrace protolog = reader.readProtoLogTrace();
+
+        Truth.assertThat(protolog.messages).hasSize(1);
+        Truth.assertThat(protolog.messages.getFirst().getTimestamp().getElapsedNanos())
+                .isAtLeast(before);
+        Truth.assertThat(protolog.messages.getFirst().getTimestamp().getElapsedNanos())
+                .isAtMost(after);
+        Truth.assertThat(protolog.messages.getFirst().getMessage())
+                .isEqualTo("My test message :: test, 2, 4, 6, 0.400000, 5.000000e-01, 0.6, true");
+    }
+
+    private long addMessageToConfig(ProtologCommon.ProtoLogLevel logLevel, String message) {
+        final long messageId = new Random().nextLong();
+        mViewerConfigBuilder.addMessages(Protolog.ProtoLogViewerConfig.MessageData.newBuilder()
+                .setMessageId(messageId)
+                .setMessage(message)
+                .setLevel(logLevel)
+                .setGroupId(1)
+        );
+
+        return messageId;
+    }
+
+    @Test
+    public void log_invalidParamsMask() {
+        final long messageHash = addMessageToConfig(
+                ProtologCommon.ProtoLogLevel.PROTOLOG_LEVEL_INFO,
+                "My test message :: %s, %d, %f, %b");
+        PerfettoTraceMonitor traceMonitor =
+                PerfettoTraceMonitor.newBuilder().enableProtoLog().build();
+        long before;
+        long after;
+        try {
+            traceMonitor.start();
+            before = SystemClock.elapsedRealtimeNanos();
+            mProtoLog.log(
+                    LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, messageHash,
+                    0b01100100, null,
+                    new Object[]{"test", 1, 0.1, true});
+            after = SystemClock.elapsedRealtimeNanos();
+        } finally {
+            traceMonitor.stop(mWriter);
+        }
+
+        final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig);
+        assertThrows(IllegalStateException.class, reader::readProtoLogTrace);
+    }
+
+    @Test
+    public void log_protoDisabled() throws Exception {
+        PerfettoTraceMonitor traceMonitor =
+                PerfettoTraceMonitor.newBuilder().enableProtoLog(false).build();
+        try {
+            traceMonitor.start();
+            mProtoLog.log(LogLevel.DEBUG, TestProtoLogGroup.TEST_GROUP, 1,
+                    0b11, null, new Object[]{true});
+        } finally {
+            traceMonitor.stop(mWriter);
+        }
+
+        final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig);
+        final ProtoLogTrace protolog = reader.readProtoLogTrace();
+
+        Truth.assertThat(protolog.messages).isEmpty();
+    }
+
+    @Test
+    public void stackTraceTrimmed() throws IOException {
+        PerfettoTraceMonitor traceMonitor =
+                PerfettoTraceMonitor.newBuilder().enableProtoLog(true,
+                        List.of(new PerfettoTraceMonitor.Builder.ProtoLogGroupOverride(
+                                TestProtoLogGroup.TEST_GROUP.toString(), LogLevel.DEBUG, true)))
+                        .build();
+        try {
+            traceMonitor.start();
+
+            ProtoLogImpl.setSingleInstance(mProtoLog);
+            ProtoLogImpl.d(TestProtoLogGroup.TEST_GROUP, 1,
+                    0b11, null, true);
+        } finally {
+            traceMonitor.stop(mWriter);
+        }
+
+        final ResultReader reader = new ResultReader(mWriter.write(), mTraceConfig);
+        final ProtoLogTrace protolog = reader.readProtoLogTrace();
+
+        Truth.assertThat(protolog.messages).hasSize(1);
+        String stacktrace = protolog.messages.getFirst().getStacktrace();
+        Truth.assertThat(stacktrace)
+                .doesNotContain(PerfettoProtoLogImpl.class.getSimpleName() + ".java");
+        Truth.assertThat(stacktrace).doesNotContain(DataSource.class.getSimpleName() + ".java");
+        Truth.assertThat(stacktrace)
+                .doesNotContain(ProtoLogImpl.class.getSimpleName() + ".java");
+        Truth.assertThat(stacktrace).contains(PerfettoProtoLogImplTest.class.getSimpleName());
+        Truth.assertThat(stacktrace).contains("stackTraceTrimmed");
+    }
+
+    private enum TestProtoLogGroup implements IProtoLogGroup {
+        TEST_GROUP(true, true, false, "TEST_TAG");
+
+        private final boolean mEnabled;
+        private volatile boolean mLogToProto;
+        private volatile boolean mLogToLogcat;
+        private final String mTag;
+
+        /**
+         * @param enabled     set to false to exclude all log statements for this group from
+         *                    compilation,
+         *                    they will not be available in runtime.
+         * @param logToProto  enable binary logging for the group
+         * @param logToLogcat enable text logging for the group
+         * @param tag         name of the source of the logged message
+         */
+        TestProtoLogGroup(boolean enabled, boolean logToProto, boolean logToLogcat, String tag) {
+            this.mEnabled = enabled;
+            this.mLogToProto = logToProto;
+            this.mLogToLogcat = logToLogcat;
+            this.mTag = tag;
+        }
+
+        @Override
+        public boolean isEnabled() {
+            return mEnabled;
+        }
+
+        @Override
+        public boolean isLogToProto() {
+            return mLogToProto;
+        }
+
+        @Override
+        public boolean isLogToLogcat() {
+            return mLogToLogcat;
+        }
+
+        @Override
+        public boolean isLogToAny() {
+            return mLogToLogcat || mLogToProto;
+        }
+
+        @Override
+        public String getTag() {
+            return mTag;
+        }
+
+        @Override
+        public void setLogToProto(boolean logToProto) {
+            this.mLogToProto = logToProto;
+        }
+
+        @Override
+        public void setLogToLogcat(boolean logToLogcat) {
+            this.mLogToLogcat = logToLogcat;
+        }
+
+    }
+}
diff --git a/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java b/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java
index 7deb8c7..4267c2c 100644
--- a/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java
+++ b/tests/Internal/src/com/android/internal/protolog/ProtoLogImplTest.java
@@ -16,49 +16,23 @@
 
 package com.android.internal.protolog;
 
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-import static com.android.internal.protolog.ProtoLogImpl.PROTOLOG_VERSION;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 
-import android.content.Context;
-import android.os.SystemClock;
 import android.platform.test.annotations.Presubmit;
-import android.util.proto.ProtoInputStream;
 
 import androidx.test.filters.SmallTest;
 
+import com.android.internal.protolog.common.IProtoLog;
 import com.android.internal.protolog.common.IProtoLogGroup;
+import com.android.internal.protolog.common.LogLevel;
 
 import org.junit.After;
-import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PrintWriter;
-import java.util.LinkedList;
 
 /**
  * Test class for {@link ProtoLogImpl}.
@@ -68,336 +42,78 @@
 @Presubmit
 @RunWith(JUnit4.class)
 public class ProtoLogImplTest {
-
-    private static final byte[] MAGIC_HEADER = new byte[]{
-            0x9, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x4c, 0x4f, 0x47
-    };
-
-    private ProtoLogImpl mProtoLog;
-    private File mFile;
-
-    @Mock
-    private ProtoLogViewerConfigReader mReader;
-
-    @Before
-    public void setUp() throws Exception {
-        MockitoAnnotations.initMocks(this);
-        final Context testContext = getInstrumentation().getContext();
-        mFile = testContext.getFileStreamPath("tracing_test.dat");
-        //noinspection ResultOfMethodCallIgnored
-        mFile.delete();
-        mProtoLog = new ProtoLogImpl(mFile, 1024 * 1024, mReader, 1024);
-    }
-
     @After
     public void tearDown() {
-        if (mFile != null) {
-            //noinspection ResultOfMethodCallIgnored
-            mFile.delete();
-        }
         ProtoLogImpl.setSingleInstance(null);
     }
 
     @Test
-    public void isEnabled_returnsFalseByDefault() {
-        assertFalse(mProtoLog.isProtoEnabled());
-    }
-
-    @Test
-    public void isEnabled_returnsTrueAfterStart() {
-        mProtoLog.startProtoLog(mock(PrintWriter.class));
-        assertTrue(mProtoLog.isProtoEnabled());
-    }
-
-    @Test
-    public void isEnabled_returnsFalseAfterStop() {
-        mProtoLog.startProtoLog(mock(PrintWriter.class));
-        mProtoLog.stopProtoLog(mock(PrintWriter.class), true);
-        assertFalse(mProtoLog.isProtoEnabled());
-    }
-
-    @Test
-    public void logFile_startsWithMagicHeader() throws Exception {
-        mProtoLog.startProtoLog(mock(PrintWriter.class));
-        mProtoLog.stopProtoLog(mock(PrintWriter.class), true);
-
-        assertTrue("Log file should exist", mFile.exists());
-
-        byte[] header = new byte[MAGIC_HEADER.length];
-        try (InputStream is = new FileInputStream(mFile)) {
-            assertEquals(MAGIC_HEADER.length, is.read(header));
-            assertArrayEquals(MAGIC_HEADER, header);
-        }
-    }
-
-    @Test
     public void getSingleInstance() {
-        ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class);
+        IProtoLog mockedProtoLog = mock(IProtoLog.class);
         ProtoLogImpl.setSingleInstance(mockedProtoLog);
         assertSame(mockedProtoLog, ProtoLogImpl.getSingleInstance());
     }
 
     @Test
     public void d_logCalled() {
-        ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class);
+        IProtoLog mockedProtoLog = mock(IProtoLog.class);
         ProtoLogImpl.setSingleInstance(mockedProtoLog);
         ProtoLogImpl.d(TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d");
-        verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.DEBUG), eq(
+        verify(mockedProtoLog).log(eq(LogLevel.DEBUG), eq(
                 TestProtoLogGroup.TEST_GROUP),
-                eq(1234), eq(4321), eq("test %d"), eq(new Object[]{}));
+                eq(1234L), eq(4321), eq("test %d"), eq(new Object[]{}));
     }
 
     @Test
     public void v_logCalled() {
-        ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class);
+        IProtoLog mockedProtoLog = mock(IProtoLog.class);
         ProtoLogImpl.setSingleInstance(mockedProtoLog);
         ProtoLogImpl.v(TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d");
-        verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.VERBOSE), eq(
+        verify(mockedProtoLog).log(eq(LogLevel.VERBOSE), eq(
                 TestProtoLogGroup.TEST_GROUP),
-                eq(1234), eq(4321), eq("test %d"), eq(new Object[]{}));
+                eq(1234L), eq(4321), eq("test %d"), eq(new Object[]{}));
     }
 
     @Test
     public void i_logCalled() {
-        ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class);
+        IProtoLog mockedProtoLog = mock(IProtoLog.class);
         ProtoLogImpl.setSingleInstance(mockedProtoLog);
         ProtoLogImpl.i(TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d");
-        verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.INFO), eq(
+        verify(mockedProtoLog).log(eq(LogLevel.INFO), eq(
                 TestProtoLogGroup.TEST_GROUP),
-                eq(1234), eq(4321), eq("test %d"), eq(new Object[]{}));
+                eq(1234L), eq(4321), eq("test %d"), eq(new Object[]{}));
     }
 
     @Test
     public void w_logCalled() {
-        ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class);
+        IProtoLog mockedProtoLog = mock(IProtoLog.class);
         ProtoLogImpl.setSingleInstance(mockedProtoLog);
         ProtoLogImpl.w(TestProtoLogGroup.TEST_GROUP, 1234,
                 4321, "test %d");
-        verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.WARN), eq(
+        verify(mockedProtoLog).log(eq(LogLevel.WARN), eq(
                 TestProtoLogGroup.TEST_GROUP),
-                eq(1234), eq(4321), eq("test %d"), eq(new Object[]{}));
+                eq(1234L), eq(4321), eq("test %d"), eq(new Object[]{}));
     }
 
     @Test
     public void e_logCalled() {
-        ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class);
+        IProtoLog mockedProtoLog = mock(IProtoLog.class);
         ProtoLogImpl.setSingleInstance(mockedProtoLog);
         ProtoLogImpl.e(TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d");
-        verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.ERROR), eq(
+        verify(mockedProtoLog).log(eq(LogLevel.ERROR), eq(
                 TestProtoLogGroup.TEST_GROUP),
-                eq(1234), eq(4321), eq("test %d"), eq(new Object[]{}));
+                eq(1234L), eq(4321), eq("test %d"), eq(new Object[]{}));
     }
 
     @Test
     public void wtf_logCalled() {
-        ProtoLogImpl mockedProtoLog = mock(ProtoLogImpl.class);
+        IProtoLog mockedProtoLog = mock(IProtoLog.class);
         ProtoLogImpl.setSingleInstance(mockedProtoLog);
         ProtoLogImpl.wtf(TestProtoLogGroup.TEST_GROUP,
                 1234, 4321, "test %d");
-        verify(mockedProtoLog).log(eq(ProtoLogImpl.LogLevel.WTF), eq(
+        verify(mockedProtoLog).log(eq(LogLevel.WTF), eq(
                 TestProtoLogGroup.TEST_GROUP),
-                eq(1234), eq(4321), eq("test %d"), eq(new Object[]{}));
-    }
-
-    @Test
-    public void log_logcatEnabledExternalMessage() {
-        when(mReader.getViewerString(anyInt())).thenReturn("test %b %d %% 0x%x %s %f");
-        ProtoLogImpl implSpy = Mockito.spy(mProtoLog);
-        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
-        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
-
-        implSpy.log(
-                ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null,
-                new Object[]{true, 10000, 30000, "test", 0.000003});
-
-        verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
-                ProtoLogImpl.LogLevel.INFO),
-                eq("test true 10000 % 0x7530 test 3.0E-6"));
-        verify(mReader).getViewerString(eq(1234));
-    }
-
-    @Test
-    public void log_logcatEnabledInvalidMessage() {
-        when(mReader.getViewerString(anyInt())).thenReturn("test %b %d %% %x %s %f");
-        ProtoLogImpl implSpy = Mockito.spy(mProtoLog);
-        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
-        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
-
-        implSpy.log(
-                ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null,
-                new Object[]{true, 10000, 0.0001, 0.00002, "test"});
-
-        verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
-                ProtoLogImpl.LogLevel.INFO),
-                eq("UNKNOWN MESSAGE (1234) true 10000 1.0E-4 2.0E-5 test"));
-        verify(mReader).getViewerString(eq(1234));
-    }
-
-    @Test
-    public void log_logcatEnabledInlineMessage() {
-        when(mReader.getViewerString(anyInt())).thenReturn("test %d");
-        ProtoLogImpl implSpy = Mockito.spy(mProtoLog);
-        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
-        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
-
-        implSpy.log(
-                ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d",
-                new Object[]{5});
-
-        verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
-                ProtoLogImpl.LogLevel.INFO), eq("test 5"));
-        verify(mReader, never()).getViewerString(anyInt());
-    }
-
-    @Test
-    public void log_logcatEnabledNoMessage() {
-        when(mReader.getViewerString(anyInt())).thenReturn(null);
-        ProtoLogImpl implSpy = Mockito.spy(mProtoLog);
-        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(true);
-        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
-
-        implSpy.log(
-                ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, null,
-                new Object[]{5});
-
-        verify(implSpy).passToLogcat(eq(TestProtoLogGroup.TEST_GROUP.getTag()), eq(
-                ProtoLogImpl.LogLevel.INFO), eq("UNKNOWN MESSAGE (1234) 5"));
-        verify(mReader).getViewerString(eq(1234));
-    }
-
-    @Test
-    public void log_logcatDisabled() {
-        when(mReader.getViewerString(anyInt())).thenReturn("test %d");
-        ProtoLogImpl implSpy = Mockito.spy(mProtoLog);
-        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false);
-        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
-
-        implSpy.log(
-                ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234, 4321, "test %d",
-                new Object[]{5});
-
-        verify(implSpy, never()).passToLogcat(any(), any(), any());
-        verify(mReader, never()).getViewerString(anyInt());
-    }
-
-    private static class ProtoLogData {
-        Integer mMessageHash = null;
-        Long mElapsedTime = null;
-        LinkedList<String> mStrParams = new LinkedList<>();
-        LinkedList<Long> mSint64Params = new LinkedList<>();
-        LinkedList<Double> mDoubleParams = new LinkedList<>();
-        LinkedList<Boolean> mBooleanParams = new LinkedList<>();
-    }
-
-    private ProtoLogData readProtoLogSingle(ProtoInputStream ip) throws IOException {
-        while (ip.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
-            if (ip.getFieldNumber() == (int) ProtoLogFileProto.VERSION) {
-                assertEquals(PROTOLOG_VERSION, ip.readString(ProtoLogFileProto.VERSION));
-                continue;
-            }
-            if (ip.getFieldNumber() != (int) ProtoLogFileProto.LOG) {
-                continue;
-            }
-            long token = ip.start(ProtoLogFileProto.LOG);
-            ProtoLogData data = new ProtoLogData();
-            while (ip.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
-                switch (ip.getFieldNumber()) {
-                    case (int) ProtoLogMessage.MESSAGE_HASH: {
-                        data.mMessageHash = ip.readInt(ProtoLogMessage.MESSAGE_HASH);
-                        break;
-                    }
-                    case (int) ProtoLogMessage.ELAPSED_REALTIME_NANOS: {
-                        data.mElapsedTime = ip.readLong(ProtoLogMessage.ELAPSED_REALTIME_NANOS);
-                        break;
-                    }
-                    case (int) ProtoLogMessage.STR_PARAMS: {
-                        data.mStrParams.add(ip.readString(ProtoLogMessage.STR_PARAMS));
-                        break;
-                    }
-                    case (int) ProtoLogMessage.SINT64_PARAMS: {
-                        data.mSint64Params.add(ip.readLong(ProtoLogMessage.SINT64_PARAMS));
-                        break;
-                    }
-                    case (int) ProtoLogMessage.DOUBLE_PARAMS: {
-                        data.mDoubleParams.add(ip.readDouble(ProtoLogMessage.DOUBLE_PARAMS));
-                        break;
-                    }
-                    case (int) ProtoLogMessage.BOOLEAN_PARAMS: {
-                        data.mBooleanParams.add(ip.readBoolean(ProtoLogMessage.BOOLEAN_PARAMS));
-                        break;
-                    }
-                }
-            }
-            ip.end(token);
-            return data;
-        }
-        return null;
-    }
-
-    @Test
-    public void log_protoEnabled() throws Exception {
-        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false);
-        TestProtoLogGroup.TEST_GROUP.setLogToProto(true);
-        mProtoLog.startProtoLog(mock(PrintWriter.class));
-        long before = SystemClock.elapsedRealtimeNanos();
-        mProtoLog.log(
-                ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234,
-                0b1110101001010100, null,
-                new Object[]{"test", 1, 2, 3, 0.4, 0.5, 0.6, true});
-        long after = SystemClock.elapsedRealtimeNanos();
-        mProtoLog.stopProtoLog(mock(PrintWriter.class), true);
-        try (InputStream is = new FileInputStream(mFile)) {
-            ProtoInputStream ip = new ProtoInputStream(is);
-            ProtoLogData data = readProtoLogSingle(ip);
-            assertNotNull(data);
-            assertEquals(1234, data.mMessageHash.longValue());
-            assertTrue(before <= data.mElapsedTime && data.mElapsedTime <= after);
-            assertArrayEquals(new String[]{"test"}, data.mStrParams.toArray());
-            assertArrayEquals(new Long[]{1L, 2L, 3L}, data.mSint64Params.toArray());
-            assertArrayEquals(new Double[]{0.4, 0.5, 0.6}, data.mDoubleParams.toArray());
-            assertArrayEquals(new Boolean[]{true}, data.mBooleanParams.toArray());
-        }
-    }
-
-    @Test
-    public void log_invalidParamsMask() throws Exception {
-        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false);
-        TestProtoLogGroup.TEST_GROUP.setLogToProto(true);
-        mProtoLog.startProtoLog(mock(PrintWriter.class));
-        long before = SystemClock.elapsedRealtimeNanos();
-        mProtoLog.log(
-                ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234,
-                0b01100100, null,
-                new Object[]{"test", 1, 0.1, true});
-        long after = SystemClock.elapsedRealtimeNanos();
-        mProtoLog.stopProtoLog(mock(PrintWriter.class), true);
-        try (InputStream is = new FileInputStream(mFile)) {
-            ProtoInputStream ip = new ProtoInputStream(is);
-            ProtoLogData data = readProtoLogSingle(ip);
-            assertNotNull(data);
-            assertEquals(1234, data.mMessageHash.longValue());
-            assertTrue(before <= data.mElapsedTime && data.mElapsedTime <= after);
-            assertArrayEquals(new String[]{"test", "(INVALID PARAMS_MASK) true"},
-                    data.mStrParams.toArray());
-            assertArrayEquals(new Long[]{1L}, data.mSint64Params.toArray());
-            assertArrayEquals(new Double[]{0.1}, data.mDoubleParams.toArray());
-            assertArrayEquals(new Boolean[]{}, data.mBooleanParams.toArray());
-        }
-    }
-
-    @Test
-    public void log_protoDisabled() throws Exception {
-        TestProtoLogGroup.TEST_GROUP.setLogToLogcat(false);
-        TestProtoLogGroup.TEST_GROUP.setLogToProto(false);
-        mProtoLog.startProtoLog(mock(PrintWriter.class));
-        mProtoLog.log(ProtoLogImpl.LogLevel.INFO, TestProtoLogGroup.TEST_GROUP, 1234,
-                0b11, null, new Object[]{true});
-        mProtoLog.stopProtoLog(mock(PrintWriter.class), true);
-        try (InputStream is = new FileInputStream(mFile)) {
-            ProtoInputStream ip = new ProtoInputStream(is);
-            ProtoLogData data = readProtoLogSingle(ip);
-            assertNull(data);
-        }
+                eq(1234L), eq(4321), eq("test %d"), eq(new Object[]{}));
     }
 
     private enum TestProtoLogGroup implements IProtoLogGroup {
diff --git a/tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java b/tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java
index ae50216..dbd85d3 100644
--- a/tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java
+++ b/tests/Internal/src/com/android/internal/protolog/ProtoLogViewerConfigReaderTest.java
@@ -72,8 +72,8 @@
             + "}\n";
 
 
-    private ProtoLogViewerConfigReader
-            mConfig = new ProtoLogViewerConfigReader();
+    private LegacyProtoLogViewerConfigReader
+            mConfig = new LegacyProtoLogViewerConfigReader();
     private File mTestViewerConfig;
 
     @Before
@@ -98,7 +98,7 @@
 
     @Test
     public void loadViewerConfig() {
-        mConfig.loadViewerConfig(null, mTestViewerConfig.getAbsolutePath());
+        mConfig.loadViewerConfig(msg -> {}, mTestViewerConfig.getAbsolutePath());
         assertEquals("Test completed successfully: %b", mConfig.getViewerString(70933285));
         assertEquals("Test 2", mConfig.getViewerString(1352021864));
         assertEquals("Window %s is already added", mConfig.getViewerString(409412266));
@@ -107,7 +107,7 @@
 
     @Test
     public void loadViewerConfig_invalidFile() {
-        mConfig.loadViewerConfig(null, "/tmp/unknown/file/does/not/exist");
+        mConfig.loadViewerConfig(msg -> {}, "/tmp/unknown/file/does/not/exist");
         // No exception is thrown.
         assertNull(mConfig.getViewerString(1));
     }
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/BufferPresentationTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/BufferPresentationTests.kt
index 97398dc..c258347 100644
--- a/tests/SurfaceViewBufferTests/src/com/android/test/BufferPresentationTests.kt
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/BufferPresentationTests.kt
@@ -15,7 +15,7 @@
  */
 package com.android.test
 
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
+import android.tools.flicker.subject.layers.LayersTraceSubject
 import junit.framework.Assert.assertEquals
 import junit.framework.Assert.assertTrue
 import org.junit.Test
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/BufferRejectionTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/BufferRejectionTests.kt
index 0cc18d6..0e70df4 100644
--- a/tests/SurfaceViewBufferTests/src/com/android/test/BufferRejectionTests.kt
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/BufferRejectionTests.kt
@@ -16,7 +16,7 @@
 package com.android.test
 
 import android.graphics.Point
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
+import android.tools.flicker.subject.layers.LayersTraceSubject
 import com.android.test.SurfaceViewBufferTestBase.Companion.ScalingMode
 import com.android.test.SurfaceViewBufferTestBase.Companion.Transform
 import junit.framework.Assert.assertEquals
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/GeometryTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/GeometryTests.kt
index 6f4d11c..8502474 100644
--- a/tests/SurfaceViewBufferTests/src/com/android/test/GeometryTests.kt
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/GeometryTests.kt
@@ -19,7 +19,7 @@
 import android.graphics.Point
 import android.graphics.Rect
 import android.os.SystemClock
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
+import android.tools.flicker.subject.layers.LayersTraceSubject
 import com.android.test.SurfaceViewBufferTestBase.Companion.ScalingMode
 import com.android.test.SurfaceViewBufferTestBase.Companion.Transform
 import junit.framework.Assert.assertEquals
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/InverseDisplayTransformTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/InverseDisplayTransformTests.kt
index 1de965e..ad8b35e 100644
--- a/tests/SurfaceViewBufferTests/src/com/android/test/InverseDisplayTransformTests.kt
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/InverseDisplayTransformTests.kt
@@ -16,7 +16,7 @@
 package com.android.test
 
 import android.graphics.Point
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
+import android.tools.flicker.subject.layers.LayersTraceSubject
 import com.android.test.SurfaceViewBufferTestBase.Companion.Transform
 import junit.framework.Assert.assertEquals
 import org.junit.Assert
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeTests.kt b/tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeTests.kt
index 4c5224a..b2ceb40 100644
--- a/tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeTests.kt
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/SharedBufferModeTests.kt
@@ -17,7 +17,7 @@
 
 import android.graphics.Color
 import android.graphics.Rect
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
+import android.tools.flicker.subject.layers.LayersTraceSubject
 import junit.framework.Assert.assertEquals
 import org.junit.Test
 import org.junit.runner.RunWith
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt
index b03b733..6e77796 100644
--- a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceTracingTestBase.kt
@@ -21,9 +21,9 @@
 import android.graphics.Rect
 import android.util.Log
 import androidx.test.ext.junit.rules.ActivityScenarioRule
-import android.tools.common.traces.surfaceflinger.LayersTrace
-import android.tools.device.traces.monitors.withSFTracing
-import android.tools.device.traces.monitors.PerfettoTraceMonitor
+import android.tools.traces.surfaceflinger.LayersTrace
+import android.tools.traces.monitors.withSFTracing
+import android.tools.traces.monitors.PerfettoTraceMonitor
 import junit.framework.Assert
 import org.junit.After
 import org.junit.Before
diff --git a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceViewBufferTestBase.kt b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceViewBufferTestBase.kt
index 1770e32..e0b1809 100644
--- a/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceViewBufferTestBase.kt
+++ b/tests/SurfaceViewBufferTests/src/com/android/test/SurfaceViewBufferTestBase.kt
@@ -18,8 +18,8 @@
 import android.app.Instrumentation
 import android.graphics.Point
 import android.provider.Settings
-import android.tools.common.datatypes.Size
-import android.tools.common.flicker.subject.layers.LayerSubject
+import android.tools.datatypes.Size
+import android.tools.flicker.subject.layers.LayerSubject
 import androidx.test.InstrumentationRegistry
 import org.junit.After
 import org.junit.Before
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt b/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt
index 2c7905d..e76a399 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/ResizeTasksSyncTest.kt
@@ -20,9 +20,9 @@
 import androidx.test.ext.junit.rules.ActivityScenarioRule
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.runner.AndroidJUnit4
-import android.tools.common.datatypes.Size
-import android.tools.common.flicker.subject.layers.LayersTraceSubject
-import android.tools.device.traces.monitors.withSFTracing
+import android.tools.datatypes.Size
+import android.tools.flicker.subject.layers.LayersTraceSubject
+import android.tools.traces.monitors.withSFTracing
 import org.junit.After
 import org.junit.Before
 import org.junit.FixMethodOrder
diff --git a/tools/hoststubgen/TEST_MAPPING b/tools/hoststubgen/TEST_MAPPING
index eca258c..b5d5b5f 100644
--- a/tools/hoststubgen/TEST_MAPPING
+++ b/tools/hoststubgen/TEST_MAPPING
@@ -1,6 +1,7 @@
 {
   "presubmit": [
-    { "name": "tiny-framework-dump-test" },
+    // TODO(b/326897452): Reenable after JDK 21 switch.
+    // { "name": "tiny-framework-dump-test" },
     { "name": "hoststubgentest" },
     { "name": "hoststubgen-invoke-test" }
   ],
diff --git a/tools/protologtool/Android.bp b/tools/protologtool/Android.bp
index 46745e9..8fbc3e8 100644
--- a/tools/protologtool/Android.bp
+++ b/tools/protologtool/Android.bp
@@ -11,12 +11,13 @@
     name: "protologtool-lib",
     srcs: [
         "src/com/android/protolog/tool/**/*.kt",
-        ":protolog-common-no-android-src",
+        ":protolog-common-src",
     ],
     static_libs: [
         "javaparser",
         "platformprotos",
         "jsonlib",
+        "perfetto_trace-full",
     ],
 }
 
@@ -42,5 +43,6 @@
         "junit",
         "mockito",
         "objenesis",
+        "truth",
     ],
 }
diff --git a/tools/protologtool/README.md b/tools/protologtool/README.md
index ba63957..24a4861 100644
--- a/tools/protologtool/README.md
+++ b/tools/protologtool/README.md
@@ -8,11 +8,13 @@
 
 ### Code transformation
 
-Command: `protologtool transform-protolog-calls 
-    --protolog-class <protolog class name> 
-    --protolog-impl-class <protolog implementation class name>
+Command: `protologtool transform-protolog-calls
+    --protolog-class <protolog class name>
     --loggroups-class <protolog groups class name>
     --loggroups-jar <config jar path>
+    --viewer-config-file-path <protobuf viewer config file path>
+    --legacy-viewer-config-file-path <legacy json.gz viewer config file path>
+    --legacy-output-file-path <.winscope file path to write the legacy trace to>
     --output-srcjar <output.srcjar>
     [<input.java>]`
 
@@ -44,10 +46,11 @@
 ### Viewer config generation
 
 Command: `generate-viewer-config
-    --protolog-class <protolog class name> 
+    --protolog-class <protolog class name>
     --loggroups-class <protolog groups class name>
     --loggroups-jar <config jar path>
-    --viewer-conf <viewer.json>
+    --viewer-config-type <proto|json>
+    --viewer-config <viewer.json>
     [<input.java>]`
 
 This command is similar in it's syntax to the previous one, only instead of creating a processed source jar
@@ -74,7 +77,7 @@
 
 ### Binary log viewing
 
-Command: `read-log --viewer-conf <viewer.json> <wm_log.pb>`
+Command: `read-log --viewer-config <viewer.json> <wm_log.pb>`
 
 Reads the binary ProtoLog log file and outputs a human-readable LogCat-like text log.
 
diff --git a/tools/protologtool/src/com/android/protolog/tool/CodeUtils.kt b/tools/protologtool/src/com/android/protolog/tool/CodeUtils.kt
index 07c6fd3..3d1dec2 100644
--- a/tools/protologtool/src/com/android/protolog/tool/CodeUtils.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/CodeUtils.kt
@@ -22,15 +22,21 @@
 import com.github.javaparser.ast.expr.BinaryExpr
 import com.github.javaparser.ast.expr.Expression
 import com.github.javaparser.ast.expr.StringLiteralExpr
+import java.util.UUID
 
 object CodeUtils {
     /**
      * Returns a stable hash of a string.
      * We reimplement String::hashCode() for readability reasons.
      */
-    fun hash(position: String, messageString: String, logLevel: LogLevel, logGroup: LogGroup): Int {
-        return (position + messageString + logLevel.name + logGroup.name)
-                .map { c -> c.code }.reduce { h, c -> h * 31 + c }
+    fun hash(
+        position: String,
+        messageString: String,
+        logLevel: LogLevel,
+        logGroup: LogGroup
+    ): Long {
+        val fullStringIdentifier = position + messageString + logLevel.name + logGroup.name
+        return UUID.nameUUIDFromBytes(fullStringIdentifier.toByteArray()).mostSignificantBits
     }
 
     fun checkWildcardStaticImported(code: CompilationUnit, className: String, fileName: String) {
diff --git a/tools/protologtool/src/com/android/protolog/tool/CommandOptions.kt b/tools/protologtool/src/com/android/protolog/tool/CommandOptions.kt
index bfbbf7a..a359155 100644
--- a/tools/protologtool/src/com/android/protolog/tool/CommandOptions.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/CommandOptions.kt
@@ -26,32 +26,35 @@
         private val commands = setOf(TRANSFORM_CALLS_CMD, GENERATE_CONFIG_CMD, READ_LOG_CMD)
 
         private const val PROTOLOG_CLASS_PARAM = "--protolog-class"
-        private const val PROTOLOGIMPL_CLASS_PARAM = "--protolog-impl-class"
-        private const val PROTOLOGCACHE_CLASS_PARAM = "--protolog-cache-class"
         private const val PROTOLOGGROUP_CLASS_PARAM = "--loggroups-class"
         private const val PROTOLOGGROUP_JAR_PARAM = "--loggroups-jar"
-        private const val VIEWER_CONFIG_JSON_PARAM = "--viewer-conf"
+        private const val VIEWER_CONFIG_PARAM = "--viewer-config"
+        private const val VIEWER_CONFIG_TYPE_PARAM = "--viewer-config-type"
         private const val OUTPUT_SOURCE_JAR_PARAM = "--output-srcjar"
-        private val parameters = setOf(PROTOLOG_CLASS_PARAM, PROTOLOGIMPL_CLASS_PARAM,
-                PROTOLOGCACHE_CLASS_PARAM, PROTOLOGGROUP_CLASS_PARAM, PROTOLOGGROUP_JAR_PARAM,
-                VIEWER_CONFIG_JSON_PARAM, OUTPUT_SOURCE_JAR_PARAM)
+        private const val VIEWER_CONFIG_FILE_PATH_PARAM = "--viewer-config-file-path"
+        // TODO(b/324128613): Remove these legacy options once we fully flip the Perfetto protolog flag
+        private const val LEGACY_VIEWER_CONFIG_FILE_PATH_PARAM = "--legacy-viewer-config-file-path"
+        private const val LEGACY_OUTPUT_FILE_PATH = "--legacy-output-file-path"
+        private val parameters = setOf(PROTOLOG_CLASS_PARAM, PROTOLOGGROUP_CLASS_PARAM,
+            PROTOLOGGROUP_JAR_PARAM, VIEWER_CONFIG_PARAM, VIEWER_CONFIG_TYPE_PARAM,
+            OUTPUT_SOURCE_JAR_PARAM, VIEWER_CONFIG_FILE_PATH_PARAM,
+            LEGACY_VIEWER_CONFIG_FILE_PATH_PARAM, LEGACY_OUTPUT_FILE_PATH)
 
         val USAGE = """
             Usage: ${Constants.NAME} <command> [<args>]
             Available commands:
 
-            $TRANSFORM_CALLS_CMD $PROTOLOG_CLASS_PARAM <class name> $PROTOLOGIMPL_CLASS_PARAM
-                <class name> $PROTOLOGCACHE_CLASS_PARAM
-                <class name> $PROTOLOGGROUP_CLASS_PARAM <class name> $PROTOLOGGROUP_JAR_PARAM
-                <config.jar> $OUTPUT_SOURCE_JAR_PARAM <output.srcjar> [<input.java>]
+            $TRANSFORM_CALLS_CMD $PROTOLOG_CLASS_PARAM <class name>
+                $PROTOLOGGROUP_CLASS_PARAM <class name> $PROTOLOGGROUP_JAR_PARAM <config.jar>
+                $OUTPUT_SOURCE_JAR_PARAM <output.srcjar> [<input.java>]
             - processes java files replacing stub calls with logging code.
 
-            $GENERATE_CONFIG_CMD $PROTOLOG_CLASS_PARAM <class name> $PROTOLOGGROUP_CLASS_PARAM
-                <class name> $PROTOLOGGROUP_JAR_PARAM <config.jar> $VIEWER_CONFIG_JSON_PARAM
-                <viewer.json> [<input.java>]
+            $GENERATE_CONFIG_CMD $PROTOLOG_CLASS_PARAM <class name>
+                $PROTOLOGGROUP_CLASS_PARAM <class name> $PROTOLOGGROUP_JAR_PARAM <config.jar>
+                $VIEWER_CONFIG_PARAM <viewer.json|viewer.pb> [<input.java>]
             - creates viewer config file from given java files.
 
-            $READ_LOG_CMD $VIEWER_CONFIG_JSON_PARAM <viewer.json> <wm_log.pb>
+            $READ_LOG_CMD $VIEWER_CONFIG_PARAM <viewer.json|viewer.pb> <wm_log.pb>
             - translates a binary log to a readable format.
         """.trimIndent()
 
@@ -69,6 +72,13 @@
             return params.getValue(paramName)
         }
 
+        private fun getOptionalParam(paramName: String, params: Map<String, String>): String? {
+            if (!params.containsKey(paramName)) {
+                return null
+            }
+            return params.getValue(paramName)
+        }
+
         private fun validateNotSpecified(paramName: String, params: Map<String, String>): String {
             if (params.containsKey(paramName)) {
                 throw InvalidCommandException("Unsupported param $paramName")
@@ -90,9 +100,43 @@
             return name
         }
 
-        private fun validateJSONName(name: String): String {
-            if (!name.endsWith(".json")) {
-                throw InvalidCommandException("Json file required, got $name instead")
+        private fun validateViewerConfigFilePath(name: String): String {
+            if (!name.endsWith(".pb")) {
+                throw InvalidCommandException("Proto file (ending with .pb) required, " +
+                        "got $name instead")
+            }
+            return name
+        }
+
+        private fun validateLegacyViewerConfigFilePath(name: String): String {
+            if (!name.endsWith(".json.gz")) {
+                throw InvalidCommandException("GZiped Json file (ending with .json.gz) required, " +
+                        "got $name instead")
+            }
+            return name
+        }
+
+        private fun validateOutputFilePath(name: String): String {
+            if (!name.endsWith(".winscope")) {
+                throw InvalidCommandException("Winscope file (ending with .winscope) required, " +
+                        "got $name instead")
+            }
+            return name
+        }
+
+        private fun validateConfigFileName(name: String): String {
+            if (!name.endsWith(".json") && !name.endsWith(".pb")) {
+                throw InvalidCommandException("Json file (ending with .json) or proto file " +
+                        "(ending with .pb) required, got $name instead")
+            }
+            return name
+        }
+
+        private fun validateConfigType(name: String): String {
+            val validType = listOf("json", "proto")
+            if (!validType.contains(name)) {
+                throw InvalidCommandException("Unexpected config file type. " +
+                        "Expected on of [${validType.joinToString()}], but got $name")
             }
             return name
         }
@@ -102,8 +146,8 @@
                 throw InvalidCommandException("No java source input files")
             }
             list.forEach { name ->
-                if (!name.endsWith(".java")) {
-                    throw InvalidCommandException("Not a java source file $name")
+                if (!name.endsWith(".java") && !name.endsWith(".kt")) {
+                    throw InvalidCommandException("Not a java or kotlin source file $name")
                 }
             }
             return list
@@ -122,12 +166,14 @@
 
     val protoLogClassNameArg: String
     val protoLogGroupsClassNameArg: String
-    val protoLogImplClassNameArg: String
-    val protoLogCacheClassNameArg: String
     val protoLogGroupsJarArg: String
-    val viewerConfigJsonArg: String
+    val viewerConfigFileNameArg: String
+    val viewerConfigTypeArg: String
     val outputSourceJarArg: String
     val logProtofileArg: String
+    val viewerConfigFilePathArg: String
+    val legacyViewerConfigFilePathArg: String?
+    val legacyOutputFilePath: String?
     val javaSourceArgs: List<String>
     val command: String
 
@@ -169,38 +215,55 @@
         when (command) {
             TRANSFORM_CALLS_CMD -> {
                 protoLogClassNameArg = validateClassName(getParam(PROTOLOG_CLASS_PARAM, params))
-                protoLogGroupsClassNameArg = validateClassName(getParam(PROTOLOGGROUP_CLASS_PARAM,
-                        params))
-                protoLogImplClassNameArg = validateClassName(getParam(PROTOLOGIMPL_CLASS_PARAM,
-                        params))
-                protoLogCacheClassNameArg = validateClassName(getParam(PROTOLOGCACHE_CLASS_PARAM,
-                        params))
+                protoLogGroupsClassNameArg =
+                    validateClassName(getParam(PROTOLOGGROUP_CLASS_PARAM, params))
                 protoLogGroupsJarArg = validateJarName(getParam(PROTOLOGGROUP_JAR_PARAM, params))
-                viewerConfigJsonArg = validateNotSpecified(VIEWER_CONFIG_JSON_PARAM, params)
+                viewerConfigFileNameArg = validateNotSpecified(VIEWER_CONFIG_PARAM, params)
+                viewerConfigTypeArg = validateNotSpecified(VIEWER_CONFIG_TYPE_PARAM, params)
                 outputSourceJarArg = validateSrcJarName(getParam(OUTPUT_SOURCE_JAR_PARAM, params))
+                viewerConfigFilePathArg = validateViewerConfigFilePath(
+                    getParam(VIEWER_CONFIG_FILE_PATH_PARAM, params))
+                legacyViewerConfigFilePathArg =
+                    getOptionalParam(LEGACY_VIEWER_CONFIG_FILE_PATH_PARAM, params)?.let {
+                        validateLegacyViewerConfigFilePath(it)
+                    }
+                legacyOutputFilePath =
+                    getOptionalParam(LEGACY_OUTPUT_FILE_PATH, params)?.let {
+                        validateOutputFilePath(it)
+                    }
                 javaSourceArgs = validateJavaInputList(inputFiles)
                 logProtofileArg = ""
             }
             GENERATE_CONFIG_CMD -> {
                 protoLogClassNameArg = validateClassName(getParam(PROTOLOG_CLASS_PARAM, params))
-                protoLogGroupsClassNameArg = validateClassName(getParam(PROTOLOGGROUP_CLASS_PARAM,
-                        params))
-                protoLogImplClassNameArg = validateNotSpecified(PROTOLOGIMPL_CLASS_PARAM, params)
-                protoLogCacheClassNameArg = validateNotSpecified(PROTOLOGCACHE_CLASS_PARAM, params)
+                protoLogGroupsClassNameArg =
+                    validateClassName(getParam(PROTOLOGGROUP_CLASS_PARAM, params))
                 protoLogGroupsJarArg = validateJarName(getParam(PROTOLOGGROUP_JAR_PARAM, params))
-                viewerConfigJsonArg = validateJSONName(getParam(VIEWER_CONFIG_JSON_PARAM, params))
+                viewerConfigFileNameArg =
+                    validateConfigFileName(getParam(VIEWER_CONFIG_PARAM, params))
+                viewerConfigTypeArg = validateConfigType(getParam(VIEWER_CONFIG_TYPE_PARAM, params))
                 outputSourceJarArg = validateNotSpecified(OUTPUT_SOURCE_JAR_PARAM, params)
+                viewerConfigFilePathArg =
+                    validateNotSpecified(VIEWER_CONFIG_FILE_PATH_PARAM, params)
+                legacyViewerConfigFilePathArg =
+                    validateNotSpecified(LEGACY_VIEWER_CONFIG_FILE_PATH_PARAM, params)
+                legacyOutputFilePath = validateNotSpecified(LEGACY_OUTPUT_FILE_PATH, params)
                 javaSourceArgs = validateJavaInputList(inputFiles)
                 logProtofileArg = ""
             }
             READ_LOG_CMD -> {
                 protoLogClassNameArg = validateNotSpecified(PROTOLOG_CLASS_PARAM, params)
                 protoLogGroupsClassNameArg = validateNotSpecified(PROTOLOGGROUP_CLASS_PARAM, params)
-                protoLogImplClassNameArg = validateNotSpecified(PROTOLOGIMPL_CLASS_PARAM, params)
-                protoLogCacheClassNameArg = validateNotSpecified(PROTOLOGCACHE_CLASS_PARAM, params)
                 protoLogGroupsJarArg = validateNotSpecified(PROTOLOGGROUP_JAR_PARAM, params)
-                viewerConfigJsonArg = validateJSONName(getParam(VIEWER_CONFIG_JSON_PARAM, params))
+                viewerConfigFileNameArg =
+                    validateConfigFileName(getParam(VIEWER_CONFIG_PARAM, params))
+                viewerConfigTypeArg = validateNotSpecified(VIEWER_CONFIG_TYPE_PARAM, params)
                 outputSourceJarArg = validateNotSpecified(OUTPUT_SOURCE_JAR_PARAM, params)
+                viewerConfigFilePathArg =
+                    validateNotSpecified(VIEWER_CONFIG_FILE_PATH_PARAM, params)
+                legacyViewerConfigFilePathArg =
+                    validateNotSpecified(LEGACY_VIEWER_CONFIG_FILE_PATH_PARAM, params)
+                legacyOutputFilePath = validateNotSpecified(LEGACY_OUTPUT_FILE_PATH, params)
                 javaSourceArgs = listOf()
                 logProtofileArg = validateLogInputList(inputFiles)
             }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/tools/protologtool/src/com/android/protolog/tool/MethodCallVisitor.kt
similarity index 62%
copy from packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
copy to tools/protologtool/src/com/android/protolog/tool/MethodCallVisitor.kt
index b370859..fda6351 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/MethodCallVisitor.kt
@@ -14,14 +14,10 @@
  * limitations under the License.
  */
 
-package com.android.systemui.keyguard.ui.viewmodel
+package com.android.protolog.tool
 
-import com.android.systemui.keyguard.ui.keyguardTransitionAnimationFlow
-import com.android.systemui.kosmos.Kosmos
+import com.github.javaparser.ast.expr.MethodCallExpr
 
-val Kosmos.dreamingToGlanceableHubTransitionViewModel by
-    Kosmos.Fixture {
-        DreamingToGlanceableHubTransitionViewModel(
-            animationFlow = keyguardTransitionAnimationFlow,
-        )
-    }
+interface MethodCallVisitor {
+    fun processCall(call: MethodCallExpr)
+}
diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt
index 9a76a6f..47724b7 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2024 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.
@@ -16,115 +16,13 @@
 
 package com.android.protolog.tool
 
-import com.android.internal.protolog.common.LogLevel
 import com.github.javaparser.ast.CompilationUnit
-import com.github.javaparser.ast.Node
-import com.github.javaparser.ast.expr.Expression
-import com.github.javaparser.ast.expr.FieldAccessExpr
-import com.github.javaparser.ast.expr.MethodCallExpr
-import com.github.javaparser.ast.expr.NameExpr
 
-/**
- * Helper class for visiting all ProtoLog calls.
- * For every valid call in the given {@code CompilationUnit} a {@code ProtoLogCallVisitor} callback
- * is executed.
- */
-open class ProtoLogCallProcessor(
-    private val protoLogClassName: String,
-    private val protoLogGroupClassName: String,
-    private val groupMap: Map<String, LogGroup>
-) {
-    private val protoLogSimpleClassName = protoLogClassName.substringAfterLast('.')
-    private val protoLogGroupSimpleClassName = protoLogGroupClassName.substringAfterLast('.')
-
-    private fun getLogGroupName(
-        expr: Expression,
-        isClassImported: Boolean,
-        staticImports: Set<String>,
+interface ProtoLogCallProcessor {
+    fun process(
+        code: CompilationUnit,
+        logCallVisitor: ProtoLogCallVisitor?,
+        otherCallVisitor: MethodCallVisitor?,
         fileName: String
-    ): String {
-        val context = ParsingContext(fileName, expr)
-        return when (expr) {
-            is NameExpr -> when {
-                expr.nameAsString in staticImports -> expr.nameAsString
-                else ->
-                    throw InvalidProtoLogCallException("Unknown/not imported ProtoLogGroup: $expr",
-                            context)
-            }
-            is FieldAccessExpr -> when {
-                expr.scope.toString() == protoLogGroupClassName
-                        || isClassImported &&
-                        expr.scope.toString() == protoLogGroupSimpleClassName -> expr.nameAsString
-                else ->
-                    throw InvalidProtoLogCallException("Unknown/not imported ProtoLogGroup: $expr",
-                            context)
-            }
-            else -> throw InvalidProtoLogCallException("Invalid group argument " +
-                    "- must be ProtoLogGroup enum member reference: $expr", context)
-        }
-    }
-
-    private fun isProtoCall(
-        call: MethodCallExpr,
-        isLogClassImported: Boolean,
-        staticLogImports: Collection<String>
-    ): Boolean {
-        return call.scope.isPresent && call.scope.get().toString() == protoLogClassName ||
-                isLogClassImported && call.scope.isPresent &&
-                call.scope.get().toString() == protoLogSimpleClassName ||
-                !call.scope.isPresent && staticLogImports.contains(call.name.toString())
-    }
-
-    open fun process(code: CompilationUnit, callVisitor: ProtoLogCallVisitor?, fileName: String):
-            CompilationUnit {
-        CodeUtils.checkWildcardStaticImported(code, protoLogClassName, fileName)
-        CodeUtils.checkWildcardStaticImported(code, protoLogGroupClassName, fileName)
-
-        val isLogClassImported = CodeUtils.isClassImportedOrSamePackage(code, protoLogClassName)
-        val staticLogImports = CodeUtils.staticallyImportedMethods(code, protoLogClassName)
-        val isGroupClassImported = CodeUtils.isClassImportedOrSamePackage(code,
-                protoLogGroupClassName)
-        val staticGroupImports = CodeUtils.staticallyImportedMethods(code, protoLogGroupClassName)
-
-        code.findAll(MethodCallExpr::class.java)
-                .filter { call ->
-                    isProtoCall(call, isLogClassImported, staticLogImports)
-                }.forEach { call ->
-                    val context = ParsingContext(fileName, call)
-                    if (call.arguments.size < 2) {
-                        throw InvalidProtoLogCallException("Method signature does not match " +
-                                "any ProtoLog method: $call", context)
-                    }
-
-                    val messageString = CodeUtils.concatMultilineString(call.getArgument(1),
-                            context)
-                    val groupNameArg = call.getArgument(0)
-                    val groupName =
-                            getLogGroupName(groupNameArg, isGroupClassImported,
-                                    staticGroupImports, fileName)
-                    if (groupName !in groupMap) {
-                        throw InvalidProtoLogCallException("Unknown group argument " +
-                                "- not a ProtoLogGroup enum member: $call", context)
-                    }
-
-                    callVisitor?.processCall(call, messageString, getLevelForMethodName(
-                            call.name.toString(), call, context), groupMap.getValue(groupName))
-                }
-        return code
-    }
-
-    companion object {
-        fun getLevelForMethodName(name: String, node: Node, context: ParsingContext): LogLevel {
-            return when (name) {
-                "d" -> LogLevel.DEBUG
-                "v" -> LogLevel.VERBOSE
-                "i" -> LogLevel.INFO
-                "w" -> LogLevel.WARN
-                "e" -> LogLevel.ERROR
-                "wtf" -> LogLevel.WTF
-                else ->
-                    throw InvalidProtoLogCallException("Unknown log level $name in $node", context)
-            }
-        }
-    }
+    ): CompilationUnit
 }
diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessorImpl.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessorImpl.kt
new file mode 100644
index 0000000..1087ae6
--- /dev/null
+++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessorImpl.kt
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2019 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.protolog.tool
+
+import com.android.internal.protolog.common.LogLevel
+import com.github.javaparser.ast.CompilationUnit
+import com.github.javaparser.ast.expr.Expression
+import com.github.javaparser.ast.expr.FieldAccessExpr
+import com.github.javaparser.ast.expr.MethodCallExpr
+import com.github.javaparser.ast.expr.NameExpr
+
+/**
+ * Helper class for visiting all ProtoLog calls.
+ * For every valid call in the given {@code CompilationUnit} a {@code ProtoLogCallVisitor} callback
+ * is executed.
+ */
+class ProtoLogCallProcessorImpl(
+    private val protoLogClassName: String,
+    private val protoLogGroupClassName: String,
+    private val groupMap: Map<String, LogGroup>
+) : ProtoLogCallProcessor {
+    private val protoLogSimpleClassName = protoLogClassName.substringAfterLast('.')
+    private val protoLogGroupSimpleClassName = protoLogGroupClassName.substringAfterLast('.')
+
+    private fun getLogGroupName(
+        expr: Expression,
+        isClassImported: Boolean,
+        staticImports: Set<String>,
+        fileName: String
+    ): String {
+        val context = ParsingContext(fileName, expr)
+        return when (expr) {
+            is NameExpr -> when {
+                expr.nameAsString in staticImports -> expr.nameAsString
+                else ->
+                    throw InvalidProtoLogCallException("Unknown/not imported ProtoLogGroup: $expr",
+                            context)
+            }
+            is FieldAccessExpr -> when {
+                expr.scope.toString() == protoLogGroupClassName || isClassImported &&
+                        expr.scope.toString() == protoLogGroupSimpleClassName -> expr.nameAsString
+                else ->
+                    throw InvalidProtoLogCallException("Unknown/not imported ProtoLogGroup: $expr",
+                            context)
+            }
+            else -> throw InvalidProtoLogCallException("Invalid group argument " +
+                    "- must be ProtoLogGroup enum member reference: $expr", context)
+        }
+    }
+
+    private fun isProtoCall(
+        call: MethodCallExpr,
+        isLogClassImported: Boolean,
+        staticLogImports: Collection<String>
+    ): Boolean {
+        return call.scope.isPresent && call.scope.get().toString() == protoLogClassName ||
+                isLogClassImported && call.scope.isPresent &&
+                call.scope.get().toString() == protoLogSimpleClassName ||
+                !call.scope.isPresent && staticLogImports.contains(call.name.toString())
+    }
+
+    fun process(code: CompilationUnit, logCallVisitor: ProtoLogCallVisitor?, fileName: String):
+            CompilationUnit {
+        return process(code, logCallVisitor, null, fileName)
+    }
+
+    override fun process(
+        code: CompilationUnit,
+        logCallVisitor: ProtoLogCallVisitor?,
+        otherCallVisitor: MethodCallVisitor?,
+        fileName: String
+    ): CompilationUnit {
+        CodeUtils.checkWildcardStaticImported(code, protoLogClassName, fileName)
+        CodeUtils.checkWildcardStaticImported(code, protoLogGroupClassName, fileName)
+
+        val isLogClassImported = CodeUtils.isClassImportedOrSamePackage(code, protoLogClassName)
+        val staticLogImports = CodeUtils.staticallyImportedMethods(code, protoLogClassName)
+        val isGroupClassImported = CodeUtils.isClassImportedOrSamePackage(code,
+                protoLogGroupClassName)
+        val staticGroupImports = CodeUtils.staticallyImportedMethods(code, protoLogGroupClassName)
+
+        code.findAll(MethodCallExpr::class.java)
+                .filter { call ->
+                    isProtoCall(call, isLogClassImported, staticLogImports)
+                }.forEach { call ->
+                    val context = ParsingContext(fileName, call)
+
+                    val logMethods = LogLevel.entries.map { it.shortCode }
+                    if (logMethods.contains(call.name.id)) {
+                        // Process a log call
+                        if (call.arguments.size < 2) {
+                            throw InvalidProtoLogCallException("Method signature does not match " +
+                                    "any ProtoLog method: $call", context)
+                        }
+
+                        val messageString = CodeUtils.concatMultilineString(call.getArgument(1),
+                            context)
+                        val groupNameArg = call.getArgument(0)
+                        val groupName =
+                            getLogGroupName(groupNameArg, isGroupClassImported,
+                                staticGroupImports, fileName)
+                        if (groupName !in groupMap) {
+                            throw InvalidProtoLogCallException("Unknown group argument " +
+                                    "- not a ProtoLogGroup enum member: $call", context)
+                        }
+
+                        logCallVisitor?.processCall(call, messageString, getLevelForMethodName(
+                            call.name.toString(), call, context), groupMap.getValue(groupName))
+                    } else {
+                        // Process non-log message calls
+                        otherCallVisitor?.processCall(call)
+                    }
+                }
+        return code
+    }
+
+    private fun getLevelForMethodName(
+        name: String,
+        node: MethodCallExpr,
+        context: ParsingContext
+    ): LogLevel = when (name) {
+            "d" -> LogLevel.DEBUG
+            "v" -> LogLevel.VERBOSE
+            "i" -> LogLevel.INFO
+            "w" -> LogLevel.WARN
+            "e" -> LogLevel.ERROR
+            "wtf" -> LogLevel.WTF
+            else ->
+                throw InvalidProtoLogCallException("Unknown log level $name in $node", context)
+        }
+}
diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
index ce856cd..1381847 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt
@@ -16,13 +16,22 @@
 
 package com.android.protolog.tool
 
+import com.android.internal.protolog.common.LogLevel
+import com.android.internal.protolog.common.ProtoLog
+import com.android.internal.protolog.common.ProtoLogToolInjected
 import com.android.protolog.tool.CommandOptions.Companion.USAGE
 import com.github.javaparser.ParseProblemException
 import com.github.javaparser.ParserConfiguration
 import com.github.javaparser.StaticJavaParser
 import com.github.javaparser.ast.CompilationUnit
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration
+import com.github.javaparser.ast.expr.MethodCallExpr
+import com.github.javaparser.ast.expr.NullLiteralExpr
+import com.github.javaparser.ast.expr.SimpleName
+import com.github.javaparser.ast.expr.StringLiteralExpr
 import java.io.File
 import java.io.FileInputStream
+import java.io.FileNotFoundException
 import java.io.FileOutputStream
 import java.io.OutputStream
 import java.time.LocalDateTime
@@ -30,9 +39,21 @@
 import java.util.concurrent.Executors
 import java.util.jar.JarOutputStream
 import java.util.zip.ZipEntry
+import kotlin.math.abs
+import kotlin.random.Random
 import kotlin.system.exitProcess
 
 object ProtoLogTool {
+    const val PROTOLOG_IMPL_SRC_PATH =
+        "frameworks/base/core/java/com/android/internal/protolog/ProtoLogImpl.java"
+
+    data class LogCall(
+        val messageString: String,
+        val logLevel: LogLevel,
+        val logGroup: LogGroup,
+        val position: String
+    )
+
     private fun showHelpAndExit() {
         println(USAGE)
         exitProcess(-1)
@@ -51,26 +72,40 @@
     }
 
     private fun processClasses(command: CommandOptions) {
+        val generationHash = abs(Random.nextInt())
+        // Need to generate a new impl class to inject static constants into the class.
+        val generatedProtoLogImplClass =
+            "com.android.internal.protolog.ProtoLogImpl_$generationHash"
+
         val groups = injector.readLogGroups(
                 command.protoLogGroupsJarArg,
                 command.protoLogGroupsClassNameArg)
         val out = injector.fileOutputStream(command.outputSourceJarArg)
         val outJar = JarOutputStream(out)
-        val processor = ProtoLogCallProcessor(command.protoLogClassNameArg,
-                command.protoLogGroupsClassNameArg, groups)
+        val processor = ProtoLogCallProcessorImpl(
+            command.protoLogClassNameArg,
+            command.protoLogGroupsClassNameArg,
+            groups)
+
+        val protologImplName = generatedProtoLogImplClass.split(".").last()
+        val protologImplPath = "gen/${generatedProtoLogImplClass.split(".")
+                .joinToString("/")}.java"
+        outJar.putNextEntry(zipEntry(protologImplPath))
+
+        outJar.write(generateProtoLogImpl(protologImplName, command.viewerConfigFilePathArg,
+            command.legacyViewerConfigFilePathArg, command.legacyOutputFilePath).toByteArray())
 
         val executor = newThreadPool()
 
         try {
             command.javaSourceArgs.map { path ->
                 executor.submitCallable {
-                    val transformer = SourceTransformer(command.protoLogImplClassNameArg,
-                            command.protoLogCacheClassNameArg, processor)
+                    val transformer = SourceTransformer(generatedProtoLogImplClass, processor)
                     val file = File(path)
                     val text = injector.readText(file)
                     val outSrc = try {
                         val code = tryParse(text, path)
-                        if (containsProtoLogText(text, command.protoLogClassNameArg)) {
+                        if (containsProtoLogText(text, ProtoLog::class.java.simpleName)) {
                             transformer.processClass(text, path, packagePath(file, code), code)
                         } else {
                             text
@@ -93,51 +128,77 @@
             executor.shutdown()
         }
 
-        val cacheSplit = command.protoLogCacheClassNameArg.split(".")
-        val cacheName = cacheSplit.last()
-        val cachePackage = cacheSplit.dropLast(1).joinToString(".")
-        val cachePath = "gen/${cacheSplit.joinToString("/")}.java"
-
-        outJar.putNextEntry(zipEntry(cachePath))
-        outJar.write(generateLogGroupCache(cachePackage, cacheName, groups,
-                command.protoLogImplClassNameArg, command.protoLogGroupsClassNameArg).toByteArray())
-
         outJar.close()
         out.close()
     }
 
-    fun generateLogGroupCache(
-        cachePackage: String,
-        cacheName: String,
-        groups: Map<String, LogGroup>,
-        protoLogImplClassName: String,
-        protoLogGroupsClassName: String
+    private fun generateProtoLogImpl(
+        protoLogImplGenName: String,
+        viewerConfigFilePath: String,
+        legacyViewerConfigFilePath: String?,
+        legacyOutputFilePath: String?,
     ): String {
-        val fields = groups.values.map {
-            "public static boolean ${it.name}_enabled = false;"
-        }.joinToString("\n")
+        val file = File(PROTOLOG_IMPL_SRC_PATH)
 
-        val updates = groups.values.map {
-            "${it.name}_enabled = " +
-                    "$protoLogImplClassName.isEnabled($protoLogGroupsClassName.${it.name});"
-        }.joinToString("\n")
+        val text = try {
+            injector.readText(file)
+        } catch (e: FileNotFoundException) {
+            throw RuntimeException("Expected to find '$PROTOLOG_IMPL_SRC_PATH' but file was not " +
+                    "included in source for the ProtoLog Tool to process.")
+        }
 
-        return """
-            package $cachePackage;
+        val code = tryParse(text, PROTOLOG_IMPL_SRC_PATH)
 
-            public class $cacheName {
-${fields.replaceIndent("                ")}
+        val classDeclarations = code.findAll(ClassOrInterfaceDeclaration::class.java)
+        require(classDeclarations.size == 1) { "Expected exactly one class declaration" }
+        val classDeclaration = classDeclarations[0]
 
-                static {
-                    $protoLogImplClassName.sCacheUpdater = $cacheName::update;
-                    update();
-                }
+        val classNameNode = classDeclaration.findFirst(SimpleName::class.java).get()
+        classNameNode.setId(protoLogImplGenName)
 
-                static void update() {
-${updates.replaceIndent("                    ")}
-                }
-            }
-        """.trimIndent()
+        injectConstants(classDeclaration,
+            viewerConfigFilePath, legacyViewerConfigFilePath, legacyOutputFilePath)
+
+        return code.toString()
+    }
+
+    private fun injectConstants(
+        classDeclaration: ClassOrInterfaceDeclaration,
+        viewerConfigFilePath: String,
+        legacyViewerConfigFilePath: String?,
+        legacyOutputFilePath: String?
+    ) {
+        classDeclaration.fields.forEach { field ->
+            field.getAnnotationByClass(ProtoLogToolInjected::class.java)
+                    .ifPresent { annotationExpr ->
+                        if (annotationExpr.isSingleMemberAnnotationExpr) {
+                            val valueName = annotationExpr.asSingleMemberAnnotationExpr()
+                                    .memberValue.asNameExpr().name.asString()
+                            when (valueName) {
+                                ProtoLogToolInjected.Value.VIEWER_CONFIG_PATH.name -> {
+                                    field.setFinal(true)
+                                    field.variables.first()
+                                            .setInitializer(StringLiteralExpr(viewerConfigFilePath))
+                                }
+                                ProtoLogToolInjected.Value.LEGACY_OUTPUT_FILE_PATH.name -> {
+                                    field.setFinal(true)
+                                    field.variables.first()
+                                            .setInitializer(legacyOutputFilePath?.let {
+                                                StringLiteralExpr(it)
+                                            } ?: NullLiteralExpr())
+                                }
+                                ProtoLogToolInjected.Value.LEGACY_VIEWER_CONFIG_PATH.name -> {
+                                    field.setFinal(true)
+                                    field.variables.first()
+                                            .setInitializer(legacyViewerConfigFilePath?.let {
+                                                StringLiteralExpr(it)
+                                            } ?: NullLiteralExpr())
+                                }
+                                else -> error("Unhandled ProtoLogToolInjected value: $valueName.")
+                            }
+                        }
+                    }
+        }
     }
 
     private fun tryParse(code: String, fileName: String): CompilationUnit {
@@ -145,24 +206,53 @@
             return StaticJavaParser.parse(code)
         } catch (ex: ParseProblemException) {
             val problem = ex.problems.first()
-            throw ParsingException("Java parsing erro" +
-                    "r: ${problem.verboseMessage}",
+            throw ParsingException("Java parsing error: ${problem.verboseMessage}",
                     ParsingContext(fileName, problem.location.orElse(null)
                             ?.begin?.range?.orElse(null)?.begin?.line
                             ?: 0))
         }
     }
 
+    class LogCallRegistry {
+        private val statements = mutableMapOf<LogCall, Long>()
+
+        fun addLogCalls(calls: List<LogCall>) {
+            calls.forEach { logCall ->
+                if (logCall.logGroup.enabled) {
+                    statements.putIfAbsent(logCall,
+                        CodeUtils.hash(logCall.position, logCall.messageString,
+                            logCall.logLevel, logCall.logGroup))
+                }
+            }
+        }
+
+        fun getStatements(): Map<LogCall, Long> {
+            return statements
+        }
+    }
+
+    interface ProtologViewerConfigBuilder {
+        fun build(statements: Map<LogCall, Long>): ByteArray
+    }
+
     private fun viewerConf(command: CommandOptions) {
         val groups = injector.readLogGroups(
                 command.protoLogGroupsJarArg,
                 command.protoLogGroupsClassNameArg)
-        val processor = ProtoLogCallProcessor(command.protoLogClassNameArg,
+        val processor = ProtoLogCallProcessorImpl(command.protoLogClassNameArg,
                 command.protoLogGroupsClassNameArg, groups)
-        val builder = ViewerConfigBuilder(processor)
+        val outputType = command.viewerConfigTypeArg
+
+        val configBuilder: ProtologViewerConfigBuilder = when (outputType.lowercase()) {
+            "json" -> ViewerConfigJsonBuilder()
+            "proto" -> ViewerConfigProtoBuilder()
+            else -> error("Invalid output type provide. Provided '$outputType'.")
+        }
 
         val executor = newThreadPool()
 
+        val logCallRegistry = LogCallRegistry()
+
         try {
             command.javaSourceArgs.map { path ->
                 executor.submitCallable {
@@ -171,7 +261,7 @@
                     if (containsProtoLogText(text, command.protoLogClassNameArg)) {
                         try {
                             val code = tryParse(text, path)
-                            builder.findLogCalls(code, path, packagePath(file, code))
+                            findLogCalls(code, path, packagePath(file, code), processor)
                         } catch (ex: ParsingException) {
                             // If we cannot parse this file, skip it (and log why). Compilation will
                             // fail in a subsequent build step.
@@ -183,15 +273,38 @@
                     }
                 }
             }.forEach { future ->
-                builder.addLogCalls(future.get() ?: return@forEach)
+                logCallRegistry.addLogCalls(future.get() ?: return@forEach)
             }
         } finally {
             executor.shutdown()
         }
 
-        val out = injector.fileOutputStream(command.viewerConfigJsonArg)
-        out.write(builder.build().toByteArray())
-        out.close()
+        val outFile = injector.fileOutputStream(command.viewerConfigFileNameArg)
+        outFile.write(configBuilder.build(logCallRegistry.getStatements()))
+        outFile.close()
+    }
+
+    private fun findLogCalls(
+        unit: CompilationUnit,
+        path: String,
+        packagePath: String,
+        processor: ProtoLogCallProcessorImpl
+    ): List<LogCall> {
+        val calls = mutableListOf<LogCall>()
+        val logCallVisitor = object : ProtoLogCallVisitor {
+            override fun processCall(
+                call: MethodCallExpr,
+                messageString: String,
+                level: LogLevel,
+                group: LogGroup
+            ) {
+                val logCall = LogCall(messageString, level, group, packagePath)
+                calls.add(logCall)
+            }
+        }
+        processor.process(unit, logCallVisitor, path)
+
+        return calls
     }
 
     private fun packagePath(file: File, code: CompilationUnit): String {
@@ -204,7 +317,7 @@
     private fun read(command: CommandOptions) {
         LogParser(ViewerConfigParser())
                 .parse(FileInputStream(command.logProtofileArg),
-                        FileInputStream(command.viewerConfigJsonArg), System.out)
+                        FileInputStream(command.viewerConfigFileNameArg), System.out)
     }
 
     @JvmStatic
diff --git a/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt b/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt
index b50f357..2b71641 100644
--- a/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt
@@ -22,11 +22,11 @@
 import com.github.javaparser.ast.CompilationUnit
 import com.github.javaparser.ast.NodeList
 import com.github.javaparser.ast.body.VariableDeclarator
-import com.github.javaparser.ast.expr.BooleanLiteralExpr
 import com.github.javaparser.ast.expr.CastExpr
 import com.github.javaparser.ast.expr.Expression
 import com.github.javaparser.ast.expr.FieldAccessExpr
 import com.github.javaparser.ast.expr.IntegerLiteralExpr
+import com.github.javaparser.ast.expr.LongLiteralExpr
 import com.github.javaparser.ast.expr.MethodCallExpr
 import com.github.javaparser.ast.expr.NameExpr
 import com.github.javaparser.ast.expr.NullLiteralExpr
@@ -35,7 +35,6 @@
 import com.github.javaparser.ast.expr.VariableDeclarationExpr
 import com.github.javaparser.ast.stmt.BlockStmt
 import com.github.javaparser.ast.stmt.ExpressionStmt
-import com.github.javaparser.ast.stmt.IfStmt
 import com.github.javaparser.ast.type.ArrayType
 import com.github.javaparser.ast.type.ClassOrInterfaceType
 import com.github.javaparser.ast.type.PrimitiveType
@@ -45,15 +44,59 @@
 
 class SourceTransformer(
     protoLogImplClassName: String,
-    protoLogCacheClassName: String,
     private val protoLogCallProcessor: ProtoLogCallProcessor
-) : ProtoLogCallVisitor {
-    override fun processCall(
-        call: MethodCallExpr,
-        messageString: String,
-        level: LogLevel,
-        group: LogGroup
-    ) {
+) {
+    private val inlinePrinter: PrettyPrinter
+    private val objectType = StaticJavaParser.parseClassOrInterfaceType("Object")
+
+    init {
+        val config = PrettyPrinterConfiguration()
+        config.endOfLineCharacter = " "
+        config.indentSize = 0
+        config.tabWidth = 1
+        inlinePrinter = PrettyPrinter(config)
+    }
+
+    fun processClass(
+        code: String,
+        path: String,
+        packagePath: String,
+        compilationUnit: CompilationUnit =
+            StaticJavaParser.parse(code)
+    ): String {
+        this.path = path
+        this.packagePath = packagePath
+        processedCode = code.split('\n').toMutableList()
+        offsets = IntArray(processedCode.size)
+        protoLogCallProcessor.process(compilationUnit, protoLogCallVisitor, otherCallVisitor, path)
+        return processedCode.joinToString("\n")
+    }
+
+    private val protoLogImplClassNode =
+            StaticJavaParser.parseExpression<FieldAccessExpr>(protoLogImplClassName)
+    private var processedCode: MutableList<String> = mutableListOf()
+    private var offsets: IntArray = IntArray(0)
+    /** The path of the file being processed, relative to $ANDROID_BUILD_TOP */
+    private var path: String = ""
+    /** The path of the file being processed, relative to the root package */
+    private var packagePath: String = ""
+
+    private val protoLogCallVisitor = object : ProtoLogCallVisitor {
+        override fun processCall(
+            call: MethodCallExpr,
+            messageString: String,
+            level: LogLevel,
+            group: LogGroup
+        ) {
+            validateCall(call)
+            val processedCallStatement =
+                createProcessedCallStatement(call, group, level, messageString)
+            val parentStmt = call.parentNode.get() as ExpressionStmt
+            injectProcessedCallStatementInCode(processedCallStatement, parentStmt)
+        }
+    }
+
+    private fun validateCall(call: MethodCallExpr) {
         // Input format: ProtoLog.e(GROUP, "msg %d", arg)
         if (!call.parentNode.isPresent) {
             // Should never happen
@@ -71,89 +114,79 @@
             throw RuntimeException("Unable to process log call $call " +
                     "- no grandparent node in AST")
         }
-        val ifStmt: IfStmt
-        if (group.enabled) {
-            val hash = CodeUtils.hash(packagePath, messageString, level, group)
-            val newCall = call.clone()
-            if (!group.textEnabled) {
-                // Remove message string if text logging is not enabled by default.
-                // Out: ProtoLog.e(GROUP, null, arg)
-                newCall.arguments[1].replace(NameExpr("null"))
-            }
-            // Insert message string hash as a second argument.
-            // Out: ProtoLog.e(GROUP, 1234, null, arg)
-            newCall.arguments.add(1, IntegerLiteralExpr(hash))
-            val argTypes = LogDataType.parseFormatString(messageString)
-            val typeMask = LogDataType.logDataTypesToBitMask(argTypes)
-            // Insert bitmap representing which Number parameters are to be considered as
-            // floating point numbers.
-            // Out: ProtoLog.e(GROUP, 1234, 0, null, arg)
-            newCall.arguments.add(2, IntegerLiteralExpr(typeMask))
-            // Replace call to a stub method with an actual implementation.
-            // Out: ProtoLogImpl.e(GROUP, 1234, null, arg)
-            newCall.setScope(protoLogImplClassNode)
-            // Create a call to ProtoLog$Cache.GROUP_enabled
-            // Out: com.android.server.protolog.ProtoLog$Cache.GROUP_enabled
-            val isLogEnabled = FieldAccessExpr(protoLogCacheClassNode, "${group.name}_enabled")
-            if (argTypes.size != call.arguments.size - 2) {
-                throw InvalidProtoLogCallException(
-                        "Number of arguments (${argTypes.size} does not mach format" +
-                                " string in: $call", ParsingContext(path, call))
-            }
-            val blockStmt = BlockStmt()
-            if (argTypes.isNotEmpty()) {
-                // Assign every argument to a variable to check its type in compile time
-                // (this is assignment is optimized-out by dex tool, there is no runtime impact)/
-                // Out: long protoLogParam0 = arg
-                argTypes.forEachIndexed { idx, type ->
-                    val varName = "protoLogParam$idx"
-                    val declaration = VariableDeclarator(getASTTypeForDataType(type), varName,
-                            getConversionForType(type)(newCall.arguments[idx + 4].clone()))
-                    blockStmt.addStatement(ExpressionStmt(VariableDeclarationExpr(declaration)))
-                    newCall.setArgument(idx + 4, NameExpr(SimpleName(varName)))
-                }
-            } else {
-                // Assign (Object[])null as the vararg parameter to prevent allocating an empty
-                // object array.
-                val nullArray = CastExpr(ArrayType(objectType), NullLiteralExpr())
-                newCall.addArgument(nullArray)
-            }
-            blockStmt.addStatement(ExpressionStmt(newCall))
-            // Create an IF-statement with the previously created condition.
-            // Out: if (ProtoLogImpl.isEnabled(GROUP)) {
-            //          long protoLogParam0 = arg;
-            //          ProtoLogImpl.e(GROUP, 1234, 0, null, protoLogParam0);
-            //      }
-            ifStmt = IfStmt(isLogEnabled, blockStmt, null)
-        } else {
-            // Surround with if (false).
-            val newCall = parentStmt.clone()
-            ifStmt = IfStmt(BooleanLiteralExpr(false), BlockStmt(NodeList(newCall)), null)
-            newCall.setBlockComment(" ${group.name} is disabled ")
+    }
+
+    private fun createProcessedCallStatement(
+        call: MethodCallExpr,
+        group: LogGroup,
+        level: LogLevel,
+        messageString: String
+    ): BlockStmt {
+        val hash = CodeUtils.hash(packagePath, messageString, level, group)
+        val newCall = call.clone()
+        if (!group.textEnabled) {
+            // Remove message string if text logging is not enabled by default.
+            // Out: ProtoLog.e(GROUP, null, arg)
+            newCall.arguments[1].replace(NameExpr("null"))
         }
+        // Insert message string hash as a second argument.
+        // Out: ProtoLog.e(GROUP, 1234, null, arg)
+        newCall.arguments.add(1, LongLiteralExpr("" + hash + "L"))
+        val argTypes = LogDataType.parseFormatString(messageString)
+        val typeMask = LogDataType.logDataTypesToBitMask(argTypes)
+        // Insert bitmap representing which Number parameters are to be considered as
+        // floating point numbers.
+        // Out: ProtoLog.e(GROUP, 1234, 0, null, arg)
+        newCall.arguments.add(2, IntegerLiteralExpr(typeMask))
+        // Replace call to a stub method with an actual implementation.
+        // Out: ProtoLogImpl.e(GROUP, 1234, null, arg)
+        newCall.setScope(protoLogImplClassNode)
+        if (argTypes.size != call.arguments.size - 2) {
+            throw InvalidProtoLogCallException(
+                "Number of arguments (${argTypes.size} does not match format" +
+                        " string in: $call", ParsingContext(path, call))
+        }
+        val blockStmt = BlockStmt()
+        if (argTypes.isNotEmpty()) {
+            // Assign every argument to a variable to check its type in compile time
+            // (this is assignment is optimized-out by dex tool, there is no runtime impact)/
+            // Out: long protoLogParam0 = arg
+            argTypes.forEachIndexed { idx, type ->
+                val varName = "protoLogParam$idx"
+                val declaration = VariableDeclarator(getASTTypeForDataType(type), varName,
+                    getConversionForType(type)(newCall.arguments[idx + 4].clone()))
+                blockStmt.addStatement(ExpressionStmt(VariableDeclarationExpr(declaration)))
+                newCall.setArgument(idx + 4, NameExpr(SimpleName(varName)))
+            }
+        } else {
+            // Assign (Object[])null as the vararg parameter to prevent allocating an empty
+            // object array.
+            val nullArray = CastExpr(ArrayType(objectType), NullLiteralExpr())
+            newCall.addArgument(nullArray)
+        }
+        blockStmt.addStatement(ExpressionStmt(newCall))
+
+        return blockStmt
+    }
+
+    private fun injectProcessedCallStatementInCode(
+        processedCallStatement: BlockStmt,
+        parentStmt: ExpressionStmt
+    ) {
         // Inline the new statement.
-        val printedIfStmt = inlinePrinter.print(ifStmt)
+        val printedBlockStmt = inlinePrinter.print(processedCallStatement)
         // Append blank lines to preserve line numbering in file (to allow debugging)
         val parentRange = parentStmt.range.get()
         val newLines = parentRange.end.line - parentRange.begin.line
-        val newStmt = printedIfStmt.substringBeforeLast('}') + ("\n".repeat(newLines)) + '}'
+        val newStmt = printedBlockStmt.substringBeforeLast('}') + ("\n".repeat(newLines)) + '}'
         // pre-workaround code, see explanation below
-        /*
-        val inlinedIfStmt = StaticJavaParser.parseStatement(newStmt)
-        LexicalPreservingPrinter.setup(inlinedIfStmt)
-        // Replace the original call.
-        if (!parentStmt.replace(inlinedIfStmt)) {
-            // Should never happen
-            throw RuntimeException("Unable to process log call $call " +
-                    "- unable to replace the call.")
-        }
-        */
+
         /** Workaround for a bug in JavaParser (AST tree invalid after replacing a node when using
          * LexicalPreservingPrinter (https://github.com/javaparser/javaparser/issues/2290).
          * Replace the code below with the one commended-out above one the issue is resolved. */
         if (!parentStmt.range.isPresent) {
             // Should never happen
-            throw RuntimeException("Unable to process log call $call " +
+            throw RuntimeException("Unable to process log call in $parentStmt " +
                     "- unable to replace the call.")
         }
         val range = parentStmt.range.get()
@@ -161,29 +194,38 @@
         val oldLines = processedCode.subList(begin, range.end.line)
         val oldCode = oldLines.joinToString("\n")
         val newCode = oldCode.replaceRange(
-                offsets[begin] + range.begin.column - 1,
-                oldCode.length - oldLines.lastOrNull()!!.length +
-                        range.end.column + offsets[range.end.line - 1], newStmt)
+            offsets[begin] + range.begin.column - 1,
+            oldCode.length - oldLines.lastOrNull()!!.length +
+                    range.end.column + offsets[range.end.line - 1], newStmt)
         newCode.split("\n").forEachIndexed { idx, line ->
             offsets[begin + idx] += line.length - processedCode[begin + idx].length
             processedCode[begin + idx] = line
         }
     }
 
-    private val inlinePrinter: PrettyPrinter
-    private val objectType = StaticJavaParser.parseClassOrInterfaceType("Object")
+    private val otherCallVisitor = object : MethodCallVisitor {
+        override fun processCall(call: MethodCallExpr) {
+            val newCall = call.clone()
+            newCall.setScope(protoLogImplClassNode)
 
-    init {
-        val config = PrettyPrinterConfiguration()
-        config.endOfLineCharacter = " "
-        config.indentSize = 0
-        config.tabWidth = 1
-        inlinePrinter = PrettyPrinter(config)
+            val range = call.range.get()
+            val begin = range.begin.line - 1
+            val oldLines = processedCode.subList(begin, range.end.line)
+            val oldCode = oldLines.joinToString("\n")
+            val newCode = oldCode.replaceRange(
+                offsets[begin] + range.begin.column - 1,
+                oldCode.length - oldLines.lastOrNull()!!.length +
+                        range.end.column + offsets[range.end.line - 1], newCall.toString())
+            newCode.split("\n").forEachIndexed { idx, line ->
+                offsets[begin + idx] += line.length - processedCode[begin + idx].length
+                processedCode[begin + idx] = line
+            }
+        }
     }
 
     companion object {
         private val stringType: ClassOrInterfaceType =
-                StaticJavaParser.parseClassOrInterfaceType("String")
+            StaticJavaParser.parseClassOrInterfaceType("String")
 
         fun getASTTypeForDataType(type: Int): Type {
             return when (type) {
@@ -202,36 +244,10 @@
             return when (type) {
                 LogDataType.STRING -> { expr ->
                     MethodCallExpr(TypeExpr(StaticJavaParser.parseClassOrInterfaceType("String")),
-                            SimpleName("valueOf"), NodeList(expr))
+                        SimpleName("valueOf"), NodeList(expr))
                 }
                 else -> { expr -> expr }
             }
         }
     }
-
-    private val protoLogImplClassNode =
-            StaticJavaParser.parseExpression<FieldAccessExpr>(protoLogImplClassName)
-    private val protoLogCacheClassNode =
-            StaticJavaParser.parseExpression<FieldAccessExpr>(protoLogCacheClassName)
-    private var processedCode: MutableList<String> = mutableListOf()
-    private var offsets: IntArray = IntArray(0)
-    /** The path of the file being processed, relative to $ANDROID_BUILD_TOP */
-    private var path: String = ""
-    /** The path of the file being processed, relative to the root package */
-    private var packagePath: String = ""
-
-    fun processClass(
-        code: String,
-        path: String,
-        packagePath: String,
-        compilationUnit: CompilationUnit =
-               StaticJavaParser.parse(code)
-    ): String {
-        this.path = path
-        this.packagePath = packagePath
-        processedCode = code.split('\n').toMutableList()
-        offsets = IntArray(processedCode.size)
-        protoLogCallProcessor.process(compilationUnit, this, path)
-        return processedCode.joinToString("\n")
-    }
 }
diff --git a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt
deleted file mode 100644
index 0d5d022..0000000
--- a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigBuilder.kt
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2019 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.protolog.tool
-
-import com.android.internal.protolog.common.LogLevel
-import com.android.json.stream.JsonWriter
-import com.github.javaparser.ast.CompilationUnit
-import com.android.protolog.tool.Constants.VERSION
-import com.github.javaparser.ast.expr.MethodCallExpr
-import java.io.StringWriter
-
-class ViewerConfigBuilder(
-    private val processor: ProtoLogCallProcessor
-) {
-    private fun addLogCall(logCall: LogCall, context: ParsingContext) {
-        val group = logCall.logGroup
-        val messageString = logCall.messageString
-        if (group.enabled) {
-            val key = logCall.key()
-            if (statements.containsKey(key)) {
-                if (statements[key] != logCall) {
-                    throw HashCollisionException(
-                            "Please modify the log message \"$messageString\" " +
-                                    "or \"${statements[key]}\" - their hashes are equal.", context)
-                }
-            } else {
-                groups.add(group)
-                statements[key] = logCall
-            }
-        }
-    }
-
-    private val statements: MutableMap<Int, LogCall> = mutableMapOf()
-    private val groups: MutableSet<LogGroup> = mutableSetOf()
-
-    fun findLogCalls(
-        unit: CompilationUnit,
-        path: String,
-        packagePath: String
-    ): List<Pair<LogCall, ParsingContext>> {
-        val calls = mutableListOf<Pair<LogCall, ParsingContext>>()
-        val visitor = object : ProtoLogCallVisitor {
-            override fun processCall(
-                call: MethodCallExpr,
-                messageString: String,
-                level: LogLevel,
-                group: LogGroup
-            ) {
-                val logCall = LogCall(messageString, level, group, packagePath)
-                val context = ParsingContext(path, call)
-                calls.add(logCall to context)
-            }
-        }
-        processor.process(unit, visitor, path)
-
-        return calls
-    }
-
-    fun addLogCalls(calls: List<Pair<LogCall, ParsingContext>>) {
-        calls.forEach { (logCall, context) ->
-            addLogCall(logCall, context)
-        }
-    }
-
-    fun build(): String {
-        val stringWriter = StringWriter()
-        val writer = JsonWriter(stringWriter)
-        writer.setIndent("  ")
-        writer.beginObject()
-        writer.name("version")
-        writer.value(VERSION)
-        writer.name("messages")
-        writer.beginObject()
-        statements.toSortedMap().forEach { (key, value) ->
-            writer.name(key.toString())
-            writer.beginObject()
-            writer.name("message")
-            writer.value(value.messageString)
-            writer.name("level")
-            writer.value(value.logLevel.name)
-            writer.name("group")
-            writer.value(value.logGroup.name)
-            writer.name("at")
-            writer.value(value.position)
-            writer.endObject()
-        }
-        writer.endObject()
-        writer.name("groups")
-        writer.beginObject()
-        groups.toSortedSet(Comparator { o1, o2 -> o1.name.compareTo(o2.name) }).forEach { group ->
-            writer.name(group.name)
-            writer.beginObject()
-            writer.name("tag")
-            writer.value(group.tag)
-            writer.endObject()
-        }
-        writer.endObject()
-        writer.endObject()
-        stringWriter.buffer.append('\n')
-        return stringWriter.toString()
-    }
-
-    data class LogCall(
-        val messageString: String,
-        val logLevel: LogLevel,
-        val logGroup: LogGroup,
-        val position: String
-    ) {
-        fun key() = CodeUtils.hash(position, messageString, logLevel, logGroup)
-    }
-}
diff --git a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigJsonBuilder.kt b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigJsonBuilder.kt
new file mode 100644
index 0000000..7714db2
--- /dev/null
+++ b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigJsonBuilder.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2024 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.protolog.tool
+
+import com.android.json.stream.JsonWriter
+import com.android.protolog.tool.Constants.VERSION
+import java.io.StringWriter
+
+class ViewerConfigJsonBuilder : ProtoLogTool.ProtologViewerConfigBuilder {
+    override fun build(statements: Map<ProtoLogTool.LogCall, Long>): ByteArray {
+        val groups = statements.map { it.key.logGroup }.toSet()
+        val stringWriter = StringWriter()
+        val writer = JsonWriter(stringWriter)
+        writer.setIndent("  ")
+        writer.beginObject()
+        writer.name("version")
+        writer.value(VERSION)
+        writer.name("messages")
+        writer.beginObject()
+        statements.forEach { (log, key) ->
+            writer.name(key.toString())
+            writer.beginObject()
+            writer.name("message")
+            writer.value(log.messageString)
+            writer.name("level")
+            writer.value(log.logLevel.name)
+            writer.name("group")
+            writer.value(log.logGroup.name)
+            writer.name("at")
+            writer.value(log.position)
+            writer.endObject()
+        }
+        writer.endObject()
+        writer.name("groups")
+        writer.beginObject()
+        groups.toSortedSet { o1, o2 -> o1.name.compareTo(o2.name) }.forEach { group ->
+            writer.name(group.name)
+            writer.beginObject()
+            writer.name("tag")
+            writer.value(group.tag)
+            writer.endObject()
+        }
+        writer.endObject()
+        writer.endObject()
+        stringWriter.buffer.append('\n')
+        return stringWriter.toString().toByteArray()
+    }
+}
diff --git a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigParser.kt b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigParser.kt
index 7278db0..58be3a3 100644
--- a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigParser.kt
+++ b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigParser.kt
@@ -63,12 +63,12 @@
         return GroupEntry(tag)
     }
 
-    fun parseMessages(jsonReader: JsonReader): Map<Int, MessageEntry> {
-        val config: MutableMap<Int, MessageEntry> = mutableMapOf()
+    fun parseMessages(jsonReader: JsonReader): Map<Long, MessageEntry> {
+        val config: MutableMap<Long, MessageEntry> = mutableMapOf()
         jsonReader.beginObject()
         while (jsonReader.hasNext()) {
             val key = jsonReader.nextName()
-            val hash = key.toIntOrNull()
+            val hash = key.toLongOrNull()
                     ?: throw InvalidViewerConfigException("Invalid key in messages viewer config")
             config[hash] = parseMessage(jsonReader)
         }
@@ -89,8 +89,8 @@
 
     data class ConfigEntry(val messageString: String, val level: String, val tag: String)
 
-    open fun parseConfig(jsonReader: JsonReader): Map<Int, ConfigEntry> {
-        var messages: Map<Int, MessageEntry>? = null
+    open fun parseConfig(jsonReader: JsonReader): Map<Long, ConfigEntry> {
+        var messages: Map<Long, MessageEntry>? = null
         var groups: Map<String, GroupEntry>? = null
         var version: String? = null
 
diff --git a/tools/protologtool/src/com/android/protolog/tool/ViewerConfigProtoBuilder.kt b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigProtoBuilder.kt
new file mode 100644
index 0000000..cf0876a
--- /dev/null
+++ b/tools/protologtool/src/com/android/protolog/tool/ViewerConfigProtoBuilder.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2019 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.protolog.tool
+
+import perfetto.protos.PerfettoTrace.ProtoLogLevel
+import perfetto.protos.PerfettoTrace.ProtoLogViewerConfig
+
+/**
+ * A builder class to construct the viewer configuration (i.e. mappings of protolog hashes to log
+ * message information used to decode the protolog messages) encoded as a proto message.
+ */
+class ViewerConfigProtoBuilder : ProtoLogTool.ProtologViewerConfigBuilder {
+    /**
+     * @return a byte array of a ProtoLogViewerConfig proto message encoding all the viewer
+     * configurations mapping protolog hashes to message information and log group information.
+     */
+    override fun build(statements: Map<ProtoLogTool.LogCall, Long>): ByteArray {
+        val configBuilder = ProtoLogViewerConfig.newBuilder()
+
+        val groups = statements.map { it.key.logGroup }.toSet()
+        val groupIds = mutableMapOf<LogGroup, Int>()
+        groups.forEach {
+            groupIds.putIfAbsent(it, groupIds.size + 1)
+        }
+
+        groupIds.forEach { (group, id) ->
+            configBuilder.addGroups(ProtoLogViewerConfig.Group.newBuilder()
+                    .setId(id)
+                    .setName(group.name)
+                    .setTag(group.tag)
+                    .build())
+        }
+
+        statements.forEach { (log, key) ->
+            val groupId = groupIds[log.logGroup] ?: error("missing group id")
+
+            configBuilder.addMessages(
+                ProtoLogViewerConfig.MessageData.newBuilder()
+                        .setMessageId(key)
+                        .setMessage(log.messageString)
+                        .setLevel(
+                            ProtoLogLevel.forNumber(log.logLevel.ordinal + 1))
+                        .setGroupId(groupId)
+            )
+        }
+
+        return configBuilder.build().toByteArray()
+    }
+}
diff --git a/tools/protologtool/tests/com/android/protolog/tool/CodeUtilsTest.kt b/tools/protologtool/tests/com/android/protolog/tool/CodeUtilsTest.kt
index b08d859..0cd02a5c 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/CodeUtilsTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/CodeUtilsTest.kt
@@ -28,31 +28,31 @@
 class CodeUtilsTest {
     @Test
     fun hash() {
-        assertEquals(-1259556708, CodeUtils.hash("Test.java:50", "test",
+        assertEquals(3883826472308915399, CodeUtils.hash("Test.java:50", "test",
                 LogLevel.DEBUG, LogGroup("test", true, true, "TAG")))
     }
 
     @Test
     fun hash_changeLocation() {
-        assertEquals(15793504, CodeUtils.hash("Test.java:10", "test2",
+        assertEquals(4125273133972468649, CodeUtils.hash("Test.java:10", "test2",
                 LogLevel.DEBUG, LogGroup("test", true, true, "TAG")))
     }
 
     @Test
     fun hash_changeLevel() {
-        assertEquals(-731772463, CodeUtils.hash("Test.java:50", "test",
+        assertEquals(2618535069521361990, CodeUtils.hash("Test.java:50", "test",
                 LogLevel.ERROR, LogGroup("test", true, true, "TAG")))
     }
 
     @Test
     fun hash_changeMessage() {
-        assertEquals(-2026343204, CodeUtils.hash("Test.java:50", "test2",
+        assertEquals(8907822592109789043, CodeUtils.hash("Test.java:50", "test2",
                 LogLevel.DEBUG, LogGroup("test", true, true, "TAG")))
     }
 
     @Test
     fun hash_changeGroup() {
-        assertEquals(1607870166, CodeUtils.hash("Test.java:50", "test2",
+        assertEquals(-1299517016176640015, CodeUtils.hash("Test.java:50", "test2",
                 LogLevel.DEBUG, LogGroup("test2", true, true, "TAG")))
     }
 
diff --git a/tools/protologtool/tests/com/android/protolog/tool/CommandOptionsTest.kt b/tools/protologtool/tests/com/android/protolog/tool/CommandOptionsTest.kt
index 3cfbb43..5ef2833 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/CommandOptionsTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/CommandOptionsTest.kt
@@ -16,7 +16,9 @@
 
 package com.android.protolog.tool
 
+import com.google.common.truth.Truth.assertThat
 import org.junit.Assert.assertEquals
+import org.junit.Assert.assertThrows
 import org.junit.Test
 
 class CommandOptionsTest {
@@ -35,6 +37,10 @@
         private const val TEST_PROTOLOGGROUP_JAR = "out/soong/.intermediates/frameworks/base/" +
                 "services/core/services.core.wm.protologgroups/android_common/javac/" +
                 "services.core.wm.protologgroups.jar"
+        private const val TEST_VIEWER_CONFIG_FILE_PATH = "/some/viewer/config/file/path.pb"
+        private const val TEST_LEGACY_VIEWER_CONFIG_FILE_PATH =
+            "/some/viewer/config/file/path.json.gz"
+        private const val TEST_LEGACY_OUTPUT_FILE_PATH = "/some/output/file/path.winscope"
         private const val TEST_SRC_JAR = "out/soong/.temp/sbox175955373/" +
                 "services.core.wm.protolog.srcjar"
         private const val TEST_VIEWER_JSON = "out/soong/.temp/sbox175955373/" +
@@ -42,186 +48,263 @@
         private const val TEST_LOG = "./test_log.pb"
     }
 
-    @Test(expected = InvalidCommandException::class)
+    @Test
     fun noCommand() {
-        CommandOptions(arrayOf())
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(arrayOf())
+        }
+        assertThat(exception).hasMessageThat().contains("No command specified")
     }
 
-    @Test(expected = InvalidCommandException::class)
+    @Test
     fun invalidCommand() {
         val testLine = "invalid"
-        CommandOptions(testLine.split(' ').toTypedArray())
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat().contains("Unknown command")
     }
 
     @Test
     fun transformClasses() {
-        val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
-                "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " +
-                "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " +
+        val testLine = "transform-protolog-calls " +
+                "--protolog-class $TEST_PROTOLOG_CLASS " +
                 "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
                 "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
+                "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " +
                 "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
         val cmd = CommandOptions(testLine.split(' ').toTypedArray())
         assertEquals(CommandOptions.TRANSFORM_CALLS_CMD, cmd.command)
         assertEquals(TEST_PROTOLOG_CLASS, cmd.protoLogClassNameArg)
-        assertEquals(TEST_PROTOLOGIMPL_CLASS, cmd.protoLogImplClassNameArg)
         assertEquals(TEST_PROTOLOGGROUP_CLASS, cmd.protoLogGroupsClassNameArg)
         assertEquals(TEST_PROTOLOGGROUP_JAR, cmd.protoLogGroupsJarArg)
+        assertEquals(TEST_VIEWER_CONFIG_FILE_PATH, cmd.viewerConfigFilePathArg)
+        assertEquals(TEST_LEGACY_VIEWER_CONFIG_FILE_PATH, cmd.legacyViewerConfigFilePathArg)
+        assertEquals(TEST_LEGACY_OUTPUT_FILE_PATH, cmd.legacyOutputFilePath)
         assertEquals(TEST_SRC_JAR, cmd.outputSourceJarArg)
         assertEquals(TEST_JAVA_SRC, cmd.javaSourceArgs)
     }
 
-    @Test(expected = InvalidCommandException::class)
+    @Test
+    fun transformClasses_noViewerConfigFile() {
+        val testLine = "transform-protolog-calls " +
+                "--protolog-class $TEST_PROTOLOG_CLASS " +
+                "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
+                "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
+                "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " +
+                "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat().contains("--viewer-config-file-path")
+    }
+
+    @Test
+    fun transformClasses_noLegacyViewerConfigFile() {
+        val testLine = "transform-protolog-calls " +
+                "--protolog-class $TEST_PROTOLOG_CLASS " +
+                "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
+                "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
+                "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " +
+                "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
+        val cmd = CommandOptions(testLine.split(' ').toTypedArray())
+        assertEquals(CommandOptions.TRANSFORM_CALLS_CMD, cmd.command)
+        assertEquals(TEST_PROTOLOG_CLASS, cmd.protoLogClassNameArg)
+        assertEquals(TEST_PROTOLOGGROUP_CLASS, cmd.protoLogGroupsClassNameArg)
+        assertEquals(TEST_PROTOLOGGROUP_JAR, cmd.protoLogGroupsJarArg)
+        assertEquals(TEST_VIEWER_CONFIG_FILE_PATH, cmd.viewerConfigFilePathArg)
+        assertEquals(null, cmd.legacyViewerConfigFilePathArg)
+        assertEquals(TEST_LEGACY_OUTPUT_FILE_PATH, cmd.legacyOutputFilePath)
+        assertEquals(TEST_SRC_JAR, cmd.outputSourceJarArg)
+        assertEquals(TEST_JAVA_SRC, cmd.javaSourceArgs)
+    }
+
+    @Test
+    fun transformClasses_noLegacyOutputFile() {
+        val testLine = "transform-protolog-calls " +
+                "--protolog-class $TEST_PROTOLOG_CLASS " +
+                "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
+                "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
+                "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " +
+                "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
+        val cmd = CommandOptions(testLine.split(' ').toTypedArray())
+        assertEquals(CommandOptions.TRANSFORM_CALLS_CMD, cmd.command)
+        assertEquals(TEST_PROTOLOG_CLASS, cmd.protoLogClassNameArg)
+        assertEquals(TEST_PROTOLOGGROUP_CLASS, cmd.protoLogGroupsClassNameArg)
+        assertEquals(TEST_PROTOLOGGROUP_JAR, cmd.protoLogGroupsJarArg)
+        assertEquals(TEST_VIEWER_CONFIG_FILE_PATH, cmd.viewerConfigFilePathArg)
+        assertEquals(TEST_LEGACY_VIEWER_CONFIG_FILE_PATH, cmd.legacyViewerConfigFilePathArg)
+        assertEquals(null, cmd.legacyOutputFilePath)
+        assertEquals(TEST_SRC_JAR, cmd.outputSourceJarArg)
+        assertEquals(TEST_JAVA_SRC, cmd.javaSourceArgs)
+    }
+
+    @Test
     fun transformClasses_noProtoLogClass() {
         val testLine = "transform-protolog-calls " +
-                "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " +
-                "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " +
                 "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
                 "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
+                "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " +
                 "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
-        CommandOptions(testLine.split(' ').toTypedArray())
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat().contains("--protolog-class")
     }
 
-    @Test(expected = InvalidCommandException::class)
-    fun transformClasses_noProtoLogImplClass() {
-        val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
-                "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " +
-                "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
-                "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
-                "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
-        CommandOptions(testLine.split(' ').toTypedArray())
-    }
-
-    @Test(expected = InvalidCommandException::class)
-    fun transformClasses_noProtoLogCacheClass() {
-        val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
-                "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " +
-                "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
-                "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
-                "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
-        CommandOptions(testLine.split(' ').toTypedArray())
-    }
-
-    @Test(expected = InvalidCommandException::class)
+    @Test
     fun transformClasses_noProtoLogGroupClass() {
-        val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
-                "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " +
-                "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " +
+        val testLine = "transform-protolog-calls " +
+                "--protolog-class $TEST_PROTOLOG_CLASS " +
                 "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
+                "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " +
                 "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
-        CommandOptions(testLine.split(' ').toTypedArray())
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat().contains("--loggroups-class")
     }
 
-    @Test(expected = InvalidCommandException::class)
+    @Test
     fun transformClasses_noProtoLogGroupJar() {
-        val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
-                "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " +
-                "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " +
+        val testLine = "transform-protolog-calls " +
+                "--protolog-class $TEST_PROTOLOG_CLASS " +
                 "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
+                "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " +
                 "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
-        CommandOptions(testLine.split(' ').toTypedArray())
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat().contains("--loggroups-jar")
     }
 
-    @Test(expected = InvalidCommandException::class)
+    @Test
     fun transformClasses_noOutJar() {
-        val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
-                "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " +
-                "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " +
+        val testLine = "transform-protolog-calls " +
+                "--protolog-class $TEST_PROTOLOG_CLASS " +
                 "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
                 "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
-                TEST_JAVA_SRC.joinToString(" ")
-        CommandOptions(testLine.split(' ').toTypedArray())
+                "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " +
+                "${TEST_JAVA_SRC.joinToString(" ")}"
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat().contains("--output-srcjar")
     }
 
-    @Test(expected = InvalidCommandException::class)
+    @Test
     fun transformClasses_noJavaInput() {
-        val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
-                "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " +
-                "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " +
+        val testLine = "transform-protolog-calls " +
+                "--protolog-class $TEST_PROTOLOG_CLASS " +
                 "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
                 "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
+                "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " +
                 "--output-srcjar $TEST_SRC_JAR"
-        CommandOptions(testLine.split(' ').toTypedArray())
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat().contains("No java source input files")
     }
 
-    @Test(expected = InvalidCommandException::class)
+    @Test
     fun transformClasses_invalidProtoLogClass() {
-        val testLine = "transform-protolog-calls --protolog-class invalid " +
-                "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " +
-                "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " +
+        val testLine = "transform-protolog-calls " +
+                "--protolog-class invalid " +
                 "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
                 "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
+                "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " +
                 "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
-        CommandOptions(testLine.split(' ').toTypedArray())
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat().contains("class name invalid")
     }
 
-    @Test(expected = InvalidCommandException::class)
-    fun transformClasses_invalidProtoLogImplClass() {
-        val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
-                "--protolog-impl-class invalid " +
-                "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " +
-                "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
-                "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
-                "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
-        CommandOptions(testLine.split(' ').toTypedArray())
-    }
-
-    @Test(expected = InvalidCommandException::class)
-    fun transformClasses_invalidProtoLogCacheClass() {
-        val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
-                "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " +
-                "--protolog-cache-class invalid " +
-                "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
-                "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
-                "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
-        CommandOptions(testLine.split(' ').toTypedArray())
-    }
-
-    @Test(expected = InvalidCommandException::class)
+    @Test
     fun transformClasses_invalidProtoLogGroupClass() {
-        val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
-                "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " +
-                "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " +
+        val testLine = "transform-protolog-calls " +
+                "--protolog-class $TEST_PROTOLOG_CLASS " +
                 "--loggroups-class invalid " +
                 "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
+                "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " +
                 "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
-        CommandOptions(testLine.split(' ').toTypedArray())
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat().contains("class name invalid")
     }
 
-    @Test(expected = InvalidCommandException::class)
+    @Test
     fun transformClasses_invalidProtoLogGroupJar() {
-        val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
-                "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " +
-                "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " +
+        val testLine = "transform-protolog-calls " +
+                "--protolog-class $TEST_PROTOLOG_CLASS " +
                 "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
                 "--loggroups-jar invalid.txt " +
+                "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " +
                 "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
-        CommandOptions(testLine.split(' ').toTypedArray())
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat()
+                .contains("Jar file required, got invalid.txt instead")
     }
 
-    @Test(expected = InvalidCommandException::class)
+    @Test
     fun transformClasses_invalidOutJar() {
-        val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
-                "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " +
-                "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " +
+        val testLine = "transform-protolog-calls " +
+                "--protolog-class $TEST_PROTOLOG_CLASS " +
                 "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
                 "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
-                "--output-srcjar invalid.db ${TEST_JAVA_SRC.joinToString(" ")}"
-        CommandOptions(testLine.split(' ').toTypedArray())
+                "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " +
+                "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " +
+                "--output-srcjar invalid.pb ${TEST_JAVA_SRC.joinToString(" ")}"
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat()
+                .contains("Source jar file required, got invalid.pb instead")
     }
 
-    @Test(expected = InvalidCommandException::class)
+    @Test
     fun transformClasses_invalidJavaInput() {
-        val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
-                "--protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " +
-                "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " +
-                "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
-                "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
-                "--output-srcjar $TEST_SRC_JAR invalid.py"
-        CommandOptions(testLine.split(' ').toTypedArray())
+            val testLine = "transform-protolog-calls " +
+                    "--protolog-class $TEST_PROTOLOG_CLASS " +
+                    "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
+                    "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
+                    "--viewer-config-file-path $TEST_VIEWER_CONFIG_FILE_PATH " +
+                    "--legacy-viewer-config-file-path $TEST_LEGACY_VIEWER_CONFIG_FILE_PATH " +
+                    "--legacy-output-file-path $TEST_LEGACY_OUTPUT_FILE_PATH " +
+                    "--output-srcjar $TEST_SRC_JAR invalid.py"
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat()
+                .contains("Not a java or kotlin source file invalid.py")
     }
 
-    @Test(expected = InvalidCommandException::class)
+    @Test
     fun transformClasses_unknownParam() {
         val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
                 "--unknown test --protolog-impl-class $TEST_PROTOLOGIMPL_CLASS " +
@@ -229,59 +312,88 @@
                 "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
                 "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
                 "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
-        CommandOptions(testLine.split(' ').toTypedArray())
-    }
-
-    @Test(expected = InvalidCommandException::class)
-    fun transformClasses_noValue() {
-        val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
-                "--protolog-impl-class " +
-                "--protolog-cache-class $TEST_PROTOLOGCACHE_CLASS " +
-                "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
-                "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
-                "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
-        CommandOptions(testLine.split(' ').toTypedArray())
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat().contains("--unknown")
     }
 
     @Test
-    fun generateConfig() {
-        val testLine = "generate-viewer-config --protolog-class $TEST_PROTOLOG_CLASS " +
+    fun transformClasses_noValue() {
+        val testLine = "transform-protolog-calls --protolog-class $TEST_PROTOLOG_CLASS " +
+                "--loggroups-class " +
+                "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
+                "--output-srcjar $TEST_SRC_JAR ${TEST_JAVA_SRC.joinToString(" ")}"
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat().contains("No value for --loggroups-class")
+    }
+
+    @Test
+    fun generateConfig_json() {
+        val testLine = "generate-viewer-config " +
+                "--protolog-class $TEST_PROTOLOG_CLASS " +
                 "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
                 "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
-                "--viewer-conf $TEST_VIEWER_JSON ${TEST_JAVA_SRC.joinToString(" ")}"
+                "--viewer-config-type json " +
+                "--viewer-config $TEST_VIEWER_JSON ${TEST_JAVA_SRC.joinToString(" ")}"
         val cmd = CommandOptions(testLine.split(' ').toTypedArray())
         assertEquals(CommandOptions.GENERATE_CONFIG_CMD, cmd.command)
         assertEquals(TEST_PROTOLOG_CLASS, cmd.protoLogClassNameArg)
         assertEquals(TEST_PROTOLOGGROUP_CLASS, cmd.protoLogGroupsClassNameArg)
         assertEquals(TEST_PROTOLOGGROUP_JAR, cmd.protoLogGroupsJarArg)
-        assertEquals(TEST_VIEWER_JSON, cmd.viewerConfigJsonArg)
+        assertEquals(TEST_VIEWER_JSON, cmd.viewerConfigFileNameArg)
         assertEquals(TEST_JAVA_SRC, cmd.javaSourceArgs)
     }
 
-    @Test(expected = InvalidCommandException::class)
+    @Test
+    fun generateConfig_proto() {
+        val testLine = "generate-viewer-config " +
+                "--protolog-class $TEST_PROTOLOG_CLASS " +
+                "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
+                "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
+                "--viewer-config-type proto " +
+                "--viewer-config $TEST_VIEWER_JSON ${TEST_JAVA_SRC.joinToString(" ")}"
+        val cmd = CommandOptions(testLine.split(' ').toTypedArray())
+        assertEquals(CommandOptions.GENERATE_CONFIG_CMD, cmd.command)
+        assertEquals(TEST_PROTOLOG_CLASS, cmd.protoLogClassNameArg)
+        assertEquals(TEST_PROTOLOGGROUP_CLASS, cmd.protoLogGroupsClassNameArg)
+        assertEquals(TEST_PROTOLOGGROUP_JAR, cmd.protoLogGroupsJarArg)
+        assertEquals(TEST_VIEWER_JSON, cmd.viewerConfigFileNameArg)
+        assertEquals(TEST_JAVA_SRC, cmd.javaSourceArgs)
+    }
+
+    @Test
     fun generateConfig_noViewerConfig() {
         val testLine = "generate-viewer-config --protolog-class $TEST_PROTOLOG_CLASS " +
                 "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
                 "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
                 TEST_JAVA_SRC.joinToString(" ")
-        CommandOptions(testLine.split(' ').toTypedArray())
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat().contains("--viewer-config required")
     }
 
-    @Test(expected = InvalidCommandException::class)
+    @Test
     fun generateConfig_invalidViewerConfig() {
         val testLine = "generate-viewer-config --protolog-class $TEST_PROTOLOG_CLASS " +
                 "--loggroups-class $TEST_PROTOLOGGROUP_CLASS " +
                 "--loggroups-jar $TEST_PROTOLOGGROUP_JAR " +
-                "--viewer-conf invalid.yaml ${TEST_JAVA_SRC.joinToString(" ")}"
-        CommandOptions(testLine.split(' ').toTypedArray())
+                "--viewer-config invalid.yaml ${TEST_JAVA_SRC.joinToString(" ")}"
+        val exception = assertThrows<InvalidCommandException>(InvalidCommandException::class.java) {
+            CommandOptions(testLine.split(' ').toTypedArray())
+        }
+        assertThat(exception).hasMessageThat().contains("required, got invalid.yaml instead")
     }
 
     @Test
     fun readLog() {
-        val testLine = "read-log --viewer-conf $TEST_VIEWER_JSON $TEST_LOG"
+        val testLine = "read-log --viewer-config $TEST_VIEWER_JSON $TEST_LOG"
         val cmd = CommandOptions(testLine.split(' ').toTypedArray())
         assertEquals(CommandOptions.READ_LOG_CMD, cmd.command)
-        assertEquals(TEST_VIEWER_JSON, cmd.viewerConfigJsonArg)
+        assertEquals(TEST_VIEWER_JSON, cmd.viewerConfigFileNameArg)
         assertEquals(TEST_LOG, cmd.logProtofileArg)
     }
 }
diff --git a/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt b/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt
index 0d2b91d..822118c 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt
@@ -16,22 +16,24 @@
 
 package com.android.protolog.tool
 
-import org.junit.Assert
-import org.junit.Assert.assertTrue
-import org.junit.Test
+import com.android.protolog.tool.ProtoLogTool.PROTOLOG_IMPL_SRC_PATH
+import com.google.common.truth.Truth
 import java.io.ByteArrayInputStream
 import java.io.ByteArrayOutputStream
 import java.io.File
 import java.io.FileNotFoundException
 import java.io.OutputStream
 import java.util.jar.JarInputStream
+import java.util.regex.Pattern
+import org.junit.Assert
+import org.junit.Test
 
 class EndToEndTest {
 
     @Test
     fun e2e_transform() {
         val output = run(
-                src = "frameworks/base/org/example/Example.java" to """
+                srcs = mapOf("frameworks/base/org/example/Example.java" to """
                     package org.example;
                     import com.android.internal.protolog.common.ProtoLog;
                     import static com.android.internal.protolog.ProtoLogGroup.GROUP;
@@ -43,26 +45,29 @@
                             ProtoLog.d(GROUP, "Example: %s %d", argString, argInt);
                         }
                     }
-                """.trimIndent(),
+                """.trimIndent()),
                 logGroup = LogGroup("GROUP", true, false, "TAG_GROUP"),
                 commandOptions = CommandOptions(arrayOf("transform-protolog-calls",
                         "--protolog-class", "com.android.internal.protolog.common.ProtoLog",
-                        "--protolog-impl-class", "com.android.internal.protolog.ProtoLogImpl",
-                        "--protolog-cache-class",
-                        "com.android.server.wm.ProtoLogCache",
                         "--loggroups-class", "com.android.internal.protolog.ProtoLogGroup",
                         "--loggroups-jar", "not_required.jar",
+                        "--viewer-config-file-path", "not_required.pb",
                         "--output-srcjar", "out.srcjar",
                         "frameworks/base/org/example/Example.java"))
         )
         val outSrcJar = assertLoadSrcJar(output, "out.srcjar")
-        assertTrue(" 2066303299," in outSrcJar["frameworks/base/org/example/Example.java"]!!)
+        Truth.assertThat(outSrcJar["frameworks/base/org/example/Example.java"])
+                .containsMatch(Pattern.compile("\\{ String protoLogParam0 = " +
+                        "String\\.valueOf\\(argString\\); long protoLogParam1 = argInt; " +
+                        "com\\.android\\.internal\\.protolog.ProtoLogImpl_.*\\.d\\(" +
+                        "GROUP, -6872339441335321086L, 4, null, protoLogParam0, protoLogParam1" +
+                        "\\); \\}"))
     }
 
     @Test
     fun e2e_viewerConfig() {
         val output = run(
-                src = "frameworks/base/org/example/Example.java" to """
+                srcs = mapOf("frameworks/base/org/example/Example.java" to """
                     package org.example;
                     import com.android.internal.protolog.common.ProtoLog;
                     import static com.android.internal.protolog.ProtoLogGroup.GROUP;
@@ -74,17 +79,27 @@
                             ProtoLog.d(GROUP, "Example: %s %d", argString, argInt);
                         }
                     }
-                """.trimIndent(),
+                """.trimIndent()),
                 logGroup = LogGroup("GROUP", true, false, "TAG_GROUP"),
                 commandOptions = CommandOptions(arrayOf("generate-viewer-config",
                         "--protolog-class", "com.android.internal.protolog.common.ProtoLog",
                         "--loggroups-class", "com.android.internal.protolog.ProtoLogGroup",
                         "--loggroups-jar", "not_required.jar",
-                        "--viewer-conf", "out.json",
+                        "--viewer-config-type", "json",
+                        "--viewer-config", "out.json",
                         "frameworks/base/org/example/Example.java"))
         )
         val viewerConfigJson = assertLoadText(output, "out.json")
-        assertTrue("\"2066303299\"" in viewerConfigJson)
+        Truth.assertThat(viewerConfigJson).contains("""
+            "messages": {
+                "-6872339441335321086": {
+                  "message": "Example: %s %d",
+                  "level": "DEBUG",
+                  "group": "GROUP",
+                  "at": "org\/example\/Example.java"
+                }
+              }
+        """.trimIndent())
     }
 
     private fun assertLoadSrcJar(
@@ -112,21 +127,46 @@
     }
 
     fun run(
-        src: Pair<String, String>,
+        srcs: Map<String, String>,
         logGroup: LogGroup,
         commandOptions: CommandOptions
     ): Map<String, ByteArray> {
         val outputs = mutableMapOf<String, ByteArrayOutputStream>()
 
+        val srcs = srcs.toMutableMap()
+        srcs[PROTOLOG_IMPL_SRC_PATH] = """
+            package com.android.internal.protolog;
+
+            import static com.android.internal.protolog.common.ProtoLogToolInjected.Value.LEGACY_OUTPUT_FILE_PATH;
+            import static com.android.internal.protolog.common.ProtoLogToolInjected.Value.LEGACY_VIEWER_CONFIG_PATH;
+            import static com.android.internal.protolog.common.ProtoLogToolInjected.Value.VIEWER_CONFIG_PATH;
+
+            import com.android.internal.protolog.common.ProtoLogToolInjected;
+
+            public class ProtoLogImpl {
+                @ProtoLogToolInjected(VIEWER_CONFIG_PATH)
+                private static String sViewerConfigPath;
+
+                @ProtoLogToolInjected(LEGACY_VIEWER_CONFIG_PATH)
+                private static String sLegacyViewerConfigPath;
+
+                @ProtoLogToolInjected(LEGACY_OUTPUT_FILE_PATH)
+                private static String sLegacyOutputFilePath;
+            }
+        """.trimIndent()
+
         ProtoLogTool.injector = object : ProtoLogTool.Injector {
             override fun fileOutputStream(file: String): OutputStream =
                     ByteArrayOutputStream().also { outputs[file] = it }
 
             override fun readText(file: File): String {
-                if (file.path == src.first) {
-                    return src.second
+                for (src in srcs.entries) {
+                    val filePath = src.key
+                    if (file.path == filePath) {
+                        return src.value
+                    }
                 }
-                throw FileNotFoundException("expected: ${src.first}, but was $file")
+                throw FileNotFoundException("$file not found in [${srcs.keys.joinToString()}].")
             }
 
             override fun readLogGroups(jarPath: String, className: String) = mapOf(
diff --git a/tools/protologtool/tests/com/android/protolog/tool/LogParserTest.kt b/tools/protologtool/tests/com/android/protolog/tool/LogParserTest.kt
index 512d90c..1d32702 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/LogParserTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/LogParserTest.kt
@@ -35,7 +35,7 @@
 class LogParserTest {
     private val configParser: ViewerConfigParser = mock(ViewerConfigParser::class.java)
     private val parser = LogParser(configParser)
-    private var config: MutableMap<Int, ViewerConfigParser.ConfigEntry> = mutableMapOf()
+    private var config: MutableMap<Long, ViewerConfigParser.ConfigEntry> = mutableMapOf()
     private var outStream: OutputStream = ByteArrayOutputStream()
     private var printStream: PrintStream = PrintStream(outStream)
     private val dateFormat = SimpleDateFormat("MM-dd HH:mm:ss.SSS", Locale.US)
diff --git a/tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorTest.kt b/tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorImplTest.kt
similarity index 96%
rename from tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorTest.kt
rename to tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorImplTest.kt
index 90b8059..5e50f71 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/ProtoLogCallProcessorImplTest.kt
@@ -22,7 +22,7 @@
 import org.junit.Assert.assertEquals
 import org.junit.Test
 
-class ProtoLogCallProcessorTest {
+class ProtoLogCallProcessorImplTest {
     private data class LogCall(
         val call: MethodCallExpr,
         val messageString: String,
@@ -32,8 +32,11 @@
 
     private val groupMap: MutableMap<String, LogGroup> = mutableMapOf()
     private val calls: MutableList<LogCall> = mutableListOf()
-    private val visitor = ProtoLogCallProcessor("org.example.ProtoLog", "org.example.ProtoLogGroup",
-            groupMap)
+    private val visitor = ProtoLogCallProcessorImpl(
+        "org.example.ProtoLog",
+        "org.example.ProtoLogGroup",
+            groupMap
+    )
     private val processor = object : ProtoLogCallVisitor {
         override fun processCall(
             call: MethodCallExpr,
diff --git a/tools/protologtool/tests/com/android/protolog/tool/ProtoLogToolTest.kt b/tools/protologtool/tests/com/android/protolog/tool/ProtoLogToolTest.kt
deleted file mode 100644
index ea9a58d..0000000
--- a/tools/protologtool/tests/com/android/protolog/tool/ProtoLogToolTest.kt
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2019 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.protolog.tool
-
-import org.junit.Assert.assertEquals
-import org.junit.Test
-
-class ProtoLogToolTest {
-
-    @Test
-    fun generateLogGroupCache() {
-        val groups = mapOf(
-                "GROUP1" to LogGroup("GROUP1", true, true, "TAG1"),
-                "GROUP2" to LogGroup("GROUP2", true, true, "TAG2")
-        )
-        val code = ProtoLogTool.generateLogGroupCache("org.example", "ProtoLog\$Cache",
-                groups, "org.example.ProtoLogImpl", "org.example.ProtoLogGroups")
-
-        assertEquals("""
-            package org.example;
-
-            public class ProtoLog${'$'}Cache {
-                public static boolean GROUP1_enabled = false;
-                public static boolean GROUP2_enabled = false;
-
-                static {
-                    org.example.ProtoLogImpl.sCacheUpdater = ProtoLog${'$'}Cache::update;
-                    update();
-                }
-
-                static void update() {
-                    GROUP1_enabled = org.example.ProtoLogImpl.isEnabled(org.example.ProtoLogGroups.GROUP1);
-                    GROUP2_enabled = org.example.ProtoLogImpl.isEnabled(org.example.ProtoLogGroups.GROUP2);
-                }
-            }
-        """.trimIndent(), code)
-    }
-}
\ No newline at end of file
diff --git a/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt b/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt
index f52bfec..de0b5ba 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/SourceTransformerTest.kt
@@ -20,17 +20,14 @@
 import com.github.javaparser.StaticJavaParser
 import com.github.javaparser.ast.CompilationUnit
 import com.github.javaparser.ast.expr.MethodCallExpr
-import com.github.javaparser.ast.stmt.IfStmt
+import com.google.common.truth.Truth
 import org.junit.Assert.assertEquals
-import org.junit.Assert.assertFalse
 import org.junit.Test
 import org.mockito.Mockito
 
 class SourceTransformerTest {
     companion object {
-        private const val PROTO_LOG_IMPL_PATH = "org.example.ProtoLogImpl"
 
-        /* ktlint-disable max-line-length */
         private val TEST_CODE = """
             package org.example;
 
@@ -79,7 +76,7 @@
 
             class Test {
                 void test() {
-                    if (org.example.ProtoLogCache.TEST_GROUP_enabled) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1698911065, 9, "test %d %f", protoLogParam0, protoLogParam1); }
+                    { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, "test %d %f", protoLogParam0, protoLogParam1); }
                 }
             }
             """.trimIndent()
@@ -89,20 +86,20 @@
 
             class Test {
                 void test() {
-                    if (org.example.ProtoLogCache.TEST_GROUP_enabled) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, 1780316587, 9, "test %d %f " + "abc %s\n test", protoLogParam0, protoLogParam1, protoLogParam2); 
+                    { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, -4447034859795564700L, 9, "test %d %f " + "abc %s\n test", protoLogParam0, protoLogParam1, protoLogParam2); 
             
             }
                 }
             }
             """.trimIndent()
 
-        private val TRANSFORMED_CODE_MULTICALL_TEXT_ENABLED = """
+        private val TRANSFORMED_CODE_MULTICALL_TEXT = """
             package org.example;
 
             class Test {
                 void test() {
-                    if (org.example.ProtoLogCache.TEST_GROUP_enabled) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1698911065, 9, "test %d %f", protoLogParam0, protoLogParam1); } /* ProtoLog.w(TEST_GROUP, "test %d %f", 100, 0.1); */ if (org.example.ProtoLogCache.TEST_GROUP_enabled) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1698911065, 9, "test %d %f", protoLogParam0, protoLogParam1); }
-                    if (org.example.ProtoLogCache.TEST_GROUP_enabled) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1698911065, 9, "test %d %f", protoLogParam0, protoLogParam1); }
+                    { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, "test %d %f", protoLogParam0, protoLogParam1); } /* ProtoLog.w(TEST_GROUP, "test %d %f", 100, 0.1); */ { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, "test %d %f", protoLogParam0, protoLogParam1); }
+                    { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, "test %d %f", protoLogParam0, protoLogParam1); }
                 }
             }
             """.trimIndent()
@@ -112,7 +109,7 @@
 
             class Test {
                 void test() {
-                    if (org.example.ProtoLogCache.TEST_GROUP_enabled) { org.example.ProtoLogImpl.w(TEST_GROUP, -1741986185, 0, "test", (Object[]) null); }
+                    { org.example.ProtoLogImpl.w(TEST_GROUP, 3218600869538902408L, 0, "test", (Object[]) null); }
                 }
             }
             """.trimIndent()
@@ -122,7 +119,7 @@
 
             class Test {
                 void test() {
-                    if (org.example.ProtoLogCache.TEST_GROUP_enabled) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 1698911065, 9, null, protoLogParam0, protoLogParam1); }
+                    { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, -1473209266730422156L, 9, null, protoLogParam0, protoLogParam1); }
                 }
             }
             """.trimIndent()
@@ -132,43 +129,19 @@
 
             class Test {
                 void test() {
-                    if (org.example.ProtoLogCache.TEST_GROUP_enabled) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, 1780316587, 9, null, protoLogParam0, protoLogParam1, protoLogParam2); 
+                    { long protoLogParam0 = 100; double protoLogParam1 = 0.1; String protoLogParam2 = String.valueOf("test"); org.example.ProtoLogImpl.w(TEST_GROUP, -4447034859795564700L, 9, null, protoLogParam0, protoLogParam1, protoLogParam2); 
             
             }
                 }
             }
             """.trimIndent()
 
-        private val TRANSFORMED_CODE_DISABLED = """
-            package org.example;
-
-            class Test {
-                void test() {
-                    if (false) { /* TEST_GROUP is disabled */ ProtoLog.w(TEST_GROUP, "test %d %f", 100, 0.1); }
-                }
-            }
-            """.trimIndent()
-
-        private val TRANSFORMED_CODE_MULTILINE_DISABLED = """
-            package org.example;
-
-            class Test {
-                void test() {
-                    if (false) { /* TEST_GROUP is disabled */ ProtoLog.w(TEST_GROUP, "test %d %f " + "abc %s\n test", 100, 0.1, "test"); 
-            
-            }
-                }
-            }
-            """.trimIndent()
-        /* ktlint-enable max-line-length */
-
         private const val PATH = "com.example.Test.java"
     }
 
     private val processor: ProtoLogCallProcessor = Mockito.mock(ProtoLogCallProcessor::class.java)
     private val implName = "org.example.ProtoLogImpl"
-    private val cacheName = "org.example.ProtoLogCache"
-    private val sourceJarWriter = SourceTransformer(implName, cacheName, processor)
+    private val sourceJarWriter = SourceTransformer(implName, processor)
 
     private fun <T> any(type: Class<T>): T = Mockito.any<T>(type)
 
@@ -176,9 +149,12 @@
     fun processClass_textEnabled() {
         var code = StaticJavaParser.parse(TEST_CODE)
 
-        Mockito.`when`(processor.process(any(CompilationUnit::class.java),
-                any(ProtoLogCallVisitor::class.java), any(String::class.java)))
-                .thenAnswer { invocation ->
+        Mockito.`when`(processor.process(
+            any(CompilationUnit::class.java),
+            any(ProtoLogCallVisitor::class.java),
+            any(MethodCallVisitor::class.java),
+            any(String::class.java))
+        ).thenAnswer { invocation ->
             val visitor = invocation.arguments[1] as ProtoLogCallVisitor
 
             visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], "test %d %f",
@@ -190,18 +166,15 @@
         val out = sourceJarWriter.processClass(TEST_CODE, PATH, PATH, code)
         code = StaticJavaParser.parse(out)
 
-        val ifStmts = code.findAll(IfStmt::class.java)
-        assertEquals(1, ifStmts.size)
-        val ifStmt = ifStmts[0]
-        assertEquals("$cacheName.TEST_GROUP_enabled", ifStmt.condition.toString())
-        assertFalse(ifStmt.elseStmt.isPresent)
-        assertEquals(3, ifStmt.thenStmt.childNodes.size)
-        val methodCall = ifStmt.thenStmt.findAll(MethodCallExpr::class.java)[0] as MethodCallExpr
-        assertEquals(PROTO_LOG_IMPL_PATH, methodCall.scope.get().toString())
+        val protoLogCalls = code.findAll(MethodCallExpr::class.java).filter {
+            it.scope.orElse(null)?.toString() == implName
+        }
+        Truth.assertThat(protoLogCalls).hasSize(1)
+        val methodCall = protoLogCalls[0] as MethodCallExpr
         assertEquals("w", methodCall.name.asString())
         assertEquals(6, methodCall.arguments.size)
         assertEquals("TEST_GROUP", methodCall.arguments[0].toString())
-        assertEquals("1698911065", methodCall.arguments[1].toString())
+        assertEquals("-1473209266730422156L", methodCall.arguments[1].toString())
         assertEquals(0b1001.toString(), methodCall.arguments[2].toString())
         assertEquals("\"test %d %f\"", methodCall.arguments[3].toString())
         assertEquals("protoLogParam0", methodCall.arguments[4].toString())
@@ -213,9 +186,12 @@
     fun processClass_textEnabledMulticalls() {
         var code = StaticJavaParser.parse(TEST_CODE_MULTICALLS)
 
-        Mockito.`when`(processor.process(any(CompilationUnit::class.java),
-                any(ProtoLogCallVisitor::class.java), any(String::class.java)))
-                .thenAnswer { invocation ->
+        Mockito.`when`(processor.process(
+            any(CompilationUnit::class.java),
+            any(ProtoLogCallVisitor::class.java),
+            any(MethodCallVisitor::class.java),
+            any(String::class.java))
+        ).thenAnswer { invocation ->
             val visitor = invocation.arguments[1] as ProtoLogCallVisitor
 
             val calls = code.findAll(MethodCallExpr::class.java)
@@ -232,32 +208,32 @@
         val out = sourceJarWriter.processClass(TEST_CODE_MULTICALLS, PATH, PATH, code)
         code = StaticJavaParser.parse(out)
 
-        val ifStmts = code.findAll(IfStmt::class.java)
-        assertEquals(3, ifStmts.size)
-        val ifStmt = ifStmts[1]
-        assertEquals("$cacheName.TEST_GROUP_enabled", ifStmt.condition.toString())
-        assertFalse(ifStmt.elseStmt.isPresent)
-        assertEquals(3, ifStmt.thenStmt.childNodes.size)
-        val methodCall = ifStmt.thenStmt.findAll(MethodCallExpr::class.java)[0] as MethodCallExpr
-        assertEquals(PROTO_LOG_IMPL_PATH, methodCall.scope.get().toString())
+        val protoLogCalls = code.findAll(MethodCallExpr::class.java).filter {
+            it.scope.orElse(null)?.toString() == implName
+        }
+        Truth.assertThat(protoLogCalls).hasSize(3)
+        val methodCall = protoLogCalls[0] as MethodCallExpr
         assertEquals("w", methodCall.name.asString())
         assertEquals(6, methodCall.arguments.size)
         assertEquals("TEST_GROUP", methodCall.arguments[0].toString())
-        assertEquals("1698911065", methodCall.arguments[1].toString())
+        assertEquals("-1473209266730422156L", methodCall.arguments[1].toString())
         assertEquals(0b1001.toString(), methodCall.arguments[2].toString())
         assertEquals("\"test %d %f\"", methodCall.arguments[3].toString())
         assertEquals("protoLogParam0", methodCall.arguments[4].toString())
         assertEquals("protoLogParam1", methodCall.arguments[5].toString())
-        assertEquals(TRANSFORMED_CODE_MULTICALL_TEXT_ENABLED, out)
+        assertEquals(TRANSFORMED_CODE_MULTICALL_TEXT, out)
     }
 
     @Test
     fun processClass_textEnabledMultiline() {
         var code = StaticJavaParser.parse(TEST_CODE_MULTILINE)
 
-        Mockito.`when`(processor.process(any(CompilationUnit::class.java),
-                any(ProtoLogCallVisitor::class.java), any(String::class.java)))
-                .thenAnswer { invocation ->
+        Mockito.`when`(processor.process(
+            any(CompilationUnit::class.java),
+            any(ProtoLogCallVisitor::class.java),
+            any(MethodCallVisitor::class.java),
+            any(String::class.java))
+        ).thenAnswer { invocation ->
             val visitor = invocation.arguments[1] as ProtoLogCallVisitor
 
             visitor.processCall(code.findAll(MethodCallExpr::class.java)[0],
@@ -270,18 +246,15 @@
         val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, PATH, code)
         code = StaticJavaParser.parse(out)
 
-        val ifStmts = code.findAll(IfStmt::class.java)
-        assertEquals(1, ifStmts.size)
-        val ifStmt = ifStmts[0]
-        assertEquals("$cacheName.TEST_GROUP_enabled", ifStmt.condition.toString())
-        assertFalse(ifStmt.elseStmt.isPresent)
-        assertEquals(4, ifStmt.thenStmt.childNodes.size)
-        val methodCall = ifStmt.thenStmt.findAll(MethodCallExpr::class.java)[1] as MethodCallExpr
-        assertEquals(PROTO_LOG_IMPL_PATH, methodCall.scope.get().toString())
+        val protoLogCalls = code.findAll(MethodCallExpr::class.java).filter {
+            it.scope.orElse(null)?.toString() == implName
+        }
+        Truth.assertThat(protoLogCalls).hasSize(1)
+        val methodCall = protoLogCalls[0] as MethodCallExpr
         assertEquals("w", methodCall.name.asString())
         assertEquals(7, methodCall.arguments.size)
         assertEquals("TEST_GROUP", methodCall.arguments[0].toString())
-        assertEquals("1780316587", methodCall.arguments[1].toString())
+        assertEquals("-4447034859795564700L", methodCall.arguments[1].toString())
         assertEquals(0b001001.toString(), methodCall.arguments[2].toString())
         assertEquals("protoLogParam0", methodCall.arguments[4].toString())
         assertEquals("protoLogParam1", methodCall.arguments[5].toString())
@@ -293,9 +266,12 @@
     fun processClass_noParams() {
         var code = StaticJavaParser.parse(TEST_CODE_NO_PARAMS)
 
-        Mockito.`when`(processor.process(any(CompilationUnit::class.java),
-                any(ProtoLogCallVisitor::class.java), any(String::class.java)))
-                .thenAnswer { invocation ->
+        Mockito.`when`(processor.process(
+            any(CompilationUnit::class.java),
+            any(ProtoLogCallVisitor::class.java),
+            any(MethodCallVisitor::class.java),
+            any(String::class.java))
+        ).thenAnswer { invocation ->
             val visitor = invocation.arguments[1] as ProtoLogCallVisitor
 
             visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], "test",
@@ -307,18 +283,15 @@
         val out = sourceJarWriter.processClass(TEST_CODE_NO_PARAMS, PATH, PATH, code)
         code = StaticJavaParser.parse(out)
 
-        val ifStmts = code.findAll(IfStmt::class.java)
-        assertEquals(1, ifStmts.size)
-        val ifStmt = ifStmts[0]
-        assertEquals("$cacheName.TEST_GROUP_enabled", ifStmt.condition.toString())
-        assertFalse(ifStmt.elseStmt.isPresent)
-        assertEquals(1, ifStmt.thenStmt.childNodes.size)
-        val methodCall = ifStmt.thenStmt.findAll(MethodCallExpr::class.java)[0] as MethodCallExpr
-        assertEquals(PROTO_LOG_IMPL_PATH, methodCall.scope.get().toString())
+        val protoLogCalls = code.findAll(MethodCallExpr::class.java).filter {
+            it.scope.orElse(null)?.toString() == implName
+        }
+        Truth.assertThat(protoLogCalls).hasSize(1)
+        val methodCall = protoLogCalls[0] as MethodCallExpr
         assertEquals("w", methodCall.name.asString())
         assertEquals(5, methodCall.arguments.size)
         assertEquals("TEST_GROUP", methodCall.arguments[0].toString())
-        assertEquals("-1741986185", methodCall.arguments[1].toString())
+        assertEquals("3218600869538902408L", methodCall.arguments[1].toString())
         assertEquals(0.toString(), methodCall.arguments[2].toString())
         assertEquals(TRANSFORMED_CODE_NO_PARAMS, out)
     }
@@ -327,9 +300,12 @@
     fun processClass_textDisabled() {
         var code = StaticJavaParser.parse(TEST_CODE)
 
-        Mockito.`when`(processor.process(any(CompilationUnit::class.java),
-                any(ProtoLogCallVisitor::class.java), any(String::class.java)))
-                .thenAnswer { invocation ->
+        Mockito.`when`(processor.process(
+            any(CompilationUnit::class.java),
+            any(ProtoLogCallVisitor::class.java),
+            any(MethodCallVisitor::class.java),
+            any(String::class.java))
+        ).thenAnswer { invocation ->
             val visitor = invocation.arguments[1] as ProtoLogCallVisitor
 
             visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], "test %d %f",
@@ -341,18 +317,15 @@
         val out = sourceJarWriter.processClass(TEST_CODE, PATH, PATH, code)
         code = StaticJavaParser.parse(out)
 
-        val ifStmts = code.findAll(IfStmt::class.java)
-        assertEquals(1, ifStmts.size)
-        val ifStmt = ifStmts[0]
-        assertEquals("$cacheName.TEST_GROUP_enabled", ifStmt.condition.toString())
-        assertFalse(ifStmt.elseStmt.isPresent)
-        assertEquals(3, ifStmt.thenStmt.childNodes.size)
-        val methodCall = ifStmt.thenStmt.findAll(MethodCallExpr::class.java)[0] as MethodCallExpr
-        assertEquals(PROTO_LOG_IMPL_PATH, methodCall.scope.get().toString())
+        val protoLogCalls = code.findAll(MethodCallExpr::class.java).filter {
+            it.scope.orElse(null)?.toString() == implName
+        }
+        Truth.assertThat(protoLogCalls).hasSize(1)
+        val methodCall = protoLogCalls[0] as MethodCallExpr
         assertEquals("w", methodCall.name.asString())
         assertEquals(6, methodCall.arguments.size)
         assertEquals("TEST_GROUP", methodCall.arguments[0].toString())
-        assertEquals("1698911065", methodCall.arguments[1].toString())
+        assertEquals("-1473209266730422156L", methodCall.arguments[1].toString())
         assertEquals(0b1001.toString(), methodCall.arguments[2].toString())
         assertEquals("null", methodCall.arguments[3].toString())
         assertEquals("protoLogParam0", methodCall.arguments[4].toString())
@@ -364,9 +337,12 @@
     fun processClass_textDisabledMultiline() {
         var code = StaticJavaParser.parse(TEST_CODE_MULTILINE)
 
-        Mockito.`when`(processor.process(any(CompilationUnit::class.java),
-                any(ProtoLogCallVisitor::class.java), any(String::class.java)))
-                .thenAnswer { invocation ->
+        Mockito.`when`(processor.process(
+            any(CompilationUnit::class.java),
+            any(ProtoLogCallVisitor::class.java),
+            any(MethodCallVisitor::class.java),
+            any(String::class.java))
+        ).thenAnswer { invocation ->
             val visitor = invocation.arguments[1] as ProtoLogCallVisitor
 
             visitor.processCall(code.findAll(MethodCallExpr::class.java)[0],
@@ -379,18 +355,15 @@
         val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, PATH, code)
         code = StaticJavaParser.parse(out)
 
-        val ifStmts = code.findAll(IfStmt::class.java)
-        assertEquals(1, ifStmts.size)
-        val ifStmt = ifStmts[0]
-        assertEquals("$cacheName.TEST_GROUP_enabled", ifStmt.condition.toString())
-        assertFalse(ifStmt.elseStmt.isPresent)
-        assertEquals(4, ifStmt.thenStmt.childNodes.size)
-        val methodCall = ifStmt.thenStmt.findAll(MethodCallExpr::class.java)[1] as MethodCallExpr
-        assertEquals(PROTO_LOG_IMPL_PATH, methodCall.scope.get().toString())
+        val protoLogCalls = code.findAll(MethodCallExpr::class.java).filter {
+            it.scope.orElse(null)?.toString() == implName
+        }
+        Truth.assertThat(protoLogCalls).hasSize(1)
+        val methodCall = protoLogCalls[0] as MethodCallExpr
         assertEquals("w", methodCall.name.asString())
         assertEquals(7, methodCall.arguments.size)
         assertEquals("TEST_GROUP", methodCall.arguments[0].toString())
-        assertEquals("1780316587", methodCall.arguments[1].toString())
+        assertEquals("-4447034859795564700L", methodCall.arguments[1].toString())
         assertEquals(0b001001.toString(), methodCall.arguments[2].toString())
         assertEquals("null", methodCall.arguments[3].toString())
         assertEquals("protoLogParam0", methodCall.arguments[4].toString())
@@ -398,55 +371,4 @@
         assertEquals("protoLogParam2", methodCall.arguments[6].toString())
         assertEquals(TRANSFORMED_CODE_MULTILINE_TEXT_DISABLED, out)
     }
-
-    @Test
-    fun processClass_disabled() {
-        var code = StaticJavaParser.parse(TEST_CODE)
-
-        Mockito.`when`(processor.process(any(CompilationUnit::class.java),
-                any(ProtoLogCallVisitor::class.java), any(String::class.java)))
-                .thenAnswer { invocation ->
-            val visitor = invocation.arguments[1] as ProtoLogCallVisitor
-
-            visitor.processCall(code.findAll(MethodCallExpr::class.java)[0], "test %d %f",
-                    LogLevel.WARN, LogGroup("TEST_GROUP", false, true, "WM_TEST"))
-
-            invocation.arguments[0] as CompilationUnit
-        }
-
-        val out = sourceJarWriter.processClass(TEST_CODE, PATH, PATH, code)
-        code = StaticJavaParser.parse(out)
-
-        val ifStmts = code.findAll(IfStmt::class.java)
-        assertEquals(1, ifStmts.size)
-        val ifStmt = ifStmts[0]
-        assertEquals("false", ifStmt.condition.toString())
-        assertEquals(TRANSFORMED_CODE_DISABLED, out)
-    }
-
-    @Test
-    fun processClass_disabledMultiline() {
-        var code = StaticJavaParser.parse(TEST_CODE_MULTILINE)
-
-        Mockito.`when`(processor.process(any(CompilationUnit::class.java),
-                any(ProtoLogCallVisitor::class.java), any(String::class.java)))
-                .thenAnswer { invocation ->
-            val visitor = invocation.arguments[1] as ProtoLogCallVisitor
-
-            visitor.processCall(code.findAll(MethodCallExpr::class.java)[0],
-                    "test %d %f abc %s\n test", LogLevel.WARN, LogGroup("TEST_GROUP",
-                    false, true, "WM_TEST"))
-
-            invocation.arguments[0] as CompilationUnit
-        }
-
-        val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, PATH, PATH, code)
-        code = StaticJavaParser.parse(out)
-
-        val ifStmts = code.findAll(IfStmt::class.java)
-        assertEquals(1, ifStmts.size)
-        val ifStmt = ifStmts[0]
-        assertEquals("false", ifStmt.condition.toString())
-        assertEquals(TRANSFORMED_CODE_MULTILINE_DISABLED, out)
-    }
 }
diff --git a/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigBuilderTest.kt b/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigJsonBuilderTest.kt
similarity index 66%
rename from tools/protologtool/tests/com/android/protolog/tool/ViewerConfigBuilderTest.kt
rename to tools/protologtool/tests/com/android/protolog/tool/ViewerConfigJsonBuilderTest.kt
index 52dce21..d27ae88 100644
--- a/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigBuilderTest.kt
+++ b/tools/protologtool/tests/com/android/protolog/tool/ViewerConfigJsonBuilderTest.kt
@@ -18,13 +18,12 @@
 
 import com.android.internal.protolog.common.LogLevel
 import com.android.json.stream.JsonReader
-import com.android.protolog.tool.ViewerConfigBuilder.LogCall
+import com.android.protolog.tool.ProtoLogTool.LogCall
+import java.io.StringReader
 import org.junit.Assert.assertEquals
 import org.junit.Test
-import org.mockito.Mockito
-import java.io.StringReader
 
-class ViewerConfigBuilderTest {
+class ViewerConfigJsonBuilderTest {
     companion object {
         private val TAG1 = "WM_TEST"
         private val TAG2 = "WM_DEBUG"
@@ -39,20 +38,22 @@
         private const val PATH = "/tmp/test.java"
     }
 
-    private val configBuilder = ViewerConfigBuilder(Mockito.mock(ProtoLogCallProcessor::class.java))
+    private val configBuilder = ViewerConfigJsonBuilder()
 
-    private fun parseConfig(json: String): Map<Int, ViewerConfigParser.ConfigEntry> {
+    private fun parseConfig(json: String): Map<Long, ViewerConfigParser.ConfigEntry> {
         return ViewerConfigParser().parseConfig(JsonReader(StringReader(json)))
     }
 
     @Test
     fun processClass() {
-        configBuilder.addLogCalls(listOf(
+        val logCallRegistry = ProtoLogTool.LogCallRegistry()
+        logCallRegistry.addLogCalls(listOf(
                 LogCall(TEST1.messageString, LogLevel.INFO, GROUP1, PATH),
                 LogCall(TEST2.messageString, LogLevel.DEBUG, GROUP2, PATH),
-                LogCall(TEST3.messageString, LogLevel.ERROR, GROUP3, PATH)).withContext())
+                LogCall(TEST3.messageString, LogLevel.ERROR, GROUP3, PATH)))
 
-        val parsedConfig = parseConfig(configBuilder.build())
+        val parsedConfig = parseConfig(
+            configBuilder.build(logCallRegistry.getStatements()).toString(Charsets.UTF_8))
         assertEquals(3, parsedConfig.size)
         assertEquals(TEST1, parsedConfig[CodeUtils.hash(PATH,
 	           TEST1.messageString, LogLevel.INFO, GROUP1)])
@@ -64,32 +65,16 @@
 
     @Test
     fun processClass_nonUnique() {
-        configBuilder.addLogCalls(listOf(
+        val logCallRegistry = ProtoLogTool.LogCallRegistry()
+        logCallRegistry.addLogCalls(listOf(
                 LogCall(TEST1.messageString, LogLevel.INFO, GROUP1, PATH),
                 LogCall(TEST1.messageString, LogLevel.INFO, GROUP1, PATH),
-                LogCall(TEST1.messageString, LogLevel.INFO, GROUP1, PATH)).withContext())
+                LogCall(TEST1.messageString, LogLevel.INFO, GROUP1, PATH)))
 
-        val parsedConfig = parseConfig(configBuilder.build())
+        val parsedConfig = parseConfig(
+            configBuilder.build(logCallRegistry.getStatements()).toString(Charsets.UTF_8))
         assertEquals(1, parsedConfig.size)
         assertEquals(TEST1, parsedConfig[CodeUtils.hash(PATH, TEST1.messageString,
-            	   LogLevel.INFO, GROUP1)])
+            LogLevel.INFO, GROUP1)])
     }
-
-    @Test
-    fun processClass_disabled() {
-        configBuilder.addLogCalls(listOf(
-                LogCall(TEST1.messageString, LogLevel.INFO, GROUP1, PATH),
-                LogCall(TEST2.messageString, LogLevel.DEBUG, GROUP_DISABLED, PATH),
-                LogCall(TEST3.messageString, LogLevel.ERROR, GROUP_TEXT_DISABLED, PATH))
-                .withContext())
-
-        val parsedConfig = parseConfig(configBuilder.build())
-        assertEquals(2, parsedConfig.size)
-        assertEquals(TEST1, parsedConfig[CodeUtils.hash(
-                PATH, TEST1.messageString, LogLevel.INFO, GROUP1)])
-        assertEquals(TEST3, parsedConfig[CodeUtils.hash(
-                PATH, TEST3.messageString, LogLevel.ERROR, GROUP_TEXT_DISABLED)])
-    }
-
-    private fun List<LogCall>.withContext() = map { it to ParsingContext() }
 }