Merge "Align the Talkback slider percentage announcement with the UI." into main
diff --git a/core/api/current.txt b/core/api/current.txt
index e9a63f7..17e7d7a 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -19346,7 +19346,7 @@
   public class BiometricManager {
     method @Deprecated @RequiresPermission(android.Manifest.permission.USE_BIOMETRIC) public int canAuthenticate();
     method @RequiresPermission(android.Manifest.permission.USE_BIOMETRIC) public int canAuthenticate(int);
-    method @FlaggedApi("android.hardware.biometrics.last_authentication_time") @RequiresPermission(android.Manifest.permission.USE_BIOMETRIC) public long getLastAuthenticationTime(int);
+    method @RequiresPermission(android.Manifest.permission.USE_BIOMETRIC) public long getLastAuthenticationTime(int);
     method @NonNull @RequiresPermission(android.Manifest.permission.USE_BIOMETRIC) public android.hardware.biometrics.BiometricManager.Strings getStrings(int);
     field public static final int BIOMETRIC_ERROR_HW_UNAVAILABLE = 1; // 0x1
     field @FlaggedApi("android.hardware.biometrics.identity_check_api") public static final int BIOMETRIC_ERROR_IDENTITY_CHECK_NOT_ACTIVE = 20; // 0x14
@@ -19354,7 +19354,7 @@
     field @FlaggedApi("android.hardware.biometrics.identity_check_api") public static final int BIOMETRIC_ERROR_NOT_ENABLED_FOR_APPS = 21; // 0x15
     field public static final int BIOMETRIC_ERROR_NO_HARDWARE = 12; // 0xc
     field public static final int BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED = 15; // 0xf
-    field @FlaggedApi("android.hardware.biometrics.last_authentication_time") public static final long BIOMETRIC_NO_AUTHENTICATION = -1L; // 0xffffffffffffffffL
+    field public static final long BIOMETRIC_NO_AUTHENTICATION = -1L; // 0xffffffffffffffffL
     field public static final int BIOMETRIC_SUCCESS = 0; // 0x0
   }
 
@@ -19407,7 +19407,7 @@
     field public static final int BIOMETRIC_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
     field public static final int BIOMETRIC_ERROR_USER_CANCELED = 10; // 0xa
     field public static final int BIOMETRIC_ERROR_VENDOR = 8; // 0x8
-    field @FlaggedApi("android.hardware.biometrics.last_authentication_time") public static final long BIOMETRIC_NO_AUTHENTICATION = -1L; // 0xffffffffffffffffL
+    field public static final long BIOMETRIC_NO_AUTHENTICATION = -1L; // 0xffffffffffffffffL
   }
 
   public abstract static class BiometricPrompt.AuthenticationCallback {
@@ -21750,6 +21750,7 @@
     field public static final int CHANNEL_IN_X_AXIS = 2048; // 0x800
     field public static final int CHANNEL_IN_Y_AXIS = 4096; // 0x1000
     field public static final int CHANNEL_IN_Z_AXIS = 8192; // 0x2000
+    field @FlaggedApi("android.media.audio.sony_360ra_mpegh_3d_format") public static final int CHANNEL_OUT_13POINT0 = 30136348; // 0x1cbd81c
     field public static final int CHANNEL_OUT_5POINT1 = 252; // 0xfc
     field public static final int CHANNEL_OUT_5POINT1POINT2 = 3145980; // 0x3000fc
     field public static final int CHANNEL_OUT_5POINT1POINT4 = 737532; // 0xb40fc
diff --git a/core/java/android/hardware/biometrics/BiometricConstants.java b/core/java/android/hardware/biometrics/BiometricConstants.java
index 875adbd..7dc6afb 100644
--- a/core/java/android/hardware/biometrics/BiometricConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricConstants.java
@@ -334,6 +334,5 @@
      * Returned from {@link BiometricManager#getLastAuthenticationTime(int)} when there has
      * been no successful authentication for the given authenticator since boot.
      */
-    @FlaggedApi(Flags.FLAG_LAST_AUTHENTICATION_TIME)
     long BIOMETRIC_NO_AUTHENTICATION = -1;
 }
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index c690c67..cefe20c 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -116,7 +116,6 @@
      * Returned from {@link BiometricManager#getLastAuthenticationTime(int)} when no matching
      * successful authentication has been performed since boot.
      */
-    @FlaggedApi(Flags.FLAG_LAST_AUTHENTICATION_TIME)
     public static final long BIOMETRIC_NO_AUTHENTICATION =
             BiometricConstants.BIOMETRIC_NO_AUTHENTICATION;
 
@@ -777,7 +776,6 @@
      */
     @RequiresPermission(USE_BIOMETRIC)
     @ElapsedRealtimeLong
-    @FlaggedApi(Flags.FLAG_LAST_AUTHENTICATION_TIME)
     public long getLastAuthenticationTime(
             @BiometricManager.Authenticators.Types int authenticators) {
         if (authenticators == 0
diff --git a/core/java/android/hardware/biometrics/flags.aconfig b/core/java/android/hardware/biometrics/flags.aconfig
index 73b6417..4815f3e 100644
--- a/core/java/android/hardware/biometrics/flags.aconfig
+++ b/core/java/android/hardware/biometrics/flags.aconfig
@@ -2,14 +2,6 @@
 container: "system"
 
 flag {
-    name: "last_authentication_time"
-    is_exported: true
-    namespace: "wallet_integration"
-    description: "Feature flag for adding getLastAuthenticationTime API to BiometricManager"
-    bug: "301979982"
-}
-
-flag {
   name: "add_key_agreement_crypto_object"
   is_exported: true
   namespace: "biometrics"
diff --git a/core/java/android/os/TestLooperManager.java b/core/java/android/os/TestLooperManager.java
index d451109..ddfa379 100644
--- a/core/java/android/os/TestLooperManager.java
+++ b/core/java/android/os/TestLooperManager.java
@@ -84,17 +84,8 @@
      * interactions with it have completed.
      */
     public Message next() {
-        // Wait for the looper block to come up, to make sure we don't accidentally get
-        // the message for the block.
-        while (!mLooperIsMyLooper && !mLooperBlocked) {
-            synchronized (this) {
-                try {
-                    wait();
-                } catch (InterruptedException e) {
-                }
-            }
-        }
         checkReleased();
+        waitForLooperHolder();
         return mQueue.next();
     }
 
@@ -110,6 +101,7 @@
     @Nullable
     public Message poll() {
         checkReleased();
+        waitForLooperHolder();
         return mQueue.pollForTest();
     }
 
@@ -124,6 +116,7 @@
     @Nullable
     public Long peekWhen() {
         checkReleased();
+        waitForLooperHolder();
         return mQueue.peekWhenForTest();
     }
 
@@ -133,6 +126,7 @@
     @FlaggedApi(Flags.FLAG_MESSAGE_QUEUE_TESTABILITY)
     public boolean isBlockedOnSyncBarrier() {
         checkReleased();
+        waitForLooperHolder();
         return mQueue.isBlockedOnSyncBarrier();
     }
 
@@ -221,6 +215,23 @@
         }
     }
 
+    /**
+     * Waits until the Looper is blocked by the LooperHolder, if one was posted.
+     *
+     * After this method returns, it's guaranteed that the LooperHolder Message
+     * is not in the underlying queue.
+     */
+    private void waitForLooperHolder() {
+        while (!mLooperIsMyLooper && !mLooperBlocked) {
+            synchronized (this) {
+                try {
+                    wait();
+                } catch (InterruptedException e) {
+                }
+            }
+        }
+    }
+
     private class LooperHolder implements Runnable {
         @Override
         public void run() {
diff --git a/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java b/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java
index 1771642..6ed8c6d 100644
--- a/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java
+++ b/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java
@@ -76,22 +76,30 @@
     private IQuickAccessWalletService mService;
 
     @Nullable
-    private final QuickAccessWalletServiceInfo mServiceInfo;
+    private QuickAccessWalletServiceInfo mServiceInfo;
 
     private static final int MSG_TIMEOUT_SERVICE = 5;
 
     QuickAccessWalletClientImpl(@NonNull Context context, @Nullable Executor bgExecutor) {
         mContext = context.getApplicationContext();
-        mServiceInfo = QuickAccessWalletServiceInfo.tryCreate(context);
+        mServiceInfo = null;
         mHandler = new Handler(Looper.getMainLooper());
         mLifecycleExecutor = (bgExecutor == null) ? Runnable::run : bgExecutor;
         mRequestQueue = new ArrayDeque<>();
         mEventListeners = new HashMap<>(1);
     }
 
+    private QuickAccessWalletServiceInfo ensureServiceInfo() {
+        if (mServiceInfo == null) {
+            mServiceInfo = QuickAccessWalletServiceInfo.tryCreate(mContext);
+        }
+
+        return mServiceInfo;
+    }
+
     @Override
     public boolean isWalletServiceAvailable() {
-        return mServiceInfo != null;
+        return ensureServiceInfo() != null;
     }
 
     @Override
@@ -239,12 +247,13 @@
     @Override
     @Nullable
     public Intent createWalletIntent() {
-        if (mServiceInfo == null) {
+        QuickAccessWalletServiceInfo serviceInfo = ensureServiceInfo();
+        if (serviceInfo == null) {
             return null;
         }
-        String packageName = mServiceInfo.getComponentName().getPackageName();
-        int userId = mServiceInfo.getUserId();
-        String walletActivity = mServiceInfo.getWalletActivity();
+        String packageName = serviceInfo.getComponentName().getPackageName();
+        int userId = serviceInfo.getUserId();
+        String walletActivity = serviceInfo.getWalletActivity();
         return createIntent(walletActivity, packageName, userId, ACTION_VIEW_WALLET);
     }
 
@@ -298,11 +307,12 @@
     @Override
     @Nullable
     public Intent createWalletSettingsIntent() {
-        if (mServiceInfo == null) {
+        QuickAccessWalletServiceInfo serviceInfo = ensureServiceInfo();
+        if (serviceInfo == null) {
             return null;
         }
-        String packageName = mServiceInfo.getComponentName().getPackageName();
-        String settingsActivity = mServiceInfo.getSettingsActivity();
+        String packageName = serviceInfo.getComponentName().getPackageName();
+        String settingsActivity = serviceInfo.getSettingsActivity();
         return createIntent(settingsActivity, packageName, UserHandle.myUserId(),
                 ACTION_VIEW_WALLET_SETTINGS);
     }
@@ -356,36 +366,42 @@
     @Override
     @Nullable
     public Drawable getLogo() {
-        return mServiceInfo == null ? null : mServiceInfo.getWalletLogo(mContext);
+        QuickAccessWalletServiceInfo serviceInfo = ensureServiceInfo();
+        return serviceInfo == null ? null : serviceInfo.getWalletLogo(mContext);
     }
 
     @Nullable
     @Override
     public Drawable getTileIcon() {
-        return mServiceInfo == null ? null : mServiceInfo.getTileIcon();
+        QuickAccessWalletServiceInfo serviceInfo = ensureServiceInfo();
+        return serviceInfo == null ? null : serviceInfo.getTileIcon();
     }
 
     @Nullable
     @Override
     public UserHandle getUser() {
-        return mServiceInfo == null ? null : UserHandle.of(mServiceInfo.getUserId());
+        QuickAccessWalletServiceInfo serviceInfo = ensureServiceInfo();
+        return serviceInfo == null ? null : UserHandle.of(serviceInfo.getUserId());
     }
 
     @Override
     @Nullable
     public CharSequence getServiceLabel() {
-        return mServiceInfo == null ? null : mServiceInfo.getServiceLabel(mContext);
+        QuickAccessWalletServiceInfo serviceInfo = ensureServiceInfo();
+        return serviceInfo == null ? null : serviceInfo.getServiceLabel(mContext);
     }
 
     @Override
     @Nullable
     public CharSequence getShortcutShortLabel() {
-        return mServiceInfo == null ? null : mServiceInfo.getShortcutShortLabel(mContext);
+        QuickAccessWalletServiceInfo serviceInfo = ensureServiceInfo();
+        return serviceInfo == null ? null : serviceInfo.getShortcutShortLabel(mContext);
     }
 
     @Override
     public CharSequence getShortcutLongLabel() {
-        return mServiceInfo == null ? null : mServiceInfo.getShortcutLongLabel(mContext);
+        QuickAccessWalletServiceInfo serviceInfo = ensureServiceInfo();
+        return serviceInfo == null ? null : serviceInfo.getShortcutLongLabel(mContext);
     }
 
     private void connect() {
@@ -393,7 +409,8 @@
     }
 
     private void connectInternal() {
-        if (mServiceInfo == null) {
+        QuickAccessWalletServiceInfo serviceInfo = ensureServiceInfo();
+        if (serviceInfo == null) {
             Log.w(TAG, "Wallet service unavailable");
             return;
         }
@@ -402,7 +419,7 @@
         }
         mIsConnected = true;
         Intent intent = new Intent(SERVICE_INTERFACE);
-        intent.setComponent(mServiceInfo.getComponentName());
+        intent.setComponent(serviceInfo.getComponentName());
         int flags = Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY;
         mLifecycleExecutor.execute(() -> mContext.bindService(intent, this, flags));
         resetServiceConnectionTimeout();
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index cd8a85a..bf34069 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -5566,9 +5566,6 @@
             if (mAttachInfo.mContentCaptureManager != null) {
                 ContentCaptureSession session =
                         mAttachInfo.mContentCaptureManager.getMainContentCaptureSession();
-                if (android.view.contentcapture.flags.Flags.postCreateAndroidBgThread()) {
-                    session.performStart();
-                }
                 session.notifyWindowBoundsChanged(session.getId(),
                         getConfiguration().windowConfiguration.getBounds());
             }
diff --git a/core/java/android/view/contentcapture/ChildContentCaptureSession.java b/core/java/android/view/contentcapture/ChildContentCaptureSession.java
index 6e2e100..8baa55f 100644
--- a/core/java/android/view/contentcapture/ChildContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ChildContentCaptureSession.java
@@ -74,8 +74,8 @@
     }
 
     @Override
-    void internalFlush(@FlushReason int reason) {
-        mParent.internalFlush(reason);
+    void flush(@FlushReason int reason) {
+        mParent.flush(reason);
     }
 
     @Override
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index b7a77d7..724e8fa 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -52,6 +52,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.RingBuffer;
 import com.android.internal.util.SyncResultReceiver;
 
@@ -604,6 +605,7 @@
                     mContext,
                     this,
                     prepareUiHandler(),
+                    prepareContentCaptureHandler(),
                     mService
                 );
                 if (sVerbose) Log.v(TAG, "getMainContentCaptureSession(): created " + mMainSession);
@@ -614,6 +616,15 @@
 
     @NonNull
     @GuardedBy("mLock")
+    private Handler prepareContentCaptureHandler() {
+        if (mContentCaptureHandler == null) {
+            mContentCaptureHandler = BackgroundThread.getHandler();
+        }
+        return mContentCaptureHandler;
+    }
+
+    @NonNull
+    @GuardedBy("mLock")
     private Handler prepareUiHandler() {
         if (mUiHandler == null) {
             mUiHandler = Handler.createAsync(Looper.getMainLooper());
@@ -663,7 +674,7 @@
     @UiThread
     public void flush(@FlushReason int reason) {
         if (mOptions.lite) return;
-        getMainContentCaptureSession().internalFlush(reason);
+        getMainContentCaptureSession().flush(reason);
     }
 
     /**
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index 791a6f4..9aeec20 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -286,9 +286,6 @@
     abstract void start(@NonNull IBinder token, @NonNull IBinder shareableActivityToken,
             @NonNull ComponentName component, int flags);
 
-    /** @hide */
-    public void performStart() {}
-
     abstract boolean isDisabled();
 
     /**
@@ -342,7 +339,7 @@
     /**
      * Flushes the buffered events to the service.
      */
-    abstract void internalFlush(@FlushReason int reason);
+    abstract void flush(@FlushReason int reason);
 
     /**
      * Sets the {@link ContentCaptureContext} associated with the session.
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index 29cae85..2fb78c0 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -57,12 +57,10 @@
 import android.view.ViewStructure;
 import android.view.autofill.AutofillId;
 import android.view.contentcapture.ViewNode.ViewStructureImpl;
-import android.view.contentcapture.flags.Flags;
 import android.view.contentprotection.ContentProtectionEventProcessor;
 import android.view.inputmethod.BaseInputConnection;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.os.BackgroundThread;
 import com.android.internal.os.IResultReceiver;
 import com.android.modules.expresslog.Counter;
 
@@ -109,10 +107,8 @@
     @NonNull
     private final Handler mUiHandler;
 
-    /** @hide */
-    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
-    @Nullable
-    public Handler mContentCaptureHandler;
+    @NonNull
+    private final Handler mContentCaptureHandler;
 
     /**
      * Interface to the system_server binder object - it's only used to start the session (and
@@ -191,12 +187,6 @@
     @Nullable
     public ContentProtectionEventProcessor mContentProtectionEventProcessor;
 
-    /**
-     * A runnable object to perform the start of this session.
-     */
-    @Nullable
-    private Runnable mStartRunnable = null;
-
     private static class SessionStateReceiver extends IResultReceiver.Stub {
         private final WeakReference<MainContentCaptureSession> mMainSession;
 
@@ -208,7 +198,7 @@
         public void send(int resultCode, Bundle resultData) {
             final MainContentCaptureSession mainSession = mMainSession.get();
             if (mainSession == null) {
-                Log.w(TAG, "received result after main session released");
+                Log.w(TAG, "received result after mina session released");
                 return;
             }
             final IBinder binder;
@@ -223,8 +213,6 @@
                 binder = resultData.getBinder(EXTRA_BINDER);
                 if (binder == null) {
                     Log.wtf(TAG, "No " + EXTRA_BINDER + " extra result");
-                    // explicitly init the bg thread
-                    mainSession.mContentCaptureHandler = mainSession.prepareContentCaptureHandler();
                     mainSession.runOnContentCaptureThread(() -> mainSession.resetSession(
                             STATE_DISABLED | STATE_INTERNAL_ERROR));
                     return;
@@ -232,45 +220,23 @@
             } else {
                 binder = null;
             }
-            // explicitly init the bg thread
-            mainSession.mContentCaptureHandler = mainSession.prepareContentCaptureHandler();
             mainSession.runOnContentCaptureThread(() ->
                     mainSession.onSessionStarted(resultCode, binder));
         }
     }
 
-    /**
-     * Prepares the content capture handler(i.e. the background thread).
-     *
-     * This is expected to be called from the {@link SessionStateReceiver#send} callback, after the
-     * session {@link performStart}. This is expected to be executed in a binder thread, instead
-     * of the UI thread.
-     */
-    @NonNull
-    private Handler prepareContentCaptureHandler() {
-        if (mContentCaptureHandler == null) {
-            try {
-                if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
-                    Trace.traceBegin(Trace.TRACE_TAG_VIEW, "prepareContentCaptureHandler");
-                }
-                mContentCaptureHandler = BackgroundThread.getHandler();
-            } finally {
-                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
-            }
-        }
-        return mContentCaptureHandler;
-    }
-
     /** @hide */
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED)
     public MainContentCaptureSession(
             @NonNull ContentCaptureManager.StrippedContext context,
             @NonNull ContentCaptureManager manager,
             @NonNull Handler uiHandler,
+            @NonNull Handler contentCaptureHandler,
             @NonNull IContentCaptureManager systemServerInterface) {
         mContext = context;
         mManager = manager;
         mUiHandler = uiHandler;
+        mContentCaptureHandler = contentCaptureHandler;
         mSystemServerInterface = systemServerInterface;
 
         final int logHistorySize = mManager.mOptions.logHistorySize;
@@ -294,49 +260,18 @@
     }
 
     /**
-     * Performs the start of the session.
-     *
-     * This is expected to be called from the UI thread, when the activity finishes its first frame.
-     * This is a no-op if the session has already been started.
-     *
-     * See {@link #start(IBinder, IBinder, ComponentName, int)} for more details.
-     *
-     * @hide */
-    @Override
-    public void performStart() {
-        if (!hasStarted() && mStartRunnable != null) {
-            mStartRunnable.run();
-        }
-    }
-
-    /**
-     * Creates a runnable to start this session.
-     *
-     * For performance reasons, it is better to only create a task to start the session
-     * during the creation of the activity and perform the actual start when the activity
-     * finishes it's first frame.
+     * Starts this session.
      */
     @Override
     void start(@NonNull IBinder token, @NonNull IBinder shareableActivityToken,
             @NonNull ComponentName component, int flags) {
-        if (Flags.postCreateAndroidBgThread()) {
-            mStartRunnable = () -> {
-                try {
-                    if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
-                        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "cc session startImpl");
-                    }
-                    startImpl(token, shareableActivityToken, component, flags);
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_VIEW);
-                }
-            };
-        } else {
-            startImpl(token, shareableActivityToken, component, flags);
-        }
+        runOnContentCaptureThread(
+                () -> startImpl(token, shareableActivityToken, component, flags));
     }
 
     private void startImpl(@NonNull IBinder token, @NonNull IBinder shareableActivityToken,
                @NonNull ComponentName component, int flags) {
+        checkOnContentCaptureThread();
         if (!isContentCaptureEnabled()) return;
 
         if (sVerbose) {
@@ -370,12 +305,11 @@
             Log.w(TAG, "Error starting session for " + component.flattenToShortString() + ": " + e);
         }
     }
-
     @Override
     void onDestroy() {
         clearAndRunOnContentCaptureThread(() -> {
             try {
-                internalFlush(FLUSH_REASON_SESSION_FINISHED);
+                flush(FLUSH_REASON_SESSION_FINISHED);
             } finally {
                 destroySession();
             }
@@ -623,10 +557,11 @@
                 flushReason = forceFlush ? FLUSH_REASON_FORCE_FLUSH : FLUSH_REASON_FULL;
         }
 
-        internalFlush(flushReason);
+        flush(flushReason);
     }
 
     private boolean hasStarted() {
+        checkOnContentCaptureThread();
         return mState != UNKNOWN_STATE;
     }
 
@@ -640,11 +575,6 @@
             if (sVerbose) Log.v(TAG, "handleScheduleFlush(): session not started yet");
             return;
         }
-        if (mContentCaptureHandler == null) {
-            Log.w(TAG, "handleScheduleFlush(" + getDebugState(reason) + "): content capture "
-                    + "thread not ready");
-            return;
-        }
 
         if (mDisabled.get()) {
             // Should not be called on this state, as handleSendEvent checks.
@@ -687,18 +617,15 @@
             if (sVerbose) Log.v(TAG, "Nothing to flush");
             return;
         }
-        internalFlush(reason);
+        flush(reason);
     }
 
-    /**
-     * Internal API to flush the buffered events to the service.
-     *
-     * Do not confuse this with the public API {@link #flush()}.
-     *
-     * @hide */
+    /** @hide */
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
     @Override
-    public void internalFlush(@FlushReason int reason) {
+    public void flush(@FlushReason int reason) {
+        // TODO: b/380381249 renaming the internal APIs to prevent confusions between this and the
+        // public API.
         runOnContentCaptureThread(() -> flushImpl(reason));
     }
 
@@ -720,11 +647,6 @@
         if (!isContentCaptureReceiverEnabled()) {
             return;
         }
-        if (mContentCaptureHandler == null) {
-            Log.w(TAG, "handleForceFlush(" + getDebugState(reason) + "): content capture thread"
-                    + "not ready");
-            return;
-        }
 
         if (mDirectServiceInterface == null) {
             if (sVerbose) {
@@ -841,9 +763,7 @@
         }
         mDirectServiceInterface = null;
         mContentProtectionEventProcessor = null;
-        if (mContentCaptureHandler != null) {
-            mContentCaptureHandler.removeMessages(MSG_FLUSH);
-        }
+        mContentCaptureHandler.removeMessages(MSG_FLUSH);
     }
 
     @Override
@@ -997,10 +917,6 @@
      * clear the buffer events then starting sending out current event.
      */
     private void enqueueEvent(@NonNull final ContentCaptureEvent event, boolean forceFlush) {
-        if (mContentCaptureHandler == null) {
-            mEventProcessQueue.offer(event);
-            return;
-        }
         if (forceFlush || mEventProcessQueue.size() >= mManager.mOptions.maxBufferSize - 1) {
             // The buffer events are cleared in the same thread first to prevent new events
             // being added during the time of context switch. This would disrupt the sequence
@@ -1203,10 +1119,6 @@
      * always delegate to the assigned thread from {@code mHandler} for synchronization.</p>
      */
     private void checkOnContentCaptureThread() {
-        if (mContentCaptureHandler == null) {
-            Log.e(TAG, "content capture thread is not initiallized!");
-            return;
-        }
         final boolean onContentCaptureThread = mContentCaptureHandler.getLooper().isCurrentThread();
         if (!onContentCaptureThread) {
             mWrongThreadCount.incrementAndGet();
@@ -1227,12 +1139,6 @@
      * </p>
      */
     private void runOnContentCaptureThread(@NonNull Runnable r) {
-        if (mContentCaptureHandler == null) {
-            Log.e(TAG, "content capture thread is not initiallized!");
-            // fall back to UI thread
-            runOnUiThread(r);
-            return;
-        }
         if (!mContentCaptureHandler.getLooper().isCurrentThread()) {
             mContentCaptureHandler.post(r);
         } else {
@@ -1241,12 +1147,6 @@
     }
 
     private void clearAndRunOnContentCaptureThread(@NonNull Runnable r, int what) {
-        if (mContentCaptureHandler == null) {
-            Log.e(TAG, "content capture thread is not initiallized!");
-            // fall back to UI thread
-            runOnUiThread(r);
-            return;
-        }
         if (!mContentCaptureHandler.getLooper().isCurrentThread()) {
             mContentCaptureHandler.removeMessages(what);
             mContentCaptureHandler.post(r);
diff --git a/core/java/android/view/contentcapture/flags/content_capture_flags.aconfig b/core/java/android/view/contentcapture/flags/content_capture_flags.aconfig
index 9df8350..e7bc004 100644
--- a/core/java/android/view/contentcapture/flags/content_capture_flags.aconfig
+++ b/core/java/android/view/contentcapture/flags/content_capture_flags.aconfig
@@ -15,14 +15,3 @@
     bug: "380381249"
     is_exported: true
 }
-
-flag {
-    name: "post_create_android_bg_thread"
-    namespace: "pixel_state_server"
-    description: "Feature flag to post create the bg thread when an app is in the allowlist"
-    bug: "376468525"
-    is_fixed_read_only: true
-    metadata {
-        purpose: PURPOSE_BUGFIX
-    }
-}
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 0e329c2..ec0d915 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -159,6 +159,7 @@
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
 import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.Predicate;
@@ -719,6 +720,11 @@
             // Nothing to visit by default.
         }
 
+        /** See {@link RemoteViews#visitIcons(Consumer)}. **/
+        public void visitIcons(@NonNull Consumer<Icon> visitor) {
+            // Nothing to visit by default.
+        }
+
         public abstract void writeToParcel(Parcel dest, int flags);
 
         /**
@@ -849,6 +855,29 @@
     }
 
     /**
+     * Note all {@link Icon} that are referenced internally.
+     * @hide
+     */
+    public void visitIcons(@NonNull Consumer<Icon> visitor) {
+        if (mActions != null) {
+            for (int i = 0; i < mActions.size(); i++) {
+                mActions.get(i).visitIcons(visitor);
+            }
+        }
+        if (mSizedRemoteViews != null) {
+            for (int i = 0; i < mSizedRemoteViews.size(); i++) {
+                mSizedRemoteViews.get(i).visitIcons(visitor);
+            }
+        }
+        if (mLandscape != null) {
+            mLandscape.visitIcons(visitor);
+        }
+        if (mPortrait != null) {
+            mPortrait.visitIcons(visitor);
+        }
+    }
+
+    /**
      * @hide
      * @return True if there is a change
      */
@@ -1312,6 +1341,19 @@
         }
 
         @Override
+        public void visitIcons(Consumer<Icon> visitor) {
+            if (mItems == null) {
+                RemoteCollectionItems cachedItems = mCollectionCache.getItemsForId(mIntentId);
+                if (cachedItems != null) {
+                    cachedItems.visitIcons(visitor);
+                }
+                return;
+            }
+
+            mItems.visitIcons(visitor);
+        }
+
+        @Override
         public boolean canWriteToProto() {
             // Skip actions that do not contain items (intent only actions)
             return mItems != null;
@@ -2385,7 +2427,7 @@
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
         ArrayList<Bitmap> mBitmaps;
         SparseIntArray mBitmapHashes;
-        int mBitmapMemory = -1;
+        long mBitmapMemory = -1;
 
         public BitmapCache() {
             mBitmaps = new ArrayList<>();
@@ -2449,7 +2491,7 @@
             }
         }
 
-        public int getBitmapMemory() {
+        public long getBitmapMemory() {
             if (mBitmapMemory < 0) {
                 mBitmapMemory = 0;
                 int count = mBitmaps.size();
@@ -2735,6 +2777,13 @@
                 // TODO(b/281044385): Should we do anything about type BUNDLE?
             }
         }
+
+        @Override
+        public void visitIcons(@NonNull Consumer<Icon> visitor) {
+            if (mType == ICON && getParameterValue(null) instanceof Icon icon) {
+                visitor.accept(icon);
+            }
+        }
     }
 
     /** Class for the reflection actions. */
@@ -4139,6 +4188,11 @@
         }
 
         @Override
+        public void visitIcons(@NonNull Consumer<Icon> visitor) {
+            mNestedViews.visitIcons(visitor);
+        }
+
+        @Override
         public boolean canWriteToProto() {
             return true;
         }
@@ -6392,15 +6446,43 @@
     }
 
     /**
-     * Returns an estimate of the bitmap heap memory usage for this RemoteViews.
+     * Returns an estimate of the bitmap heap memory usage by setBitmap and setImageViewBitmap in
+     * this RemoteViews.
+     *
+     * @hide
      */
-    /** @hide */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public int estimateMemoryUsage() {
+    public long estimateMemoryUsage() {
         return mBitmapCache.getBitmapMemory();
     }
 
     /**
+     * Returns an estimate of bitmap heap memory usage by setIcon and setImageViewIcon in this
+     * RemoteViews. Note that this function will count duplicate Icons in its estimate.
+     *
+     * @hide
+     */
+    public long estimateIconMemoryUsage() {
+        AtomicLong total = new AtomicLong(0);
+        visitIcons(icon -> {
+            if (icon.getType() == Icon.TYPE_BITMAP || icon.getType() == Icon.TYPE_ADAPTIVE_BITMAP) {
+                total.addAndGet(icon.getBitmap().getAllocationByteCount());
+            }
+        });
+        return total.get();
+    }
+
+    /**
+     * Returns an estimate of the bitmap heap memory usage for all Icon and Bitmap actions in this
+     * RemoteViews.
+     *
+     * @hide
+     */
+    public long estimateTotalBitmapMemoryUsage() {
+        return estimateMemoryUsage() + estimateIconMemoryUsage();
+    }
+
+    /**
      * Add an action to be executed on the remote side when apply is called.
      *
      * @param a The action to add
@@ -9768,6 +9850,15 @@
                 view.visitUris(visitor);
             }
         }
+
+        /**
+         * See {@link RemoteViews#visitIcons(Consumer)}.
+         */
+        private void visitIcons(@NonNull Consumer<Icon> visitor) {
+            for (RemoteViews view : mViews) {
+                view.visitIcons(visitor);
+            }
+        }
     }
 
     /**
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index 222088e..51d488f 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -593,3 +593,10 @@
        purpose: PURPOSE_BUGFIX
     }
 }
+
+flag {
+    name: "enable_non_default_display_split"
+    namespace: "lse_desktop_experience"
+    description: "Enables split screen on non default displays"
+    bug: "384999213"
+}
diff --git a/core/proto/android/service/appwidget.proto b/core/proto/android/service/appwidget.proto
index fb90719..5dc90e0 100644
--- a/core/proto/android/service/appwidget.proto
+++ b/core/proto/android/service/appwidget.proto
@@ -39,6 +39,7 @@
     optional int32 maxWidth = 8;
     optional int32 maxHeight = 9;
     optional bool restoreCompleted = 10;
+    optional int32 views_bitmap_memory = 11;
 }
 
 // represents a set of widget previews for a particular provider
diff --git a/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt b/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt
index f9d449c..4ad6708 100644
--- a/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt
+++ b/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt
@@ -191,7 +191,7 @@
             .fuzzFractions()
             .mapNotNull{ FontScaleConverterFactory.forScale(it) }
             .flatMap{ table ->
-                generateSequenceOfFractions(-2000f..2000f, step = 0.1f)
+                generateSequenceOfFractions(-20f..100f, step = 0.1f)
                     .fuzzFractions()
                     .map{ Pair(table, it) }
             }
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
index ee8d428..f87b699 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
@@ -224,7 +224,7 @@
         }
 
         @Override
-        void internalFlush(int reason) {
+        void flush(int reason) {
             throw new UnsupportedOperationException("should not have been called");
         }
 
diff --git a/core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionTest.java
index a1d7f87..b42bcee 100644
--- a/core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/MainContentCaptureSessionTest.java
@@ -263,7 +263,7 @@
         session.mEvents = new ArrayList<>(Arrays.asList(EVENT));
         session.mDirectServiceInterface = mMockContentCaptureDirectManager;
 
-        session.internalFlush(REASON);
+        session.flush(REASON);
         mTestableLooper.processAllMessages();
 
         verifyZeroInteractions(mMockContentProtectionEventProcessor);
@@ -280,7 +280,7 @@
         session.mEvents = new ArrayList<>(Arrays.asList(EVENT));
         session.mDirectServiceInterface = mMockContentCaptureDirectManager;
 
-        session.internalFlush(REASON);
+        session.flush(REASON);
         mTestableLooper.processAllMessages();
 
         verifyZeroInteractions(mMockContentProtectionEventProcessor);
@@ -298,7 +298,7 @@
         session.mEvents = new ArrayList<>(Arrays.asList(EVENT));
         session.mDirectServiceInterface = mMockContentCaptureDirectManager;
 
-        session.internalFlush(REASON);
+        session.flush(REASON);
         mTestableLooper.processAllMessages();
 
         verifyZeroInteractions(mMockContentProtectionEventProcessor);
@@ -316,7 +316,7 @@
         session.mEvents = new ArrayList<>(Arrays.asList(EVENT));
         session.mDirectServiceInterface = mMockContentCaptureDirectManager;
 
-        session.internalFlush(REASON);
+        session.flush(REASON);
         mTestableLooper.processAllMessages();
 
         verifyZeroInteractions(mMockContentProtectionEventProcessor);
@@ -499,57 +499,6 @@
         assertThat(session.mEventProcessQueue).hasSize(1);
     }
 
-    @Test
-    public void notifyContentCaptureEvents_beforeSessionPerformStart() throws RemoteException {
-        ContentCaptureOptions options =
-                createOptions(
-                        /* enableContentCaptureReceiver= */ true,
-                        /* enableContentProtectionReceiver= */ true);
-        MainContentCaptureSession session = createSession(options);
-        session.mContentCaptureHandler = null;
-        session.mDirectServiceInterface = null;
-
-        notifyContentCaptureEvents(session);
-        mTestableLooper.processAllMessages();
-
-        assertThat(session.mEvents).isNull();
-        assertThat(session.mEventProcessQueue).hasSize(7); // 5 view events + 2 view tree events
-    }
-
-    @Test
-    public void notifyViewAppeared_beforeSessionPerformStart() throws RemoteException {
-        ContentCaptureOptions options =
-                createOptions(
-                        /* enableContentCaptureReceiver= */ true,
-                        /* enableContentProtectionReceiver= */ true);
-        MainContentCaptureSession session = createSession(options);
-        session.mContentCaptureHandler = null;
-        session.mDirectServiceInterface = null;
-
-        View view = prepareView(session);
-        session.notifyViewAppeared(session.newViewStructure(view));
-
-        assertThat(session.mEvents).isNull();
-        assertThat(session.mEventProcessQueue).hasSize(1);
-    }
-
-    @Test
-    public void flush_beforeSessionPerformStart() throws Exception {
-        ContentCaptureOptions options =
-                createOptions(
-                        /* enableContentCaptureReceiver= */ true,
-                        /* enableContentProtectionReceiver= */ true);
-        MainContentCaptureSession session = createSession(options);
-        session.mEvents = new ArrayList<>(Arrays.asList(EVENT));
-        session.mContentCaptureHandler = null;
-        session.mDirectServiceInterface = null;
-
-        session.internalFlush(REASON);
-
-        assertThat(session.mEvents).hasSize(1);
-        assertThat(session.mEventProcessQueue).isEmpty();
-    }
-
     /** Simulates the regular content capture events sequence. */
     private void notifyContentCaptureEvents(final MainContentCaptureSession session) {
         final ArrayList<Object> events = new ArrayList<>(
@@ -612,8 +561,8 @@
                         sStrippedContext,
                         manager,
                         testHandler,
+                        testHandler,
                         mMockSystemServerInterface);
-        session.mContentCaptureHandler = testHandler;
         session.mComponentName = COMPONENT_NAME;
         return session;
     }
diff --git a/core/tests/coretests/src/android/widget/RemoteViewsTest.java b/core/tests/coretests/src/android/widget/RemoteViewsTest.java
index 2880ecf..8b0d315 100644
--- a/core/tests/coretests/src/android/widget/RemoteViewsTest.java
+++ b/core/tests/coretests/src/android/widget/RemoteViewsTest.java
@@ -36,6 +36,7 @@
 import android.appwidget.AppWidgetHostView;
 import android.content.Context;
 import android.content.Intent;
+import android.graphics.Bitmap;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.AsyncTask;
@@ -934,6 +935,136 @@
         assertEquals(testText, replacedTextView.getText());
     }
 
+    @Test
+    public void estimateMemoryUsage() {
+        Bitmap b1 = Bitmap.createBitmap(1024, 768, Bitmap.Config.ARGB_8888);
+        int b1Memory = b1.getAllocationByteCount();
+        Bitmap b2 = Bitmap.createBitmap(640, 480, Bitmap.Config.ARGB_8888);
+        int b2Memory = b2.getAllocationByteCount();
+        Bitmap b3 = Bitmap.createBitmap(800, 600, Bitmap.Config.ARGB_8888);
+        int b3Memory = b3.getAllocationByteCount();
+
+        final RemoteViews rv = new RemoteViews(mPackage, R.layout.remote_views_test);
+        assertEquals(0, rv.estimateMemoryUsage());
+        assertEquals(0, rv.estimateIconMemoryUsage());
+        assertEquals(0, rv.estimateTotalBitmapMemoryUsage());
+
+        rv.setBitmap(R.id.view, "", b1);
+        rv.setImageViewBitmap(R.id.view, b1); // second instance of b1 is cached
+        rv.setBitmap(R.id.view, "", b2);
+        assertEquals(b1Memory + b2Memory, rv.estimateMemoryUsage());
+        assertEquals(0, rv.estimateIconMemoryUsage());
+        assertEquals(b1Memory + b2Memory, rv.estimateTotalBitmapMemoryUsage());
+
+        rv.setIcon(R.id.view, "", Icon.createWithBitmap(b2));
+        rv.setIcon(R.id.view, "", Icon.createWithBitmap(b3));
+        rv.setImageViewIcon(R.id.view, Icon.createWithBitmap(b3));
+        assertEquals(b1Memory + b2Memory, rv.estimateMemoryUsage());
+        assertEquals(b2Memory + (2 * b3Memory), rv.estimateIconMemoryUsage());
+        assertEquals(b1Memory + (2 * b2Memory) + (2 * b3Memory),
+                rv.estimateTotalBitmapMemoryUsage());
+    }
+
+    @Test
+    public void estimateMemoryUsage_landscapePortrait() {
+        Bitmap b1 = Bitmap.createBitmap(1024, 768, Bitmap.Config.ARGB_8888);
+        int b1Memory = b1.getAllocationByteCount();
+        Bitmap b2 = Bitmap.createBitmap(640, 480, Bitmap.Config.ARGB_8888);
+        int b2Memory = b2.getAllocationByteCount();
+        Bitmap b3 = Bitmap.createBitmap(800, 600, Bitmap.Config.ARGB_8888);
+        int b3Memory = b3.getAllocationByteCount();
+        Bitmap b4 = Bitmap.createBitmap(320, 240, Bitmap.Config.ARGB_8888);
+        int b4Memory = b4.getAllocationByteCount();
+
+        // Landscape and portrait using same bitmaps get counted twice.
+        final RemoteViews rv = new RemoteViews(mPackage, R.layout.remote_views_test);
+        rv.setBitmap(R.id.view, "", b1);
+        rv.setIcon(R.id.view, "", Icon.createWithBitmap(b2));
+        RemoteViews landscapePortraitViews = new RemoteViews(rv, rv);
+        assertEquals(b1Memory, landscapePortraitViews.estimateMemoryUsage());
+        assertEquals(2 * b2Memory, landscapePortraitViews.estimateIconMemoryUsage());
+        assertEquals(b1Memory + (2 * b2Memory),
+                landscapePortraitViews.estimateTotalBitmapMemoryUsage());
+
+        final RemoteViews rv2 = new RemoteViews(mPackage, R.layout.remote_views_test);
+        rv.setBitmap(R.id.view, "", b3);
+        rv.setIcon(R.id.view, "", Icon.createWithBitmap(b4));
+        landscapePortraitViews = new RemoteViews(rv, rv2);
+        assertEquals(b1Memory + b3Memory, landscapePortraitViews.estimateMemoryUsage());
+        assertEquals(b2Memory + b4Memory, landscapePortraitViews.estimateIconMemoryUsage());
+        assertEquals(b1Memory + b2Memory + b3Memory + b4Memory,
+                landscapePortraitViews.estimateTotalBitmapMemoryUsage());
+    }
+
+    @Test
+    public void estimateMemoryUsage_sizedViews() {
+        Bitmap b1 = Bitmap.createBitmap(1024, 768, Bitmap.Config.ARGB_8888);
+        int b1Memory = b1.getAllocationByteCount();
+        Bitmap b2 = Bitmap.createBitmap(640, 480, Bitmap.Config.ARGB_8888);
+        int b2Memory = b2.getAllocationByteCount();
+        Bitmap b3 = Bitmap.createBitmap(800, 600, Bitmap.Config.ARGB_8888);
+        int b3Memory = b3.getAllocationByteCount();
+        Bitmap b4 = Bitmap.createBitmap(320, 240, Bitmap.Config.ARGB_8888);
+        int b4Memory = b4.getAllocationByteCount();
+
+        // Sized views using same bitmaps do not get counted twice.
+        final RemoteViews rv = new RemoteViews(mPackage, R.layout.remote_views_test);
+        rv.setBitmap(R.id.view, "", b1);
+        rv.setIcon(R.id.view, "", Icon.createWithBitmap(b2));
+        RemoteViews sizedViews = new RemoteViews(
+                Map.of(new SizeF(0f, 0f), rv, new SizeF(1f, 1f), rv));
+        assertEquals(b1Memory, sizedViews.estimateMemoryUsage());
+        assertEquals(2 * b2Memory, sizedViews.estimateIconMemoryUsage());
+        assertEquals(b1Memory + (2 * b2Memory), sizedViews.estimateTotalBitmapMemoryUsage());
+
+        final RemoteViews rv2 = new RemoteViews(mPackage, R.layout.remote_views_test);
+        rv.setBitmap(R.id.view, "", b3);
+        rv.setIcon(R.id.view, "", Icon.createWithBitmap(b4));
+        sizedViews = new RemoteViews(Map.of(new SizeF(0f, 0f), rv, new SizeF(1f, 1f), rv2));
+        assertEquals(b1Memory + b3Memory, sizedViews.estimateMemoryUsage());
+        assertEquals(b2Memory + b4Memory, sizedViews.estimateIconMemoryUsage());
+        assertEquals(b1Memory + b2Memory + b3Memory + b4Memory,
+                sizedViews.estimateTotalBitmapMemoryUsage());
+    }
+
+    @Test
+    public void estimateMemoryUsage_nestedViews() {
+        Bitmap b1 = Bitmap.createBitmap(1024, 768, Bitmap.Config.ARGB_8888);
+        int b1Memory = b1.getAllocationByteCount();
+        Bitmap b2 = Bitmap.createBitmap(640, 480, Bitmap.Config.ARGB_8888);
+        int b2Memory = b2.getAllocationByteCount();
+
+        final RemoteViews rv1 = new RemoteViews(mPackage, R.layout.remote_views_test);
+        rv1.setBitmap(R.id.view, "", b1);
+        final RemoteViews rv2 = new RemoteViews(mPackage, R.layout.remote_views_test);
+        rv2.setIcon(R.id.view, "", Icon.createWithBitmap(b2));
+        final RemoteViews rv = new RemoteViews(mPackage, R.layout.remote_views_test);
+        rv.addView(R.id.view, rv1);
+        rv.addView(R.id.view, rv2);
+        assertEquals(b1Memory, rv.estimateMemoryUsage());
+        assertEquals(b2Memory, rv.estimateIconMemoryUsage());
+        assertEquals(b1Memory + b2Memory, rv.estimateTotalBitmapMemoryUsage());
+    }
+
+    @Test
+    public void estimateMemoryUsage_remoteCollectionItems() {
+        Bitmap b1 = Bitmap.createBitmap(1024, 768, Bitmap.Config.ARGB_8888);
+        int b1Memory = b1.getAllocationByteCount();
+        Bitmap b2 = Bitmap.createBitmap(640, 480, Bitmap.Config.ARGB_8888);
+        int b2Memory = b2.getAllocationByteCount();
+
+        final RemoteViews rv1 = new RemoteViews(mPackage, R.layout.remote_views_test);
+        rv1.setBitmap(R.id.view, "", b1);
+        final RemoteViews rv2 = new RemoteViews(mPackage, R.layout.remote_views_test);
+        rv2.setIcon(R.id.view, "", Icon.createWithBitmap(b2));
+        final RemoteViews rv = new RemoteViews(mPackage, R.layout.remote_views_test);
+        rv.setRemoteAdapter(R.id.view, new RemoteViews.RemoteCollectionItems.Builder().addItem(0L,
+                rv1).addItem(1L, rv2).build());
+        assertEquals(b1Memory, rv.estimateMemoryUsage());
+        assertEquals(b2Memory, rv.estimateIconMemoryUsage());
+        assertEquals(b1Memory + b2Memory, rv.estimateTotalBitmapMemoryUsage());
+    }
+
     private static LayoutInflater.Factory2 createLayoutInflaterFactory(String viewTypeToReplace,
             View replacementView) {
         return new LayoutInflater.Factory2() {
diff --git a/libs/WindowManager/Shell/aconfig/multitasking.aconfig b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
index 0656446..13d0169 100644
--- a/libs/WindowManager/Shell/aconfig/multitasking.aconfig
+++ b/libs/WindowManager/Shell/aconfig/multitasking.aconfig
@@ -177,10 +177,3 @@
     description: "Factor task-view state tracking out of taskviewtransitions"
     bug: "384976265"
 }
-
-flag {
-    name: "enable_non_default_display_split"
-    namespace: "multitasking"
-    description: "Enables split screen on non default displays"
-    bug: "384999213"
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index cd5c135..bd89f5c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -394,11 +394,19 @@
      * Returns the divider position as a fraction from 0 to 1.
      */
     public float getDividerPositionAsFraction() {
-        return Math.min(1f, Math.max(0f, mIsLeftRightSplit
-                ? (float) ((getTopLeftBounds().right + getBottomRightBounds().left) / 2f)
-                        / getBottomRightBounds().right
-                : (float) ((getTopLeftBounds().bottom + getBottomRightBounds().top) / 2f)
-                        / getBottomRightBounds().bottom));
+        if (Flags.enableFlexibleTwoAppSplit()) {
+            return Math.min(1f, Math.max(0f, mIsLeftRightSplit
+                    ? (getTopLeftBounds().right + getBottomRightBounds().left) / 2f
+                    / getDisplayWidth()
+                    : (getTopLeftBounds().bottom + getBottomRightBounds().top) / 2f
+                            / getDisplayHeight()));
+        } else {
+            return Math.min(1f, Math.max(0f, mIsLeftRightSplit
+                    ? (float) ((getTopLeftBounds().right + getBottomRightBounds().left) / 2f)
+                    / getBottomRightBounds().right
+                    : (float) ((getTopLeftBounds().bottom + getBottomRightBounds().top) / 2f)
+                            / getBottomRightBounds().bottom));
+        }
     }
 
     private void updateInvisibleRect() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTaskListener.java
index 2f93715..d735375 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTaskListener.java
@@ -133,7 +133,9 @@
                 taskInfo.topActivity, mPipTransitionState, mPictureInPictureParams, params);
         setPictureInPictureParams(params);
         float newAspectRatio = mPictureInPictureParams.getAspectRatioFloat();
-        if (PipUtils.aspectRatioChanged(newAspectRatio, mPipBoundsState.getAspectRatio())) {
+        if (params.hasSetAspectRatio()
+                && mPipBoundsAlgorithm.isValidPictureInPictureAspectRatio(newAspectRatio)
+                && PipUtils.aspectRatioChanged(newAspectRatio, mPipBoundsState.getAspectRatio())) {
             mPipTransitionState.setOnIdlePipTransitionStateRunnable(() -> {
                 onAspectRatioChanged(newAspectRatio);
             });
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
index 03327bf..2299624 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
@@ -725,6 +725,12 @@
                 mPipTransitionState.getPipTaskToken());
         mFinishCallback = finishCallback;
 
+        if (isPipClosing(info)) {
+            // If PiP is removed via a close (e.g. finishing of the activity), then
+            // clear out the PiP cache related to that activity component (e.g. reentry state).
+            mPipBoundsState.setLastPipComponentName(null /* lastPipComponentName */);
+        }
+
         finishTransaction.setAlpha(pipChange.getLeash(), 0f);
         if (mPendingRemoveWithFadeout) {
             PipAlphaAnimator animator = new PipAlphaAnimator(mContext, pipChange.getLeash(),
@@ -952,13 +958,29 @@
 
         boolean isPipMovedToBack = info.getType() == TRANSIT_TO_BACK
                 && pipChange.getMode() == TRANSIT_TO_BACK;
-        boolean isPipClosed = info.getType() == TRANSIT_CLOSE
-                && pipChange.getMode() == TRANSIT_CLOSE;
         // If PiP is dismissed by user (i.e. via dismiss button in PiP menu)
         boolean isPipDismissed = info.getType() == TRANSIT_REMOVE_PIP
                 && pipChange.getMode() == TRANSIT_TO_BACK;
         // PiP is being removed if the pinned task is either moved to back, closed, or dismissed.
-        return isPipMovedToBack || isPipClosed || isPipDismissed;
+        return isPipMovedToBack || isPipClosing(info) || isPipDismissed;
+    }
+
+    private boolean isPipClosing(@NonNull TransitionInfo info) {
+        if (mPipTransitionState.getPipTaskToken() == null) {
+            // PiP removal makes sense if enter-PiP has cached a valid pinned task token.
+            return false;
+        }
+        TransitionInfo.Change pipChange = info.getChange(mPipTransitionState.getPipTaskToken());
+        TransitionInfo.Change pipActivityChange = info.getChanges().stream().filter(change ->
+                change.getTaskInfo() == null && change.getParent() != null
+                        && change.getParent() == mPipTransitionState.getPipTaskToken())
+                .findFirst().orElse(null);
+
+        boolean isPipTaskClosed = pipChange != null
+                && pipChange.getMode() == TRANSIT_CLOSE;
+        boolean isPipActivityClosed = pipActivityChange != null
+                && pipActivityChange.getMode() == TRANSIT_CLOSE;
+        return isPipTaskClosed || isPipActivityClosed;
     }
 
     private void prepareConfigAtEndActivity(@NonNull SurfaceControl.Transaction startTx,
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 722494c..2174017 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
@@ -109,6 +109,7 @@
 import android.util.IntArray;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseIntArray;
 import android.view.Choreographer;
 import android.view.IRemoteAnimationFinishedCallback;
 import android.view.IRemoteAnimationRunner;
@@ -3012,11 +3013,18 @@
             final int transitType = info.getType();
             TransitionInfo.Change pipChange = null;
             int closingSplitTaskId = -1;
-            // This array tracks where we are sending stages (TO_BACK/TO_FRONT) in this transition.
-            // TODO (b/349828130): Update for n apps (needs to handle different indices than 0/1).
-            //  Also make sure having multiple changes per stage (2+ tasks in one stage) is being
-            //  handled properly.
-            int[] stageChanges = new int[2];
+            // This array tracks if we are sending stages TO_BACK/TO_FRONT in this transition.
+            // TODO (b/349828130): Also make sure having multiple changes per stage (2+ tasks in
+            //  one stage) is being handled properly.
+            SparseIntArray stageChanges = new SparseIntArray();
+            if (enableFlexibleSplit()) {
+                mStageOrderOperator.getActiveStages()
+                        .forEach(stage -> stageChanges.put(stage.getId(), -1));
+            } else {
+                stageChanges.put(STAGE_TYPE_MAIN, -1);
+                stageChanges.put(STAGE_TYPE_SIDE, -1);
+            }
+
 
             for (int iC = 0; iC < info.getChanges().size(); ++iC) {
                 final TransitionInfo.Change change = info.getChanges().get(iC);
@@ -3090,14 +3098,12 @@
                     // we'll break split
                     closingSplitTaskId = taskId;
                 }
-                if (transitType == WindowManager.TRANSIT_WAKE) {
-                    // Record which stages are receiving which changes
-                    if ((change.getMode() == TRANSIT_TO_BACK
-                            || change.getMode() == TRANSIT_TO_FRONT)
-                            && (stageOfTaskId == STAGE_TYPE_MAIN
-                            || stageOfTaskId == STAGE_TYPE_SIDE)) {
-                        stageChanges[stageOfTaskId] = change.getMode();
-                    }
+                // Record which stages are receiving which changes
+                if ((change.getMode() == TRANSIT_TO_BACK
+                        || change.getMode() == TRANSIT_TO_FRONT)
+                        && (stageOfTaskId == STAGE_TYPE_MAIN
+                        || stageOfTaskId == STAGE_TYPE_SIDE)) {
+                    stageChanges.put(getStageOfTask(taskId), change.getMode());
                 }
             }
 
@@ -3126,8 +3132,16 @@
             // If keyguard is active, check to see if we have all our stages showing. If one stage
             // was moved but not the other (which can happen with SHOW_ABOVE_LOCKED apps), we should
             // break split.
-            if (mKeyguardActive && stageChanges[STAGE_TYPE_MAIN] != stageChanges[STAGE_TYPE_SIDE]) {
-                dismissSplitKeepingLastActiveStage(EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
+            if (mKeyguardActive && stageChanges.size() > 0) {
+                int firstChangeMode = stageChanges.valueAt(0);
+                for (int i = 0; i < stageChanges.size(); i++) {
+                    int changeMode = stageChanges.valueAt(i);
+                    // Compare each changeMode to the first one. If any are different, break split.
+                    if (changeMode != firstChangeMode) {
+                        dismissSplitKeepingLastActiveStage(EXIT_REASON_SCREEN_LOCKED_SHOW_ON_TOP);
+                        break;
+                    }
+                }
             }
 
             final ArraySet<StageTaskListener> dismissStages = record.getShouldDismissedStage();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTaskListenerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTaskListenerTest.java
index 89cb729..3923a1e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTaskListenerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTaskListenerTest.java
@@ -22,6 +22,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.when;
 import static org.mockito.kotlin.MatchersKt.eq;
@@ -193,6 +194,12 @@
                 mMockPipTransitionState, mMockPipScheduler, mMockPipBoundsState,
                 mMockPipBoundsAlgorithm, mMockShellExecutor);
         mPipTaskListener.addParamsChangedListener(mMockPipParamsChangedCallback);
+
+        // For this test case, any aspect ratio passed is considered within allowed range.
+        when(mMockPipBoundsAlgorithm
+                .isValidPictureInPictureAspectRatio(anyFloat()))
+                .thenReturn(true);
+
         Rational aspectRatio = new Rational(4, 3);
         when(mMockPipBoundsState.getAspectRatio()).thenReturn(aspectRatio.toFloat());
         String action1 = "action1";
@@ -227,6 +234,29 @@
     }
 
     @Test
+    public void onTaskInfoChanged_nonValidAspectRatio_doesNotCallbackAspectRatioChanged() {
+        mPipTaskListener = new PipTaskListener(mMockContext, mMockShellTaskOrganizer,
+                mMockPipTransitionState, mMockPipScheduler, mMockPipBoundsState,
+                mMockPipBoundsAlgorithm, mMockShellExecutor);
+        mPipTaskListener.addParamsChangedListener(mMockPipParamsChangedCallback);
+
+        String action1 = "action1";
+        mPipTaskListener.onTaskInfoChanged(getTaskInfo(null, action1));
+        verify(mMockPipTransitionState, times(0))
+                .setOnIdlePipTransitionStateRunnable(any(Runnable.class));
+
+        // Define an invalid aspect ratio and try and update the params with it.
+        Rational aspectRatio = new Rational(100, 3);
+        when(mMockPipBoundsAlgorithm
+                .isValidPictureInPictureAspectRatio(eq(aspectRatio.floatValue())))
+                .thenReturn(false);
+
+        mPipTaskListener.onTaskInfoChanged(getTaskInfo(aspectRatio, action1));
+        verify(mMockPipTransitionState, times(0))
+                .setOnIdlePipTransitionStateRunnable(any(Runnable.class));
+    }
+
+    @Test
     public void onPipTransitionStateChanged_scheduledBoundsChangeWithAspectRatioChange_schedule() {
         mPipTaskListener = new PipTaskListener(mMockContext, mMockShellTaskOrganizer,
                 mMockPipTransitionState, mMockPipScheduler, mMockPipBoundsState,
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 8bc66a0..f308ce9 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -18,6 +18,7 @@
 
 import static android.media.audio.Flags.FLAG_DOLBY_AC4_LEVEL4_ENCODING_API;
 import static android.media.audio.Flags.FLAG_IAMF_DEFINITIONS_API;
+import static android.media.audio.Flags.FLAG_SONY_360RA_MPEGH_3D_FORMAT;
 
 import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
@@ -718,8 +719,9 @@
      * Same as 9.1.4 with the addition of left and right top side channels */
     public static final int CHANNEL_OUT_9POINT1POINT6 = (CHANNEL_OUT_9POINT1POINT4
             | CHANNEL_OUT_TOP_SIDE_LEFT | CHANNEL_OUT_TOP_SIDE_RIGHT);
-    /** @hide */
-    public static final int CHANNEL_OUT_13POINT_360RA = (
+    /** Output channel mask for 13.0 */
+    @FlaggedApi(FLAG_SONY_360RA_MPEGH_3D_FORMAT)
+    public static final int CHANNEL_OUT_13POINT0 = (
             CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_FRONT_RIGHT |
             CHANNEL_OUT_SIDE_LEFT | CHANNEL_OUT_SIDE_RIGHT |
             CHANNEL_OUT_TOP_FRONT_LEFT | CHANNEL_OUT_TOP_FRONT_CENTER |
@@ -915,7 +917,7 @@
             case CHANNEL_OUT_9POINT1POINT6:
                 result.append("9.1.6");
                 break;
-            case CHANNEL_OUT_13POINT_360RA:
+            case CHANNEL_OUT_13POINT0:
                 result.append("360RA 13ch");
                 break;
             case CHANNEL_OUT_22POINT2:
diff --git a/media/java/android/media/audio/common/AidlConversion.java b/media/java/android/media/audio/common/AidlConversion.java
index 8521d1c..b831e4f 100644
--- a/media/java/android/media/audio/common/AidlConversion.java
+++ b/media/java/android/media/audio/common/AidlConversion.java
@@ -366,8 +366,8 @@
                             return AudioFormat.CHANNEL_OUT_9POINT1POINT4;
                         case AudioChannelLayout.LAYOUT_9POINT1POINT6:
                             return AudioFormat.CHANNEL_OUT_9POINT1POINT6;
-                        case AudioChannelLayout.LAYOUT_13POINT_360RA:
-                            return AudioFormat.CHANNEL_OUT_13POINT_360RA;
+                        case AudioChannelLayout.LAYOUT_13POINT0:
+                            return AudioFormat.CHANNEL_OUT_13POINT0;
                         case AudioChannelLayout.LAYOUT_22POINT2:
                             return AudioFormat.CHANNEL_OUT_22POINT2;
                         case AudioChannelLayout.LAYOUT_MONO_HAPTIC_A:
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt
index 9300964..3f2e78c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractorTest.kt
@@ -39,6 +39,8 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.Flags
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
+import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
 import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
@@ -85,11 +87,13 @@
 
     private lateinit var powerInteractor: PowerInteractor
     private lateinit var transitionRepository: FakeKeyguardTransitionRepository
+    private lateinit var bouncerRepository: FakeKeyguardBouncerRepository
 
     @Before
     fun setup() {
         powerInteractor = kosmos.powerInteractor
         transitionRepository = kosmos.fakeKeyguardTransitionRepositorySpy
+        bouncerRepository = kosmos.fakeKeyguardBouncerRepository
         underTest = kosmos.fromAodTransitionInteractor
 
         underTest.start()
@@ -304,6 +308,29 @@
         }
 
     @Test
+    fun testWakeAndUnlock_transitionsToGone_evenIfBouncerShows() =
+        testScope.runTest {
+            kosmos.fakeKeyguardRepository.setBiometricUnlockState(
+                BiometricUnlockMode.WAKE_AND_UNLOCK
+            )
+            runCurrent()
+            bouncerRepository.setPrimaryShow(true)
+            runCurrent()
+            powerInteractor.setAwakeForTest()
+            runCurrent()
+
+            // Waking up from wake and unlock should not start any transitions, we'll wait for the
+            // dismiss call.
+            assertThat(transitionRepository).noTransitionsStarted()
+
+            underTest.dismissAod()
+            advanceTimeBy(100) // account for debouncing
+
+            assertThat(transitionRepository)
+                .startedTransition(from = KeyguardState.AOD, to = KeyguardState.GONE)
+        }
+
+    @Test
     fun testTransitionToOccluded_onWake() =
         testScope.runTest {
             kosmos.fakeKeyguardRepository.setKeyguardOccluded(true)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
index 555c717..93d1f59 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
@@ -78,6 +78,7 @@
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.emptyFlow
 import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
@@ -220,6 +221,7 @@
                 mock(),
                 { configurationForwarder },
                 brightnessMirrorShowingInteractor,
+                UnconfinedTestDispatcher(),
             )
 
         controller.setupExpandedStatusBar()
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/TableLogBufferBase.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/TableLogBufferBase.kt
index 50b3f78..8a962f9 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/TableLogBufferBase.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/log/TableLogBufferBase.kt
@@ -25,34 +25,34 @@
      *
      * For Java overloading.
      */
-    fun logChange(prefix: String, columnName: String, value: String?) {
+    fun logChange(prefix: String = "", columnName: String, value: String?) {
         logChange(prefix, columnName, value, isInitial = false)
     }
 
     /** Logs a String? change. */
-    fun logChange(prefix: String, columnName: String, value: String?, isInitial: Boolean)
+    fun logChange(prefix: String = "", columnName: String, value: String?, isInitial: Boolean)
 
     /**
      * Logs a Boolean change.
      *
      * For Java overloading.
      */
-    fun logChange(prefix: String, columnName: String, value: Boolean) {
+    fun logChange(prefix: String = "", columnName: String, value: Boolean) {
         logChange(prefix, columnName, value, isInitial = false)
     }
 
     /** Logs a Boolean change. */
-    fun logChange(prefix: String, columnName: String, value: Boolean, isInitial: Boolean)
+    fun logChange(prefix: String = "", columnName: String, value: Boolean, isInitial: Boolean)
 
     /**
      * Logs an Int? change.
      *
      * For Java overloading.
      */
-    fun logChange(prefix: String, columnName: String, value: Int?) {
+    fun logChange(prefix: String = "", columnName: String, value: Int?) {
         logChange(prefix, columnName, value, isInitial = false)
     }
 
     /** Logs an Int? change. */
-    fun logChange(prefix: String, columnName: String, value: Int?, isInitial: Boolean)
+    fun logChange(prefix: String = "", columnName: String, value: Int?, isInitial: Boolean)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
index 7174379..4ad04be 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
@@ -193,7 +193,10 @@
         if (SceneContainerFlag.isEnabled) return
         scope.launch("$TAG#listenForAodToPrimaryBouncer") {
             keyguardInteractor.primaryBouncerShowing
-                .filterRelevantKeyguardStateAnd { primaryBouncerShowing -> primaryBouncerShowing }
+                .filterRelevantKeyguardStateAnd { primaryBouncerShowing ->
+                    !isWakeAndUnlock(keyguardInteractor.biometricUnlockState.value.mode) &&
+                        primaryBouncerShowing
+                }
                 .collect { startTransitionTo(KeyguardState.PRIMARY_BOUNCER) }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/log/table/Diffable.kt b/packages/SystemUI/src/com/android/systemui/log/table/Diffable.kt
index baa07c1..9fddbfb 100644
--- a/packages/SystemUI/src/com/android/systemui/log/table/Diffable.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/table/Diffable.kt
@@ -65,7 +65,7 @@
  */
 fun <T : Diffable<T>> Flow<T>.logDiffsForTable(
     tableLogBuffer: TableLogBuffer,
-    columnPrefix: String,
+    columnPrefix: String = "",
     initialValue: T,
 ): Flow<T> {
     // Fully log the initial value to the table.
@@ -87,7 +87,7 @@
 /** See [logDiffsForTable(TableLogBuffer, String, T)]. */
 fun Flow<Boolean>.logDiffsForTable(
     tableLogBuffer: TableLogBuffer,
-    columnPrefix: String,
+    columnPrefix: String = "",
     columnName: String,
     initialValue: Boolean,
 ): Flow<Boolean> {
@@ -106,7 +106,7 @@
 /** See [logDiffsForTable(TableLogBuffer, String, T)]. */
 fun Flow<Int>.logDiffsForTable(
     tableLogBuffer: TableLogBuffer,
-    columnPrefix: String,
+    columnPrefix: String = "",
     columnName: String,
     initialValue: Int,
 ): Flow<Int> {
@@ -125,7 +125,7 @@
 /** See [logDiffsForTable(TableLogBuffer, String, T)]. */
 fun Flow<Int?>.logDiffsForTable(
     tableLogBuffer: TableLogBuffer,
-    columnPrefix: String,
+    columnPrefix: String = "",
     columnName: String,
     initialValue: Int?,
 ): Flow<Int?> {
@@ -144,7 +144,7 @@
 /** See [logDiffsForTable(TableLogBuffer, String, T)]. */
 fun Flow<String?>.logDiffsForTable(
     tableLogBuffer: TableLogBuffer,
-    columnPrefix: String,
+    columnPrefix: String = "",
     columnName: String,
     initialValue: String?,
 ): Flow<String?> {
@@ -163,7 +163,7 @@
 /** See [logDiffsForTable(TableLogBuffer, String, T)]. */
 fun <T> Flow<List<T>>.logDiffsForTable(
     tableLogBuffer: TableLogBuffer,
-    columnPrefix: String,
+    columnPrefix: String = "",
     columnName: String,
     initialValue: List<T>,
 ): Flow<List<T>> {
diff --git a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
index 89a599a..3d1623b 100644
--- a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
@@ -124,7 +124,7 @@
      *   the separator token for parsing, so it can't be present in any part of the column name.
      */
     @Synchronized
-    fun <T : Diffable<T>> logDiffs(columnPrefix: String, prevVal: T, newVal: T) {
+    fun <T : Diffable<T>> logDiffs(columnPrefix: String = "", prevVal: T, newVal: T) {
         val row = tempRow
         row.timestamp = systemClock.currentTimeMillis()
         row.columnPrefix = columnPrefix
@@ -136,6 +136,7 @@
     /**
      * Logs change(s) to the buffer using [rowInitializer].
      *
+     * @param columnPrefix see [logDiffs].
      * @param rowInitializer a function that will be called immediately to store relevant data on
      *   the row.
      * @param isInitial true if this change represents the starting value for a particular column
@@ -145,9 +146,9 @@
      */
     @Synchronized
     fun logChange(
-        columnPrefix: String,
+        columnPrefix: String = "",
         isInitial: Boolean = false,
-        rowInitializer: (TableRowLogger) -> Unit
+        rowInitializer: (TableRowLogger) -> Unit,
     ) {
         val row = tempRow
         row.timestamp = systemClock.currentTimeMillis()
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index 255494f0..10a9fd2 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -45,6 +45,7 @@
 import com.android.systemui.bouncer.ui.binder.BouncerViewBinder;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlagsClassic;
@@ -87,6 +88,8 @@
 import com.android.systemui.window.ui.WindowRootViewBinder;
 import com.android.systemui.window.ui.viewmodel.WindowRootViewModel;
 
+import kotlinx.coroutines.CoroutineDispatcher;
+import kotlinx.coroutines.ExperimentalCoroutinesApi;
 import kotlinx.coroutines.flow.Flow;
 
 import java.io.PrintWriter;
@@ -119,6 +122,7 @@
     private final PrimaryBouncerInteractor mPrimaryBouncerInteractor;
     private final AlternateBouncerInteractor mAlternateBouncerInteractor;
     private final QuickSettingsController mQuickSettingsController;
+    private final CoroutineDispatcher mMainDispatcher;
     private final KeyguardTransitionInteractor mKeyguardTransitionInteractor;
     private final GlanceableHubContainerController
             mGlanceableHubContainerController;
@@ -204,7 +208,8 @@
             AlternateBouncerInteractor alternateBouncerInteractor,
             BouncerViewBinder bouncerViewBinder,
             @ShadeDisplayAware Provider<ConfigurationForwarder> configurationForwarder,
-            BrightnessMirrorShowingInteractor brightnessMirrorShowingInteractor) {
+            BrightnessMirrorShowingInteractor brightnessMirrorShowingInteractor,
+            @Main CoroutineDispatcher mainDispatcher) {
         mLockscreenShadeTransitionController = transitionController;
         mFalsingCollector = falsingCollector;
         mStatusBarStateController = statusBarStateController;
@@ -232,6 +237,7 @@
         mPrimaryBouncerInteractor = primaryBouncerInteractor;
         mAlternateBouncerInteractor = alternateBouncerInteractor;
         mQuickSettingsController = quickSettingsController;
+        mMainDispatcher = mainDispatcher;
 
         // This view is not part of the newly inflated expanded status bar.
         mBrightnessMirror = mView.findViewById(R.id.brightness_mirror_container);
@@ -286,7 +292,7 @@
         if (SceneContainerFlag.isEnabled()) return;
 
         WindowRootViewBinder.INSTANCE.bind(mView, windowRootViewModelFactory, blurUtils,
-                choreographer);
+                choreographer, mMainDispatcher);
     }
 
     private void bindBouncer(BouncerViewBinder bouncerViewBinder) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepository.kt
index 9f1395a..f82e681 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepository.kt
@@ -81,12 +81,7 @@
                 awaitClose { observer.isListening = false }
             }
             .distinctUntilChanged()
-            .logDiffsForTable(
-                logger,
-                columnPrefix = "",
-                columnName = "isAirplaneMode",
-                initialValue = false,
-            )
+            .logDiffsForTable(logger, columnName = "isAirplaneMode", initialValue = false)
             .stateIn(
                 scope,
                 started = SharingStarted.WhileSubscribed(),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModel.kt
index bd18f4b..2cef54f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModel.kt
@@ -59,7 +59,6 @@
             .distinctUntilChanged()
             .logDiffsForTable(
                 logger,
-                columnPrefix = "",
                 columnName = "isAirplaneModeIconVisible",
                 initialValue = false,
             )
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt
index be3977e..410389a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepository.kt
@@ -64,9 +64,8 @@
         _carrierId
             .logDiffsForTable(
                 tableLogBuffer,
-                columnPrefix = "",
                 columnName = COL_CARRIER_ID,
-                _carrierId.value,
+                initialValue = _carrierId.value,
             )
             .stateIn(scope, SharingStarted.WhileSubscribed(), _carrierId.value)
 
@@ -75,9 +74,8 @@
         _inflateSignalStrength
             .logDiffsForTable(
                 tableLogBuffer,
-                columnPrefix = "",
                 columnName = "inflate",
-                _inflateSignalStrength.value,
+                initialValue = _inflateSignalStrength.value,
             )
             .stateIn(scope, SharingStarted.WhileSubscribed(), _inflateSignalStrength.value)
 
@@ -89,9 +87,8 @@
         _isEmergencyOnly
             .logDiffsForTable(
                 tableLogBuffer,
-                columnPrefix = "",
                 columnName = COL_EMERGENCY,
-                _isEmergencyOnly.value,
+                initialValue = _isEmergencyOnly.value,
             )
             .stateIn(scope, SharingStarted.WhileSubscribed(), _isEmergencyOnly.value)
 
@@ -100,9 +97,8 @@
         _isRoaming
             .logDiffsForTable(
                 tableLogBuffer,
-                columnPrefix = "",
                 columnName = COL_ROAMING,
-                _isRoaming.value,
+                initialValue = _isRoaming.value,
             )
             .stateIn(scope, SharingStarted.WhileSubscribed(), _isRoaming.value)
 
@@ -111,9 +107,8 @@
         _operatorAlphaShort
             .logDiffsForTable(
                 tableLogBuffer,
-                columnPrefix = "",
                 columnName = COL_OPERATOR,
-                _operatorAlphaShort.value,
+                initialValue = _operatorAlphaShort.value,
             )
             .stateIn(scope, SharingStarted.WhileSubscribed(), _operatorAlphaShort.value)
 
@@ -122,9 +117,8 @@
         _isInService
             .logDiffsForTable(
                 tableLogBuffer,
-                columnPrefix = "",
                 columnName = COL_IS_IN_SERVICE,
-                _isInService.value,
+                initialValue = _isInService.value,
             )
             .stateIn(scope, SharingStarted.WhileSubscribed(), _isInService.value)
 
@@ -133,21 +127,15 @@
         _isNonTerrestrial
             .logDiffsForTable(
                 tableLogBuffer,
-                columnPrefix = "",
                 columnName = COL_IS_NTN,
-                _isNonTerrestrial.value,
+                initialValue = _isNonTerrestrial.value,
             )
             .stateIn(scope, SharingStarted.WhileSubscribed(), _isNonTerrestrial.value)
 
     private val _isGsm = MutableStateFlow(false)
     override val isGsm =
         _isGsm
-            .logDiffsForTable(
-                tableLogBuffer,
-                columnPrefix = "",
-                columnName = COL_IS_GSM,
-                _isGsm.value,
-            )
+            .logDiffsForTable(tableLogBuffer, columnName = COL_IS_GSM, initialValue = _isGsm.value)
             .stateIn(scope, SharingStarted.WhileSubscribed(), _isGsm.value)
 
     private val _cdmaLevel = MutableStateFlow(CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
@@ -155,9 +143,8 @@
         _cdmaLevel
             .logDiffsForTable(
                 tableLogBuffer,
-                columnPrefix = "",
                 columnName = COL_CDMA_LEVEL,
-                _cdmaLevel.value,
+                initialValue = _cdmaLevel.value,
             )
             .stateIn(scope, SharingStarted.WhileSubscribed(), _cdmaLevel.value)
 
@@ -166,9 +153,8 @@
         _primaryLevel
             .logDiffsForTable(
                 tableLogBuffer,
-                columnPrefix = "",
                 columnName = COL_PRIMARY_LEVEL,
-                _primaryLevel.value,
+                initialValue = _primaryLevel.value,
             )
             .stateIn(scope, SharingStarted.WhileSubscribed(), _primaryLevel.value)
 
@@ -177,23 +163,22 @@
         _satelliteLevel
             .logDiffsForTable(
                 tableLogBuffer,
-                columnPrefix = "",
                 columnName = COL_SATELLITE_LEVEL,
-                _satelliteLevel.value,
+                initialValue = _satelliteLevel.value,
             )
             .stateIn(scope, SharingStarted.WhileSubscribed(), _satelliteLevel.value)
 
     private val _dataConnectionState = MutableStateFlow(DataConnectionState.Disconnected)
     override val dataConnectionState =
         _dataConnectionState
-            .logDiffsForTable(tableLogBuffer, columnPrefix = "", _dataConnectionState.value)
+            .logDiffsForTable(tableLogBuffer, initialValue = _dataConnectionState.value)
             .stateIn(scope, SharingStarted.WhileSubscribed(), _dataConnectionState.value)
 
     private val _dataActivityDirection =
         MutableStateFlow(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
     override val dataActivityDirection =
         _dataActivityDirection
-            .logDiffsForTable(tableLogBuffer, columnPrefix = "", _dataActivityDirection.value)
+            .logDiffsForTable(tableLogBuffer, initialValue = _dataActivityDirection.value)
             .stateIn(scope, SharingStarted.WhileSubscribed(), _dataActivityDirection.value)
 
     private val _carrierNetworkChangeActive = MutableStateFlow(false)
@@ -201,9 +186,8 @@
         _carrierNetworkChangeActive
             .logDiffsForTable(
                 tableLogBuffer,
-                columnPrefix = "",
                 columnName = COL_CARRIER_NETWORK_CHANGE,
-                _carrierNetworkChangeActive.value,
+                initialValue = _carrierNetworkChangeActive.value,
             )
             .stateIn(scope, SharingStarted.WhileSubscribed(), _carrierNetworkChangeActive.value)
 
@@ -211,7 +195,7 @@
         MutableStateFlow(ResolvedNetworkType.UnknownNetworkType)
     override val resolvedNetworkType =
         _resolvedNetworkType
-            .logDiffsForTable(tableLogBuffer, columnPrefix = "", _resolvedNetworkType.value)
+            .logDiffsForTable(tableLogBuffer, initialValue = _resolvedNetworkType.value)
             .stateIn(scope, SharingStarted.WhileSubscribed(), _resolvedNetworkType.value)
 
     override val numberOfLevels =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt
index 21a3410..5094bc7e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepository.kt
@@ -73,7 +73,6 @@
         _isCarrierMerged
             .logDiffsForTable(
                 tableLogBuffer,
-                columnPrefix = "",
                 columnName = "isCarrierMerged",
                 initialValue = startingIsCarrierMerged,
             )
@@ -128,9 +127,8 @@
             .flatMapLatest { it.isEmergencyOnly }
             .logDiffsForTable(
                 tableLogBuffer,
-                columnPrefix = "",
                 columnName = COL_EMERGENCY,
-                activeRepo.value.isEmergencyOnly.value,
+                initialValue = activeRepo.value.isEmergencyOnly.value,
             )
             .stateIn(
                 scope,
@@ -143,9 +141,8 @@
             .flatMapLatest { it.isRoaming }
             .logDiffsForTable(
                 tableLogBuffer,
-                columnPrefix = "",
                 columnName = COL_ROAMING,
-                activeRepo.value.isRoaming.value,
+                initialValue = activeRepo.value.isRoaming.value,
             )
             .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.isRoaming.value)
 
@@ -154,9 +151,8 @@
             .flatMapLatest { it.operatorAlphaShort }
             .logDiffsForTable(
                 tableLogBuffer,
-                columnPrefix = "",
                 columnName = COL_OPERATOR,
-                activeRepo.value.operatorAlphaShort.value,
+                initialValue = activeRepo.value.operatorAlphaShort.value,
             )
             .stateIn(
                 scope,
@@ -169,9 +165,8 @@
             .flatMapLatest { it.isInService }
             .logDiffsForTable(
                 tableLogBuffer,
-                columnPrefix = "",
                 columnName = COL_IS_IN_SERVICE,
-                activeRepo.value.isInService.value,
+                initialValue = activeRepo.value.isInService.value,
             )
             .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.isInService.value)
 
@@ -180,9 +175,8 @@
             .flatMapLatest { it.isNonTerrestrial }
             .logDiffsForTable(
                 tableLogBuffer,
-                columnPrefix = "",
                 columnName = COL_IS_NTN,
-                activeRepo.value.isNonTerrestrial.value,
+                initialValue = activeRepo.value.isNonTerrestrial.value,
             )
             .stateIn(
                 scope,
@@ -195,9 +189,8 @@
             .flatMapLatest { it.isGsm }
             .logDiffsForTable(
                 tableLogBuffer,
-                columnPrefix = "",
                 columnName = COL_IS_GSM,
-                activeRepo.value.isGsm.value,
+                initialValue = activeRepo.value.isGsm.value,
             )
             .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.isGsm.value)
 
@@ -206,9 +199,8 @@
             .flatMapLatest { it.cdmaLevel }
             .logDiffsForTable(
                 tableLogBuffer,
-                columnPrefix = "",
                 columnName = COL_CDMA_LEVEL,
-                activeRepo.value.cdmaLevel.value,
+                initialValue = activeRepo.value.cdmaLevel.value,
             )
             .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.cdmaLevel.value)
 
@@ -217,9 +209,8 @@
             .flatMapLatest { it.primaryLevel }
             .logDiffsForTable(
                 tableLogBuffer,
-                columnPrefix = "",
                 columnName = COL_PRIMARY_LEVEL,
-                activeRepo.value.primaryLevel.value,
+                initialValue = activeRepo.value.primaryLevel.value,
             )
             .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.primaryLevel.value)
 
@@ -228,9 +219,8 @@
             .flatMapLatest { it.satelliteLevel }
             .logDiffsForTable(
                 tableLogBuffer,
-                columnPrefix = "",
                 columnName = COL_SATELLITE_LEVEL,
-                activeRepo.value.satelliteLevel.value,
+                initialValue = activeRepo.value.satelliteLevel.value,
             )
             .stateIn(scope, SharingStarted.WhileSubscribed(), activeRepo.value.satelliteLevel.value)
 
@@ -239,8 +229,7 @@
             .flatMapLatest { it.dataConnectionState }
             .logDiffsForTable(
                 tableLogBuffer,
-                columnPrefix = "",
-                activeRepo.value.dataConnectionState.value,
+                initialValue = activeRepo.value.dataConnectionState.value,
             )
             .stateIn(
                 scope,
@@ -253,8 +242,7 @@
             .flatMapLatest { it.dataActivityDirection }
             .logDiffsForTable(
                 tableLogBuffer,
-                columnPrefix = "",
-                activeRepo.value.dataActivityDirection.value,
+                initialValue = activeRepo.value.dataActivityDirection.value,
             )
             .stateIn(
                 scope,
@@ -267,9 +255,8 @@
             .flatMapLatest { it.carrierNetworkChangeActive }
             .logDiffsForTable(
                 tableLogBuffer,
-                columnPrefix = "",
                 columnName = COL_CARRIER_NETWORK_CHANGE,
-                activeRepo.value.carrierNetworkChangeActive.value,
+                initialValue = activeRepo.value.carrierNetworkChangeActive.value,
             )
             .stateIn(
                 scope,
@@ -282,8 +269,7 @@
             .flatMapLatest { it.resolvedNetworkType }
             .logDiffsForTable(
                 tableLogBuffer,
-                columnPrefix = "",
-                activeRepo.value.resolvedNetworkType.value,
+                initialValue = activeRepo.value.resolvedNetworkType.value,
             )
             .stateIn(
                 scope,
@@ -296,7 +282,6 @@
             .flatMapLatest { it.dataEnabled }
             .logDiffsForTable(
                 tableLogBuffer,
-                columnPrefix = "",
                 columnName = "dataEnabled",
                 initialValue = activeRepo.value.dataEnabled.value,
             )
@@ -307,7 +292,6 @@
             .flatMapLatest { it.inflateSignalStrength }
             .logDiffsForTable(
                 tableLogBuffer,
-                columnPrefix = "",
                 columnName = "inflate",
                 initialValue = activeRepo.value.inflateSignalStrength.value,
             )
@@ -322,7 +306,6 @@
             .flatMapLatest { it.allowNetworkSliceIndicator }
             .logDiffsForTable(
                 tableLogBuffer,
-                columnPrefix = "",
                 columnName = "allowSlice",
                 initialValue = activeRepo.value.allowNetworkSliceIndicator.value,
             )
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
index 6337110..d336903 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
@@ -380,7 +380,6 @@
             .distinctUntilChanged()
             .logDiffsForTable(
                 tableLogger,
-                columnPrefix = "",
                 columnName = "defaultConnectionIsValidated",
                 initialValue = false,
             )
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
index 36de2c1..a1f7a81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractor.kt
@@ -238,7 +238,6 @@
             .distinctUntilChanged()
             .logDiffsForTable(
                 tableLogBuffer = tableLogBuffer,
-                columnPrefix = "",
                 initialValue = DefaultIcon(defaultMobileIconGroup.value),
             )
             .stateIn(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
index be9d8f7..171e4f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModel.kt
@@ -191,7 +191,6 @@
             .distinctUntilChanged()
             .logDiffsForTable(
                 iconInteractor.tableLogBuffer,
-                columnPrefix = "",
                 columnName = "visible",
                 initialValue = false,
             )
@@ -249,7 +248,6 @@
             .distinctUntilChanged()
             .logDiffsForTable(
                 iconInteractor.tableLogBuffer,
-                columnPrefix = "",
                 columnName = "showNetworkTypeIcon",
                 initialValue = false,
             )
@@ -293,7 +291,6 @@
         iconInteractor.isRoaming
             .logDiffsForTable(
                 iconInteractor.tableLogBuffer,
-                columnPrefix = "",
                 columnName = "roaming",
                 initialValue = false,
             )
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt
index 88b4802..569e02c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/domain/interactor/DeviceBasedSatelliteInteractor.kt
@@ -63,12 +63,7 @@
                 flowOf(false)
             }
             .distinctUntilChanged()
-            .logDiffsForTable(
-                tableLog,
-                columnPrefix = "",
-                columnName = COL_ALLOWED,
-                initialValue = false,
-            )
+            .logDiffsForTable(tableLog, columnName = COL_ALLOWED, initialValue = false)
             .stateIn(scope, SharingStarted.WhileSubscribed(), false)
 
     /** See [SatelliteConnectionState] for relevant states */
@@ -80,11 +75,7 @@
                 flowOf(SatelliteConnectionState.Off)
             }
             .distinctUntilChanged()
-            .logDiffsForTable(
-                tableLog,
-                columnPrefix = "",
-                initialValue = SatelliteConnectionState.Off,
-            )
+            .logDiffsForTable(tableLog, initialValue = SatelliteConnectionState.Off)
             .stateIn(scope, SharingStarted.WhileSubscribed(), SatelliteConnectionState.Off)
 
     /** 0-4 description of the connection strength */
@@ -95,7 +86,7 @@
                 flowOf(0)
             }
             .distinctUntilChanged()
-            .logDiffsForTable(tableLog, columnPrefix = "", columnName = COL_LEVEL, initialValue = 0)
+            .logDiffsForTable(tableLog, columnName = COL_LEVEL, initialValue = 0)
             .stateIn(scope, SharingStarted.WhileSubscribed(), 0)
 
     val isSatelliteProvisioned = repo.isSatelliteProvisioned
@@ -119,12 +110,7 @@
                 isOosAndNotEmergencyAndNotSatellite.all { it }
             }
             .distinctUntilChanged()
-            .logDiffsForTable(
-                tableLog,
-                columnPrefix = "",
-                columnName = COL_ALL_OOS,
-                initialValue = true,
-            )
+            .logDiffsForTable(tableLog, columnName = COL_ALL_OOS, initialValue = true)
 
     /** When all connections are considered OOS, satellite connectivity is potentially valid */
     val areAllConnectionsOutOfService =
@@ -152,12 +138,7 @@
                 flowOf(false)
             }
             .distinctUntilChanged()
-            .logDiffsForTable(
-                tableLog,
-                columnPrefix = "",
-                columnName = COL_FULL_OOS,
-                initialValue = true,
-            )
+            .logDiffsForTable(tableLog, columnName = COL_FULL_OOS, initialValue = true)
             .stateIn(scope, SharingStarted.WhileSubscribed(), true)
 
     /** True if any known mobile network is currently using a non terrestrial network */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
index 5acedf1..a59d95f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
@@ -195,7 +195,6 @@
             .distinctUntilChanged()
             .logDiffsForTable(
                 tableLogBuffer = tableLogger,
-                columnPrefix = "",
                 columnName = COL_LOCK_TO_OCCLUDED,
                 initialValue = false,
             )
@@ -228,7 +227,6 @@
             .distinctUntilChanged()
             .logDiffsForTable(
                 tableLogBuffer = tableLogger,
-                columnPrefix = "",
                 columnName = COL_ALLOWED_BY_SCENE,
                 initialValue = false,
             )
@@ -248,7 +246,6 @@
             }
             .logDiffsForTable(
                 tableLogBuffer = tableLogger,
-                columnPrefix = "",
                 columnName = COL_NOTIF_LIGHTS_OUT,
                 initialValue = false,
             )
@@ -306,7 +303,6 @@
             .distinctUntilChanged()
             .logDiffsForTable(
                 tableLogBuffer = tableLogger,
-                columnPrefix = "",
                 columnName = COL_VISIBLE,
                 initialValue = false,
             )
@@ -350,7 +346,6 @@
             .distinctUntilChanged()
             .logDiffsForTable(
                 tableLogBuffer = tableLogger,
-                columnPrefix = "",
                 columnName = COL_SHOW_OPERATOR_NAME,
                 initialValue = false,
             )
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
index 115de28..f9bba9d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt
@@ -300,19 +300,14 @@
         wifiPickerTrackerInfo
             .map { it.state == WifiManager.WIFI_STATE_ENABLED }
             .distinctUntilChanged()
-            .logDiffsForTable(
-                tableLogger,
-                columnPrefix = "",
-                columnName = COL_NAME_IS_ENABLED,
-                initialValue = false,
-            )
+            .logDiffsForTable(tableLogger, columnName = COL_NAME_IS_ENABLED, initialValue = false)
             .stateIn(scope, SharingStarted.Eagerly, false)
 
     override val wifiNetwork: StateFlow<WifiNetworkModel> =
         wifiPickerTrackerInfo
             .map { it.primaryNetwork }
             .distinctUntilChanged()
-            .logDiffsForTable(tableLogger, columnPrefix = "", initialValue = WIFI_NETWORK_DEFAULT)
+            .logDiffsForTable(tableLogger, initialValue = WIFI_NETWORK_DEFAULT)
             .stateIn(scope, SharingStarted.Eagerly, WIFI_NETWORK_DEFAULT)
 
     override val secondaryNetworks: StateFlow<List<WifiNetworkModel>> =
@@ -321,7 +316,6 @@
             .distinctUntilChanged()
             .logDiffsForTable(
                 tableLogger,
-                columnPrefix = "",
                 columnName = "secondaryNetworks",
                 initialValue = emptyList(),
             )
@@ -400,12 +394,7 @@
         wifiPickerTrackerInfo
             .map { it.isDefault }
             .distinctUntilChanged()
-            .logDiffsForTable(
-                tableLogger,
-                columnPrefix = "",
-                columnName = COL_NAME_IS_DEFAULT,
-                initialValue = false,
-            )
+            .logDiffsForTable(tableLogger, columnName = COL_NAME_IS_DEFAULT, initialValue = false)
             .stateIn(scope, SharingStarted.Eagerly, false)
 
     override val wifiActivity: StateFlow<DataActivityModel> =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
index f9556d2..986068b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
@@ -89,7 +89,7 @@
                     else -> WifiIcon.Hidden
                 }
             }
-            .logDiffsForTable(wifiTableLogBuffer, columnPrefix = "", initialValue = WifiIcon.Hidden)
+            .logDiffsForTable(wifiTableLogBuffer, initialValue = WifiIcon.Hidden)
             .stateIn(
                 scope,
                 started = SharingStarted.WhileSubscribed(),
diff --git a/packages/SystemUI/src/com/android/systemui/window/ui/WindowRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/window/ui/WindowRootViewBinder.kt
index 7f4bfb0..e09a74c 100644
--- a/packages/SystemUI/src/com/android/systemui/window/ui/WindowRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/window/ui/WindowRootViewBinder.kt
@@ -26,6 +26,7 @@
 import com.android.systemui.scene.ui.view.WindowRootView
 import com.android.systemui.statusbar.BlurUtils
 import com.android.systemui.window.ui.viewmodel.WindowRootViewModel
+import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.awaitCancellation
 import kotlinx.coroutines.flow.filter
 import kotlinx.coroutines.launch
@@ -42,11 +43,12 @@
         viewModelFactory: WindowRootViewModel.Factory,
         blurUtils: BlurUtils?,
         choreographer: Choreographer?,
+        mainDispatcher: CoroutineDispatcher,
     ) {
         if (!Flags.bouncerUiRevamp() && !Flags.glanceableHubBlurredBackground()) return
         if (blurUtils == null || choreographer == null) return
 
-        view.repeatWhenAttached {
+        view.repeatWhenAttached(mainDispatcher) {
             Log.d(TAG, "Binding root view")
             var frameCallbackPendingExecution: FrameCallback? = null
             view.viewModel(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt
index b5eb904..676d8fa0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt
@@ -235,6 +235,7 @@
                 modifyNotification(context).also {
                     it.setSmallIcon(android.R.drawable.ic_media_pause)
                     it.setStyle(MediaStyle().apply { setMediaSession(session.sessionToken) })
+                    it.setContentIntent(getNewPendingIntent())
                 }
                 build()
             }
@@ -2156,6 +2157,28 @@
         verify(kosmos.mediaLogger, never()).logDuplicateMediaNotification(eq(KEY))
     }
 
+    @Test
+    @EnableFlags(Flags.FLAG_MEDIA_CONTROLS_POSTS_OPTIMIZATION)
+    fun postDifferentIntentNotifications_CallsListeners() {
+        addNotificationAndLoad()
+        reset(listener)
+        mediaNotification =
+            mediaNotification.also { it.notification.contentIntent = getNewPendingIntent() }
+        mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+
+        testScope.assertRunAllReady(foreground = 1, background = 1)
+        verify(listener)
+            .onMediaDataLoaded(
+                eq(KEY),
+                eq(KEY),
+                capture(mediaDataCaptor),
+                eq(true),
+                eq(0),
+                eq(false),
+            )
+        verify(kosmos.mediaLogger, never()).logDuplicateMediaNotification(eq(KEY))
+    }
+
     private fun TestScope.assertRunAllReady(foreground: Int = 0, background: Int = 0) {
         runCurrent()
         if (Flags.mediaLoadMetadataViaMediaDataLoader()) {
@@ -2235,4 +2258,14 @@
         backgroundExecutor.runAllReady()
         foregroundExecutor.runAllReady()
     }
+
+    private fun getNewPendingIntent(): PendingIntent {
+        val intent = Intent().setAction(null)
+        return PendingIntent.getBroadcast(
+            mContext,
+            1,
+            intent,
+            PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE,
+        )
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt
index 042d30e..496b319 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt
@@ -251,6 +251,7 @@
         verify(mediaTimeoutListener).stateCallback = capture(stateCallbackCaptor)
         verify(mediaTimeoutListener).sessionCallback = capture(sessionCallbackCaptor)
         session = MediaSession(context, "MediaDataProcessorTestSession")
+
         mediaNotification =
             SbnBuilder().run {
                 setUser(UserHandle(USER_ID))
@@ -258,6 +259,7 @@
                 modifyNotification(context).also {
                     it.setSmallIcon(android.R.drawable.ic_media_pause)
                     it.setStyle(MediaStyle().apply { setMediaSession(session.sessionToken) })
+                    it.setContentIntent(getNewPendingIntent())
                 }
                 build()
             }
@@ -2250,6 +2252,33 @@
         verify(kosmos.mediaLogger, never()).logDuplicateMediaNotification(eq(KEY))
     }
 
+    @Test
+    @EnableFlags(Flags.FLAG_MEDIA_CONTROLS_POSTS_OPTIMIZATION)
+    fun postDifferentIntentNotifications_CallsListeners() {
+        whenever(notificationLockscreenUserManager.isCurrentProfile(USER_ID)).thenReturn(true)
+        whenever(notificationLockscreenUserManager.isProfileAvailable(USER_ID)).thenReturn(true)
+
+        mediaDataProcessor.addInternalListener(mediaDataFilter)
+        mediaDataFilter.mediaDataProcessor = mediaDataProcessor
+        addNotificationAndLoad()
+        reset(listener)
+        mediaNotification =
+            mediaNotification.also { it.notification.contentIntent = getNewPendingIntent() }
+        mediaDataProcessor.onNotificationAdded(KEY, mediaNotification)
+
+        testScope.assertRunAllReady(foreground = 1, background = 1)
+        verify(listener)
+            .onMediaDataLoaded(
+                eq(KEY),
+                eq(KEY),
+                capture(mediaDataCaptor),
+                eq(true),
+                eq(0),
+                eq(false),
+            )
+        verify(kosmos.mediaLogger, never()).logDuplicateMediaNotification(eq(KEY))
+    }
+
     private fun TestScope.assertRunAllReady(foreground: Int = 0, background: Int = 0) {
         runCurrent()
         if (Flags.mediaLoadMetadataViaMediaDataLoader()) {
@@ -2329,4 +2358,14 @@
         runCurrent()
         advanceUntilIdle()
     }
+
+    private fun getNewPendingIntent(): PendingIntent {
+        val intent = Intent().setAction(null)
+        return PendingIntent.getBroadcast(
+            mContext,
+            1,
+            intent,
+            PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE,
+        )
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index 70450d2..49d6909 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -254,6 +254,7 @@
                 mock(BouncerViewBinder::class.java),
                 { mock(ConfigurationForwarder::class.java) },
                 brightnessMirrorShowingInteractor,
+                kosmos.testDispatcher,
             )
         underTest.setupExpandedStatusBar()
         underTest.setDragDownHelper(dragDownHelper)
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 8ef44ad..aef1c08 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -1095,6 +1095,10 @@
             proto.write(WidgetProto.MAX_HEIGHT,
                 widget.options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, 0));
         }
+        if (widget.views != null) {
+            proto.write(WidgetProto.VIEWS_BITMAP_MEMORY,
+                    widget.views.estimateTotalBitmapMemoryUsage());
+        }
         proto.end(token);
     }
 
@@ -2846,7 +2850,7 @@
                 // For a full update we replace the RemoteViews completely.
                 widget.views = views;
             }
-            int memoryUsage;
+            long memoryUsage;
             if ((UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) &&
                     (widget.views != null) &&
                     ((memoryUsage = widget.views.estimateMemoryUsage()) > mMaxWidgetBitmapMemory)) {
@@ -3503,6 +3507,8 @@
         }
         if (widget.views != null) {
             pw.print("    views="); pw.println(widget.views);
+            pw.print("    views_bitmap_memory=");
+            pw.println(widget.views.estimateTotalBitmapMemoryUsage());
         }
     }
 
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index 2d802b2..b6768c9 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -38,7 +38,6 @@
 import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.BiometricManager;
 import android.hardware.biometrics.ComponentInfoInternal;
-import android.hardware.biometrics.Flags;
 import android.hardware.biometrics.IAuthService;
 import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
 import android.hardware.biometrics.IBiometricService;
@@ -399,12 +398,6 @@
 
             final long identity = Binder.clearCallingIdentity();
             try {
-                // We can't do this above because we need the READ_DEVICE_CONFIG permission, which
-                // the calling user may not possess.
-                if (!Flags.lastAuthenticationTime()) {
-                    throw new UnsupportedOperationException();
-                }
-
                 return mBiometricService.getLastAuthenticationTime(userId, authenticators);
             } finally {
                 Binder.restoreCallingIdentity(identity);
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 15b1f22..a5058dd 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -44,7 +44,6 @@
 import android.hardware.biometrics.BiometricConstants;
 import android.hardware.biometrics.BiometricPrompt;
 import android.hardware.biometrics.BiometricStateListener;
-import android.hardware.biometrics.Flags;
 import android.hardware.biometrics.IBiometricAuthenticator;
 import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
 import android.hardware.biometrics.IBiometricSensorReceiver;
@@ -906,10 +905,6 @@
                 int userId, @Authenticators.Types int authenticators) {
             super.getLastAuthenticationTime_enforcePermission();
 
-            if (!Flags.lastAuthenticationTime()) {
-                throw new UnsupportedOperationException();
-            }
-
             Slogf.d(TAG, "getLastAuthenticationTime(userId=%d, authenticators=0x%x)",
                     userId, authenticators);
 
diff --git a/services/core/java/com/android/server/media/quality/MediaQualityService.java b/services/core/java/com/android/server/media/quality/MediaQualityService.java
index f6c94a7..d23a863 100644
--- a/services/core/java/com/android/server/media/quality/MediaQualityService.java
+++ b/services/core/java/com/android/server/media/quality/MediaQualityService.java
@@ -73,6 +73,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.server.SystemService;
 import com.android.server.utils.Slogf;
 
@@ -122,6 +123,13 @@
     private SharedPreferences mPictureProfileSharedPreference;
     private SharedPreferences mSoundProfileSharedPreference;
 
+    // A global lock for picture profile objects.
+    private final Object mPictureProfileLock = new Object();
+    // A global lock for sound profile objects.
+    private final Object mSoundProfileLock = new Object();
+    // A global lock for ambient backlight objects.
+    private final Object mAmbientBacklightLock = new Object();
+
     public MediaQualityService(Context context) {
         super(context);
         mContext = context;
@@ -254,6 +262,7 @@
     // TODO: Add additional APIs. b/373951081
     private final class BinderService extends IMediaQualityManager.Stub {
 
+        @GuardedBy("mPictureProfileLock")
         @Override
         public PictureProfile createPictureProfile(PictureProfile pp, UserHandle user) {
             if ((pp.getPackageName() != null && !pp.getPackageName().isEmpty()
@@ -263,24 +272,27 @@
                         Binder.getCallingUid(), Binder.getCallingPid());
             }
 
-            SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase();
+            synchronized (mPictureProfileLock) {
+                SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase();
 
-            ContentValues values = getContentValues(null,
-                    pp.getProfileType(),
-                    pp.getName(),
-                    pp.getPackageName() == null || pp.getPackageName().isEmpty()
-                            ? getPackageOfCallingUid() : pp.getPackageName(),
-                    pp.getInputId(),
-                    pp.getParameters());
+                ContentValues values = getContentValues(null,
+                        pp.getProfileType(),
+                        pp.getName(),
+                        pp.getPackageName() == null || pp.getPackageName().isEmpty()
+                                ? getPackageOfCallingUid() : pp.getPackageName(),
+                        pp.getInputId(),
+                        pp.getParameters());
 
-            // id is auto-generated by SQLite upon successful insertion of row
-            Long id = db.insert(mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME,
-                    null, values);
-            populateTempIdMap(mPictureProfileTempIdMap, id);
-            String value = mPictureProfileTempIdMap.getValue(id);
-            pp.setProfileId(value);
-            notifyOnPictureProfileAdded(value, pp, Binder.getCallingUid(), Binder.getCallingPid());
-            return pp;
+                // id is auto-generated by SQLite upon successful insertion of row
+                Long id = db.insert(mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME,
+                        null, values);
+                populateTempIdMap(mPictureProfileTempIdMap, id);
+                String value = mPictureProfileTempIdMap.getValue(id);
+                pp.setProfileId(value);
+                notifyOnPictureProfileAdded(value, pp, Binder.getCallingUid(),
+                        Binder.getCallingPid());
+                return pp;
+            }
         }
 
         private void notifyHalOnPictureProfileChange(Long dbId, PersistableBundle params) {
@@ -307,6 +319,7 @@
             return toReturn;
         }
 
+        @GuardedBy("mPictureProfileLock")
         @Override
         public void updatePictureProfile(String id, PictureProfile pp, UserHandle user) {
             Long dbId = mPictureProfileTempIdMap.getKey(id);
@@ -315,12 +328,13 @@
                         Binder.getCallingUid(), Binder.getCallingPid());
             }
 
-            ContentValues values = getContentValues(dbId,
-                    pp.getProfileType(),
-                    pp.getName(),
-                    pp.getPackageName(),
-                    pp.getInputId(),
-                    pp.getParameters());
+            synchronized (mPictureProfileLock) {
+                ContentValues values = getContentValues(dbId,
+                        pp.getProfileType(),
+                        pp.getName(),
+                        pp.getPackageName(),
+                        pp.getInputId(),
+                        pp.getParameters());
 
             SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase();
             db.replace(mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME,
@@ -328,6 +342,7 @@
             notifyOnPictureProfileUpdated(mPictureProfileTempIdMap.getValue(dbId),
                     getPictureProfile(dbId), Binder.getCallingUid(), Binder.getCallingPid());
             notifyHalOnPictureProfileChange(dbId, pp.getParameters());
+            }
         }
 
         private boolean hasPermissionToUpdatePictureProfile(Long dbId, PictureProfile toUpdate) {
@@ -338,30 +353,33 @@
                     && fromDb.getName().equals(getPackageOfCallingUid());
         }
 
+        @GuardedBy("mPictureProfileLock")
         @Override
         public void removePictureProfile(String id, UserHandle user) {
-            Long dbId = mPictureProfileTempIdMap.getKey(id);
+            synchronized (mPictureProfileLock) {
+                Long dbId = mPictureProfileTempIdMap.getKey(id);
 
-            PictureProfile toDelete = getPictureProfile(dbId);
-            if (!hasPermissionToRemovePictureProfile(toDelete)) {
-                notifyOnPictureProfileError(id, PictureProfile.ERROR_NO_PERMISSION,
-                        Binder.getCallingUid(), Binder.getCallingPid());
-            }
-
-            if (dbId != null) {
-                SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase();
-                String selection = BaseParameters.PARAMETER_ID + " = ?";
-                String[] selectionArgs = {Long.toString(dbId)};
-                int result = db.delete(mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME, selection,
-                        selectionArgs);
-                if (result == 0) {
-                    notifyOnPictureProfileError(id, PictureProfile.ERROR_INVALID_ARGUMENT,
+                PictureProfile toDelete = getPictureProfile(dbId);
+                if (!hasPermissionToRemovePictureProfile(toDelete)) {
+                    notifyOnPictureProfileError(id, PictureProfile.ERROR_NO_PERMISSION,
                             Binder.getCallingUid(), Binder.getCallingPid());
                 }
-                notifyOnPictureProfileRemoved(mPictureProfileTempIdMap.getValue(dbId), toDelete,
-                        Binder.getCallingUid(), Binder.getCallingPid());
-                mPictureProfileTempIdMap.remove(dbId);
-                notifyHalOnPictureProfileChange(dbId, null);
+
+                if (dbId != null) {
+                    SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase();
+                    String selection = BaseParameters.PARAMETER_ID + " = ?";
+                    String[] selectionArgs = {Long.toString(dbId)};
+                    int result = db.delete(mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME,
+                            selection, selectionArgs);
+                    if (result == 0) {
+                        notifyOnPictureProfileError(id, PictureProfile.ERROR_INVALID_ARGUMENT,
+                                Binder.getCallingUid(), Binder.getCallingPid());
+                    }
+                    notifyOnPictureProfileRemoved(mPictureProfileTempIdMap.getValue(dbId), toDelete,
+                            Binder.getCallingUid(), Binder.getCallingPid());
+                    mPictureProfileTempIdMap.remove(dbId);
+                    notifyHalOnPictureProfileChange(dbId, null);
+                }
             }
         }
 
@@ -372,6 +390,7 @@
             return false;
         }
 
+        @GuardedBy("mPictureProfileLock")
         @Override
         public PictureProfile getPictureProfile(int type, String name, Bundle options,
                 UserHandle user) {
@@ -382,23 +401,27 @@
                     + BaseParameters.PARAMETER_PACKAGE + " = ?";
             String[] selectionArguments = {Integer.toString(type), name, getPackageOfCallingUid()};
 
-            try (
-                    Cursor cursor = getCursorAfterQuerying(
-                            mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME,
-                            getMediaProfileColumns(includeParams), selection, selectionArguments)
-            ) {
-                int count = cursor.getCount();
-                if (count == 0) {
-                    return null;
+            synchronized (mPictureProfileLock) {
+                try (
+                        Cursor cursor = getCursorAfterQuerying(
+                                mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME,
+                                getMediaProfileColumns(includeParams), selection,
+                                selectionArguments)
+                ) {
+                    int count = cursor.getCount();
+                    if (count == 0) {
+                        return null;
+                    }
+                    if (count > 1) {
+                        Log.wtf(TAG, TextUtils.formatSimple(String.valueOf(Locale.US), "%d "
+                                        + "entries found for type=%d and name=%s in %s. Should"
+                                        + " only ever be 0 or 1.", count, type, name,
+                                mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME));
+                        return null;
+                    }
+                    cursor.moveToFirst();
+                    return convertCursorToPictureProfileWithTempId(cursor);
                 }
-                if (count > 1) {
-                    Log.wtf(TAG, String.format(Locale.US, "%d entries found for type=%d and name=%s"
-                                    + " in %s. Should only ever be 0 or 1.", count, type, name,
-                            mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME));
-                    return null;
-                }
-                cursor.moveToFirst();
-                return convertCursorToPictureProfileWithTempId(cursor);
             }
         }
 
@@ -416,9 +439,9 @@
                     return null;
                 }
                 if (count > 1) {
-                    Log.wtf(TAG, String.format(Locale.US, "%d entries found for id=%d"
-                                    + " in %s. Should only ever be 0 or 1.", count, dbId,
-                            mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME));
+                    Log.wtf(TAG, TextUtils.formatSimple(String.valueOf(Locale.US), "%d entries "
+                                    + "found for id=%d in %s. Should only ever be 0 or 1.",
+                            count, dbId, mMediaQualityDbHelper.PICTURE_QUALITY_TABLE_NAME));
                     return null;
                 }
                 cursor.moveToFirst();
@@ -426,6 +449,7 @@
             }
         }
 
+        @GuardedBy("mPictureProfileLock")
         @Override
         public List<PictureProfile> getPictureProfilesByPackage(
                 String packageName, Bundle options, UserHandle user) {
@@ -434,14 +458,17 @@
                         Binder.getCallingUid(), Binder.getCallingPid());
             }
 
-            boolean includeParams =
-                    options.getBoolean(MediaQualityManager.OPTION_INCLUDE_PARAMETERS, false);
-            String selection = BaseParameters.PARAMETER_PACKAGE + " = ?";
-            String[] selectionArguments = {packageName};
-            return getPictureProfilesBasedOnConditions(getMediaProfileColumns(includeParams),
-                    selection, selectionArguments);
+            synchronized (mPictureProfileLock) {
+                boolean includeParams =
+                        options.getBoolean(MediaQualityManager.OPTION_INCLUDE_PARAMETERS, false);
+                String selection = BaseParameters.PARAMETER_PACKAGE + " = ?";
+                String[] selectionArguments = {packageName};
+                return getPictureProfilesBasedOnConditions(getMediaProfileColumns(includeParams),
+                        selection, selectionArguments);
+            }
         }
 
+        @GuardedBy("mPictureProfileLock")
         @Override
         public List<PictureProfile> getAvailablePictureProfiles(Bundle options, UserHandle user) {
             String packageName = getPackageOfCallingUid();
@@ -451,6 +478,7 @@
             return new ArrayList<>();
         }
 
+        @GuardedBy("mPictureProfileLock")
         @Override
         public boolean setDefaultPictureProfile(String profileId, UserHandle user) {
             if (!hasGlobalPictureQualityServicePermission()) {
@@ -810,6 +838,7 @@
             return  (PictureParameter[]) pictureParams.toArray();
         }
 
+        @GuardedBy("mPictureProfileLock")
         @Override
         public List<String> getPictureProfilePackageNames(UserHandle user) {
             if (!hasGlobalPictureQualityServicePermission()) {
@@ -817,42 +846,51 @@
                         Binder.getCallingUid(), Binder.getCallingPid());
             }
             String [] column = {BaseParameters.PARAMETER_PACKAGE};
-            List<PictureProfile> pictureProfiles = getPictureProfilesBasedOnConditions(column,
-                    null, null);
-            return pictureProfiles.stream()
-                    .map(PictureProfile::getPackageName)
-                    .distinct()
-                    .collect(Collectors.toList());
+            synchronized (mPictureProfileLock) {
+                List<PictureProfile> pictureProfiles = getPictureProfilesBasedOnConditions(column,
+                        null, null);
+                return pictureProfiles.stream()
+                        .map(PictureProfile::getPackageName)
+                        .distinct()
+                        .collect(Collectors.toList());
+            }
         }
 
+        @GuardedBy("mPictureProfileLock")
         @Override
         public List<PictureProfileHandle> getPictureProfileHandle(String[] ids, UserHandle user) {
             List<PictureProfileHandle> toReturn = new ArrayList<>();
-            for (String id : ids) {
-                Long key = mPictureProfileTempIdMap.getKey(id);
-                if (key != null) {
-                    toReturn.add(new PictureProfileHandle(key));
-                } else {
-                    toReturn.add(null);
+            synchronized (mPictureProfileLock) {
+                for (String id : ids) {
+                    Long key = mPictureProfileTempIdMap.getKey(id);
+                    if (key != null) {
+                        toReturn.add(new PictureProfileHandle(key));
+                    } else {
+                        toReturn.add(null);
+                    }
                 }
             }
             return toReturn;
         }
 
+        @GuardedBy("mSoundProfileLock")
         @Override
         public List<SoundProfileHandle> getSoundProfileHandle(String[] ids, UserHandle user) {
             List<SoundProfileHandle> toReturn = new ArrayList<>();
-            for (String id : ids) {
-                Long key = mSoundProfileTempIdMap.getKey(id);
-                if (key != null) {
-                    toReturn.add(new SoundProfileHandle(key));
-                } else {
-                    toReturn.add(null);
+            synchronized (mSoundProfileLock) {
+                for (String id : ids) {
+                    Long key = mSoundProfileTempIdMap.getKey(id);
+                    if (key != null) {
+                        toReturn.add(new SoundProfileHandle(key));
+                    } else {
+                        toReturn.add(null);
+                    }
                 }
             }
             return toReturn;
         }
 
+        @GuardedBy("mSoundProfileLock")
         @Override
         public SoundProfile createSoundProfile(SoundProfile sp, UserHandle user) {
             if ((sp.getPackageName() != null && !sp.getPackageName().isEmpty()
@@ -861,24 +899,28 @@
                 notifyOnSoundProfileError(null, SoundProfile.ERROR_NO_PERMISSION,
                         Binder.getCallingUid(), Binder.getCallingPid());
             }
-            SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase();
 
-            ContentValues values = getContentValues(null,
-                    sp.getProfileType(),
-                    sp.getName(),
-                    sp.getPackageName() == null || sp.getPackageName().isEmpty()
-                            ? getPackageOfCallingUid() : sp.getPackageName(),
-                    sp.getInputId(),
-                    sp.getParameters());
+            synchronized (mSoundProfileLock) {
+                SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase();
 
-            // id is auto-generated by SQLite upon successful insertion of row
-            Long id = db.insert(mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME,
-                    null, values);
-            populateTempIdMap(mSoundProfileTempIdMap, id);
-            String value = mSoundProfileTempIdMap.getValue(id);
-            sp.setProfileId(value);
-            notifyOnSoundProfileAdded(value, sp, Binder.getCallingUid(), Binder.getCallingPid());
-            return sp;
+                ContentValues values = getContentValues(null,
+                        sp.getProfileType(),
+                        sp.getName(),
+                        sp.getPackageName() == null || sp.getPackageName().isEmpty()
+                                ? getPackageOfCallingUid() : sp.getPackageName(),
+                        sp.getInputId(),
+                        sp.getParameters());
+
+                // id is auto-generated by SQLite upon successful insertion of row
+                Long id = db.insert(mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME,
+                        null, values);
+                populateTempIdMap(mSoundProfileTempIdMap, id);
+                String value = mSoundProfileTempIdMap.getValue(id);
+                sp.setProfileId(value);
+                notifyOnSoundProfileAdded(value, sp, Binder.getCallingUid(),
+                        Binder.getCallingPid());
+                return sp;
+            }
         }
 
         private void notifyHalOnSoundProfileChange(Long dbId, PersistableBundle params) {
@@ -903,6 +945,7 @@
             return toReturn;
         }
 
+        @GuardedBy("mSoundProfileLock")
         @Override
         public void updateSoundProfile(String id, SoundProfile sp, UserHandle user) {
             Long dbId = mSoundProfileTempIdMap.getKey(id);
@@ -911,18 +954,20 @@
                         Binder.getCallingUid(), Binder.getCallingPid());
             }
 
-            ContentValues values = getContentValues(dbId,
-                    sp.getProfileType(),
-                    sp.getName(),
-                    sp.getPackageName(),
-                    sp.getInputId(),
-                    sp.getParameters());
+            synchronized (mSoundProfileLock) {
+                ContentValues values = getContentValues(dbId,
+                        sp.getProfileType(),
+                        sp.getName(),
+                        sp.getPackageName(),
+                        sp.getInputId(),
+                        sp.getParameters());
 
             SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase();
             db.replace(mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME, null, values);
             notifyOnSoundProfileUpdated(mSoundProfileTempIdMap.getValue(dbId),
                     getSoundProfile(dbId), Binder.getCallingUid(), Binder.getCallingPid());
             notifyHalOnSoundProfileChange(dbId, sp.getParameters());
+            }
         }
 
         private boolean hasPermissionToUpdateSoundProfile(Long dbId, SoundProfile sp) {
@@ -933,29 +978,32 @@
                     && fromDb.getName().equals(getPackageOfCallingUid());
         }
 
+        @GuardedBy("mSoundProfileLock")
         @Override
         public void removeSoundProfile(String id, UserHandle user) {
-            Long dbId = mSoundProfileTempIdMap.getKey(id);
-            SoundProfile toDelete = getSoundProfile(dbId);
-            if (!hasPermissionToRemoveSoundProfile(toDelete)) {
-                notifyOnSoundProfileError(id, SoundProfile.ERROR_NO_PERMISSION,
-                        Binder.getCallingUid(), Binder.getCallingPid());
-            }
-
-            if (dbId != null) {
-                SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase();
-                String selection = BaseParameters.PARAMETER_ID + " = ?";
-                String[] selectionArgs = {Long.toString(dbId)};
-                int result = db.delete(mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME, selection,
-                        selectionArgs);
-                if (result == 0) {
-                    notifyOnSoundProfileError(id, SoundProfile.ERROR_INVALID_ARGUMENT,
+            synchronized (mSoundProfileLock) {
+                Long dbId = mSoundProfileTempIdMap.getKey(id);
+                SoundProfile toDelete = getSoundProfile(dbId);
+                if (!hasPermissionToRemoveSoundProfile(toDelete)) {
+                    notifyOnSoundProfileError(id, SoundProfile.ERROR_NO_PERMISSION,
                             Binder.getCallingUid(), Binder.getCallingPid());
                 }
-                notifyOnSoundProfileRemoved(mSoundProfileTempIdMap.getValue(dbId), toDelete,
-                        Binder.getCallingUid(), Binder.getCallingPid());
-                mSoundProfileTempIdMap.remove(dbId);
-                notifyHalOnSoundProfileChange(dbId, null);
+                if (dbId != null) {
+                    SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase();
+                    String selection = BaseParameters.PARAMETER_ID + " = ?";
+                    String[] selectionArgs = {Long.toString(dbId)};
+                    int result = db.delete(mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME,
+                            selection,
+                            selectionArgs);
+                    if (result == 0) {
+                        notifyOnSoundProfileError(id, SoundProfile.ERROR_INVALID_ARGUMENT,
+                                Binder.getCallingUid(), Binder.getCallingPid());
+                    }
+                    notifyOnSoundProfileRemoved(mSoundProfileTempIdMap.getValue(dbId), toDelete,
+                            Binder.getCallingUid(), Binder.getCallingPid());
+                    mSoundProfileTempIdMap.remove(dbId);
+                    notifyHalOnSoundProfileChange(dbId, null);
+                }
             }
         }
 
@@ -966,6 +1014,7 @@
             return false;
         }
 
+        @GuardedBy("mSoundProfileLock")
         @Override
         public SoundProfile getSoundProfile(int type, String name, Bundle options,
                 UserHandle user) {
@@ -976,23 +1025,27 @@
                     + BaseParameters.PARAMETER_PACKAGE + " = ?";
             String[] selectionArguments = {String.valueOf(type), name, getPackageOfCallingUid()};
 
-            try (
-                    Cursor cursor = getCursorAfterQuerying(
-                            mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME,
-                            getMediaProfileColumns(includeParams), selection, selectionArguments)
-            ) {
-                int count = cursor.getCount();
-                if (count == 0) {
-                    return null;
+            synchronized (mSoundProfileLock) {
+                try (
+                        Cursor cursor = getCursorAfterQuerying(
+                                mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME,
+                                getMediaProfileColumns(includeParams), selection,
+                                selectionArguments)
+                ) {
+                    int count = cursor.getCount();
+                    if (count == 0) {
+                        return null;
+                    }
+                    if (count > 1) {
+                        Log.wtf(TAG, TextUtils.formatSimple(String.valueOf(Locale.US), "%d "
+                                        + "entries found for name=%s in %s. Should only ever "
+                                        + "be 0 or 1.", String.valueOf(count), name,
+                                mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME));
+                        return null;
+                    }
+                    cursor.moveToFirst();
+                    return convertCursorToSoundProfileWithTempId(cursor);
                 }
-                if (count > 1) {
-                    Log.wtf(TAG, String.format(Locale.US, "%d entries found for name=%s"
-                                    + " in %s. Should only ever be 0 or 1.", count, name,
-                            mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME));
-                    return null;
-                }
-                cursor.moveToFirst();
-                return convertCursorToSoundProfileWithTempId(cursor);
             }
         }
 
@@ -1010,9 +1063,9 @@
                     return null;
                 }
                 if (count > 1) {
-                    Log.wtf(TAG, String.format(Locale.US, "%d entries found for id=%s "
-                                    + "in %s. Should only ever be 0 or 1.", count, dbId,
-                            mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME));
+                    Log.wtf(TAG, TextUtils.formatSimple(String.valueOf(Locale.US), "%d entries "
+                                    + "found for id=%s in %s. Should only ever be 0 or 1.", count,
+                            dbId, mMediaQualityDbHelper.SOUND_QUALITY_TABLE_NAME));
                     return null;
                 }
                 cursor.moveToFirst();
@@ -1020,6 +1073,7 @@
             }
         }
 
+        @GuardedBy("mSoundProfileLock")
         @Override
         public List<SoundProfile> getSoundProfilesByPackage(
                 String packageName, Bundle options, UserHandle user) {
@@ -1028,14 +1082,17 @@
                         Binder.getCallingUid(), Binder.getCallingPid());
             }
 
-            boolean includeParams =
-                    options.getBoolean(MediaQualityManager.OPTION_INCLUDE_PARAMETERS, false);
-            String selection = BaseParameters.PARAMETER_PACKAGE + " = ?";
-            String[] selectionArguments = {packageName};
-            return getSoundProfilesBasedOnConditions(getMediaProfileColumns(includeParams),
-                    selection, selectionArguments);
+            synchronized (mSoundProfileLock) {
+                boolean includeParams =
+                        options.getBoolean(MediaQualityManager.OPTION_INCLUDE_PARAMETERS, false);
+                String selection = BaseParameters.PARAMETER_PACKAGE + " = ?";
+                String[] selectionArguments = {packageName};
+                return getSoundProfilesBasedOnConditions(getMediaProfileColumns(includeParams),
+                        selection, selectionArguments);
+            }
         }
 
+        @GuardedBy("mSoundProfileLock")
         @Override
         public List<SoundProfile> getAvailableSoundProfiles(Bundle options, UserHandle user) {
             String packageName = getPackageOfCallingUid();
@@ -1045,6 +1102,7 @@
             return new ArrayList<>();
         }
 
+        @GuardedBy("mSoundProfileLock")
         @Override
         public boolean setDefaultSoundProfile(String profileId, UserHandle user) {
             if (!hasGlobalSoundQualityServicePermission()) {
@@ -1161,6 +1219,7 @@
             return  (SoundParameter[]) soundParams.toArray();
         }
 
+        @GuardedBy("mSoundProfileLock")
         @Override
         public List<String> getSoundProfilePackageNames(UserHandle user) {
             if (!hasGlobalSoundQualityServicePermission()) {
@@ -1168,12 +1227,15 @@
                         Binder.getCallingUid(), Binder.getCallingPid());
             }
             String [] column = {BaseParameters.PARAMETER_NAME};
-            List<SoundProfile> soundProfiles = getSoundProfilesBasedOnConditions(column,
-                    null, null);
-            return soundProfiles.stream()
-                    .map(SoundProfile::getPackageName)
-                    .distinct()
-                    .collect(Collectors.toList());
+
+            synchronized (mSoundProfileLock) {
+                List<SoundProfile> soundProfiles = getSoundProfilesBasedOnConditions(column,
+                        null, null);
+                return soundProfiles.stream()
+                        .map(SoundProfile::getPackageName)
+                        .distinct()
+                        .collect(Collectors.toList());
+            }
         }
 
         private String getPackageOfCallingUid() {
@@ -1539,6 +1601,7 @@
             userState.mSoundProfileCallbacks.finishBroadcast();
         }
 
+        //TODO: need lock here?
         @Override
         public void registerPictureProfileCallback(final IPictureProfileCallback callback) {
             int callingPid = Binder.getCallingPid();
@@ -1549,6 +1612,7 @@
                     Pair.create(callingPid, callingUid));
         }
 
+        //TODO: need lock here?
         @Override
         public void registerSoundProfileCallback(final ISoundProfileCallback callback) {
             int callingPid = Binder.getCallingPid();
@@ -1586,6 +1650,7 @@
             }
         }
 
+        @GuardedBy("mAmbientBacklightLock")
         @Override
         public void setAmbientBacklightSettings(
                 AmbientBacklightSettings settings, UserHandle user) {
@@ -1624,6 +1689,7 @@
             }
         }
 
+        @GuardedBy("mAmbientBacklightLock")
         @Override
         public void setAmbientBacklightEnabled(boolean enabled, UserHandle user) {
             if (DEBUG) {
@@ -1643,12 +1709,14 @@
             }
         }
 
+        //TODO: do I need a lock here?
         @Override
         public List<ParameterCapability> getParameterCapabilities(
                 List<String> names, UserHandle user) {
             return new ArrayList<>();
         }
 
+        @GuardedBy("mPictureProfileLock")
         @Override
         public List<String> getPictureProfileAllowList(UserHandle user) {
             if (!hasGlobalPictureQualityServicePermission()) {
@@ -1663,6 +1731,7 @@
             return new ArrayList<>();
         }
 
+        @GuardedBy("mPictureProfileLock")
         @Override
         public void setPictureProfileAllowList(List<String> packages, UserHandle user) {
             if (!hasGlobalPictureQualityServicePermission()) {
@@ -1674,6 +1743,7 @@
             editor.commit();
         }
 
+        @GuardedBy("mSoundProfileLock")
         @Override
         public List<String> getSoundProfileAllowList(UserHandle user) {
             if (!hasGlobalSoundQualityServicePermission()) {
@@ -1688,6 +1758,7 @@
             return new ArrayList<>();
         }
 
+        @GuardedBy("mSoundProfileLock")
         @Override
         public void setSoundProfileAllowList(List<String> packages, UserHandle user) {
             if (!hasGlobalSoundQualityServicePermission()) {
@@ -1704,70 +1775,81 @@
             return false;
         }
 
+        @GuardedBy("mPictureProfileLock")
         @Override
         public void setAutoPictureQualityEnabled(boolean enabled, UserHandle user) {
             if (!hasGlobalPictureQualityServicePermission()) {
                 notifyOnPictureProfileError(null, PictureProfile.ERROR_NO_PERMISSION,
                         Binder.getCallingUid(), Binder.getCallingPid());
             }
-
-            try {
-                if (mMediaQuality != null) {
-                    if (mMediaQuality.isAutoPqSupported()) {
-                        mMediaQuality.setAutoPqEnabled(enabled);
+            synchronized (mPictureProfileLock) {
+                try {
+                    if (mMediaQuality != null) {
+                        if (mMediaQuality.isAutoPqSupported()) {
+                            mMediaQuality.setAutoPqEnabled(enabled);
+                        }
                     }
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Failed to set auto picture quality", e);
                 }
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Failed to set auto picture quality", e);
             }
         }
 
+        @GuardedBy("mPictureProfileLock")
         @Override
         public boolean isAutoPictureQualityEnabled(UserHandle user) {
-            try {
-                if (mMediaQuality != null) {
-                    if (mMediaQuality.isAutoPqSupported()) {
-                        return mMediaQuality.getAutoPqEnabled();
+            synchronized (mPictureProfileLock) {
+                try {
+                    if (mMediaQuality != null) {
+                        if (mMediaQuality.isAutoPqSupported()) {
+                            return mMediaQuality.getAutoPqEnabled();
+                        }
                     }
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Failed to get auto picture quality", e);
                 }
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Failed to get auto picture quality", e);
+                return false;
             }
-            return false;
         }
 
+        @GuardedBy("mPictureProfileLock")
         @Override
         public void setSuperResolutionEnabled(boolean enabled, UserHandle user) {
             if (!hasGlobalPictureQualityServicePermission()) {
                 notifyOnPictureProfileError(null, PictureProfile.ERROR_NO_PERMISSION,
                         Binder.getCallingUid(), Binder.getCallingPid());
             }
-
-            try {
-                if (mMediaQuality != null) {
-                    if (mMediaQuality.isAutoSrSupported()) {
-                        mMediaQuality.setAutoSrEnabled(enabled);
+            synchronized (mPictureProfileLock) {
+                try {
+                    if (mMediaQuality != null) {
+                        if (mMediaQuality.isAutoSrSupported()) {
+                            mMediaQuality.setAutoSrEnabled(enabled);
+                        }
                     }
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Failed to set super resolution", e);
                 }
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Failed to set super resolution", e);
             }
         }
 
+        @GuardedBy("mPictureProfileLock")
         @Override
         public boolean isSuperResolutionEnabled(UserHandle user) {
-            try {
-                if (mMediaQuality != null) {
-                    if (mMediaQuality.isAutoSrSupported()) {
-                        return mMediaQuality.getAutoSrEnabled();
+            synchronized (mPictureProfileLock) {
+                try {
+                    if (mMediaQuality != null) {
+                        if (mMediaQuality.isAutoSrSupported()) {
+                            return mMediaQuality.getAutoSrEnabled();
+                        }
                     }
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Failed to get super resolution", e);
                 }
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Failed to get super resolution", e);
+                return false;
             }
-            return false;
         }
 
+        @GuardedBy("mSoundProfileLock")
         @Override
         public void setAutoSoundQualityEnabled(boolean enabled, UserHandle user) {
             if (!hasGlobalSoundQualityServicePermission()) {
@@ -1775,31 +1857,37 @@
                         Binder.getCallingUid(), Binder.getCallingPid());
             }
 
-            try {
-                if (mMediaQuality != null) {
-                    if (mMediaQuality.isAutoAqSupported()) {
-                        mMediaQuality.setAutoAqEnabled(enabled);
+            synchronized (mSoundProfileLock) {
+                try {
+                    if (mMediaQuality != null) {
+                        if (mMediaQuality.isAutoAqSupported()) {
+                            mMediaQuality.setAutoAqEnabled(enabled);
+                        }
                     }
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Failed to set auto sound quality", e);
                 }
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Failed to set auto sound quality", e);
             }
         }
 
+        @GuardedBy("mSoundProfileLock")
         @Override
         public boolean isAutoSoundQualityEnabled(UserHandle user) {
-            try {
-                if (mMediaQuality != null) {
-                    if (mMediaQuality.isAutoAqSupported()) {
-                        return mMediaQuality.getAutoAqEnabled();
+            synchronized (mSoundProfileLock) {
+                try {
+                    if (mMediaQuality != null) {
+                        if (mMediaQuality.isAutoAqSupported()) {
+                            return mMediaQuality.getAutoAqEnabled();
+                        }
                     }
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Failed to get auto sound quality", e);
                 }
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Failed to get auto sound quality", e);
+                return false;
             }
-            return false;
         }
 
+        @GuardedBy("mAmbientBacklightLock")
         @Override
         public boolean isAmbientBacklightEnabled(UserHandle user) {
             return false;
@@ -1853,6 +1941,7 @@
         }
     }
 
+    //TODO: used by both picture and sound. can i add both locks?
     private UserState getOrCreateUserStateLocked(int userId) {
         UserState userState = getUserStateLocked(userId);
         if (userState == null) {
@@ -1862,6 +1951,7 @@
         return userState;
     }
 
+    //TODO: used by both picture and sound. can i add both locks?
     private UserState getUserStateLocked(int userId) {
         return mUserStates.get(userId);
     }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 2305f1b..a16b122 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -8898,7 +8898,7 @@
         if (contentView == null) {
             return false;
         }
-        final int contentViewSize = contentView.estimateMemoryUsage();
+        final long contentViewSize = contentView.estimateMemoryUsage();
         if (contentViewSize > mWarnRemoteViewsSizeBytes
                 && contentViewSize < mStripRemoteViewsSizeBytes) {
             Slog.w(TAG, "RemoteViews too large on pkg: " + pkg + " tag: " + tag + " id: " + id
diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java
index b8b49f3e..f9758fc 100644
--- a/services/core/java/com/android/server/om/OverlayManagerSettings.java
+++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java
@@ -26,13 +26,13 @@
 import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.IndentingPrintWriter;
 import android.util.Pair;
 import android.util.Slog;
 import android.util.Xml;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.CollectionUtils;
-import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.XmlUtils;
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
@@ -49,7 +49,6 @@
 import java.util.Set;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
-import java.util.stream.Stream;
 
 /**
  * Data structure representing the current state of all overlay packages in the
@@ -358,26 +357,29 @@
     }
 
     void dump(@NonNull final PrintWriter p, @NonNull DumpState dumpState) {
-        // select items to display
-        Stream<SettingsItem> items = mItems.stream();
-        if (dumpState.getUserId() != UserHandle.USER_ALL) {
-            items = items.filter(item -> item.mUserId == dumpState.getUserId());
-        }
-        if (dumpState.getPackageName() != null) {
-            items = items.filter(item -> item.mOverlay.getPackageName()
-                    .equals(dumpState.getPackageName()));
-        }
-        if (dumpState.getOverlayName() != null) {
-            items = items.filter(item -> item.mOverlay.getOverlayName()
-                    .equals(dumpState.getOverlayName()));
-        }
+        final int userId = dumpState.getUserId();
+        final String packageName = dumpState.getPackageName();
+        final String overlayName = dumpState.getOverlayName();
+        final String field = dumpState.getField();
+        final var pw = new IndentingPrintWriter(p, "  ");
 
-        // display items
-        final IndentingPrintWriter pw = new IndentingPrintWriter(p, "  ");
-        if (dumpState.getField() != null) {
-            items.forEach(item -> dumpSettingsItemField(pw, item, dumpState.getField()));
-        } else {
-            items.forEach(item -> dumpSettingsItem(pw, item));
+        for (int i = 0; i < mItems.size(); i++) {
+            final var item = mItems.get(i);
+            if (userId != UserHandle.USER_ALL && userId != item.mUserId) {
+                continue;
+            }
+            if (packageName != null && !packageName.equals(item.mOverlay.getPackageName())) {
+                continue;
+            }
+            if (overlayName != null && !overlayName.equals(item.mOverlay.getOverlayName())) {
+                continue;
+            }
+
+            if (field != null) {
+                dumpSettingsItemField(pw, item, field);
+            } else {
+                dumpSettingsItem(pw, item);
+            }
         }
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
index 605fed0..c7efa31 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java
@@ -45,7 +45,6 @@
 import android.content.res.Resources;
 import android.hardware.biometrics.AuthenticationStateListener;
 import android.hardware.biometrics.BiometricManager;
-import android.hardware.biometrics.Flags;
 import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
 import android.hardware.biometrics.IBiometricService;
 import android.hardware.biometrics.IBiometricServiceReceiver;
@@ -504,23 +503,9 @@
                 eq(callback));
     }
 
-    @Test(expected = UnsupportedOperationException.class)
-    public void testGetLastAuthenticationTime_flaggedOff_throwsUnsupportedOperationException()
-            throws Exception {
-        mSetFlagsRule.disableFlags(Flags.FLAG_LAST_AUTHENTICATION_TIME);
-        setInternalAndTestBiometricPermissions(mContext, true /* hasPermission */);
-
-        mAuthService = new AuthService(mContext, mInjector);
-        mAuthService.onStart();
-
-        mAuthService.mImpl.getLastAuthenticationTime(0,
-                BiometricManager.Authenticators.BIOMETRIC_STRONG);
-    }
-
     @Test
-    public void testGetLastAuthenticationTime_flaggedOn_callsBiometricService()
+    public void testGetLastAuthenticationTime_callsBiometricService()
             throws Exception {
-        mSetFlagsRule.enableFlags(Flags.FLAG_LAST_AUTHENTICATION_TIME);
         setInternalAndTestBiometricPermissions(mContext, true /* hasPermission */);
 
         mAuthService = new AuthService(mContext, mInjector);
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index acca4cc..9918a9a 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -2014,20 +2014,9 @@
         verifyNoMoreInteractions(callback);
     }
 
-    @Test(expected = UnsupportedOperationException.class)
-    public void testGetLastAuthenticationTime_flagOff_throwsUnsupportedOperationException()
-            throws RemoteException {
-        mSetFlagsRule.disableFlags(Flags.FLAG_LAST_AUTHENTICATION_TIME);
-
-        mBiometricService = new BiometricService(mContext, mInjector, mBiometricHandlerProvider);
-        mBiometricService.mImpl.getLastAuthenticationTime(0, Authenticators.BIOMETRIC_STRONG);
-    }
-
     @Test
-    public void testGetLastAuthenticationTime_flagOn_callsKeystoreAuthorization()
+    public void testGetLastAuthenticationTime_callsKeystoreAuthorization()
             throws RemoteException {
-        mSetFlagsRule.enableFlags(Flags.FLAG_LAST_AUTHENTICATION_TIME);
-
         final int[] hardwareAuthenticators = new int[] {
                 HardwareAuthenticatorType.PASSWORD,
                 HardwareAuthenticatorType.FINGERPRINT
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 0cd809c..c1c8211 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -12007,7 +12007,8 @@
     @Test
     @DisableFlags(android.app.Flags.FLAG_REMOVE_REMOTE_VIEWS)
     public void testRemoveLargeRemoteViews() throws Exception {
-        int removeSize = mContext.getResources().getInteger(
+        // Cast to long to mock RemoteViews.estimateMemoryUsage which returns long.
+        long removeSize = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_notificationStripRemoteViewSizeBytes);
 
         RemoteViews rv = mock(RemoteViews.class);
diff --git a/tests/testables/src/android/testing/TestableLooper.java b/tests/testables/src/android/testing/TestableLooper.java
index 7d07d42..3ee6dc4 100644
--- a/tests/testables/src/android/testing/TestableLooper.java
+++ b/tests/testables/src/android/testing/TestableLooper.java
@@ -16,13 +16,11 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.Instrumentation;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Message;
 import android.os.MessageQueue;
-import android.os.SystemClock;
 import android.os.TestLooperManager;
 import android.util.ArrayMap;
 
@@ -34,7 +32,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
-import java.util.LinkedList;
+import java.lang.reflect.Field;
 import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -58,6 +56,9 @@
      * catch crashes.
      */
     public static final boolean HOLD_MAIN_THREAD = false;
+    private static final Field MESSAGE_QUEUE_MESSAGES_FIELD;
+    private static final Field MESSAGE_NEXT_FIELD;
+    private static final Field MESSAGE_WHEN_FIELD;
 
     private Looper mLooper;
     private MessageQueue mQueue;
@@ -66,6 +67,19 @@
     private Handler mHandler;
     private TestLooperManager mQueueWrapper;
 
+    static {
+        try {
+            MESSAGE_QUEUE_MESSAGES_FIELD = MessageQueue.class.getDeclaredField("mMessages");
+            MESSAGE_QUEUE_MESSAGES_FIELD.setAccessible(true);
+            MESSAGE_NEXT_FIELD = Message.class.getDeclaredField("next");
+            MESSAGE_NEXT_FIELD.setAccessible(true);
+            MESSAGE_WHEN_FIELD = Message.class.getDeclaredField("when");
+            MESSAGE_WHEN_FIELD.setAccessible(true);
+        } catch (NoSuchFieldException e) {
+            throw new RuntimeException("Failed to initialize TestableLooper", e);
+        }
+    }
+
     public TestableLooper(Looper l) throws Exception {
         this(acquireLooperManager(l), l);
     }
@@ -208,17 +222,29 @@
     }
 
     public void moveTimeForward(long milliSeconds) {
-        long futureWhen = SystemClock.uptimeMillis() + milliSeconds;
-        // Find messages in the queue enqueued within the future time, and execute them now.
-        while (true) {
-            Long peekWhen = mQueueWrapper.peekWhen();
-            if (peekWhen == null || peekWhen > futureWhen) {
-                break;
+        try {
+            Message msg = getMessageLinkedList();
+            while (msg != null) {
+                long updatedWhen = msg.getWhen() - milliSeconds;
+                if (updatedWhen < 0) {
+                    updatedWhen = 0;
+                }
+                MESSAGE_WHEN_FIELD.set(msg, updatedWhen);
+                msg = (Message) MESSAGE_NEXT_FIELD.get(msg);
             }
-            Message message = mQueueWrapper.poll();
-            if (message != null) {
-                mQueueWrapper.execute(message);
-            }
+        } catch (IllegalAccessException e) {
+            throw new RuntimeException("Access failed in TestableLooper: set - Message.when", e);
+        }
+    }
+
+    private Message getMessageLinkedList() {
+        try {
+            MessageQueue queue = mLooper.getQueue();
+            return (Message) MESSAGE_QUEUE_MESSAGES_FIELD.get(queue);
+        } catch (IllegalAccessException e) {
+            throw new RuntimeException(
+                    "Access failed in TestableLooper: get - MessageQueue.mMessages",
+                    e);
         }
     }