Merge "Create WindowWakeUpPolicy" into main
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java
index e5a06c9..3c361d7 100644
--- a/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java
@@ -16,12 +16,14 @@
 
 package android.graphics.perftests;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
 import android.graphics.Color;
+import android.graphics.ColorSpace;
 import android.graphics.ImageDecoder;
 import android.graphics.Paint;
 import android.graphics.RecordingCanvas;
@@ -104,15 +106,36 @@
     }
 
     @Test
-    public void testCreateScaledBitmap() throws IOException {
+    public void testCreateScaledSrgbBitmap() throws IOException {
         BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         final Context context = InstrumentationRegistry.getContext();
         Bitmap source = ImageDecoder.decodeBitmap(
                 ImageDecoder.createSource(context.getResources(), R.drawable.fountain_night),
                 (decoder, info, source1) -> {
                     decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+                    decoder.setTargetColorSpace(ColorSpace.get(ColorSpace.Named.SRGB));
                 });
         source.setGainmap(null);
+        assertEquals(source.getColorSpace().getId(), ColorSpace.Named.SRGB.ordinal());
+
+        while (state.keepRunning()) {
+            Bitmap.createScaledBitmap(source, source.getWidth() / 2, source.getHeight() / 2, true)
+                    .recycle();
+        }
+    }
+
+    @Test
+    public void testCreateScaledP3Bitmap() throws IOException {
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        final Context context = InstrumentationRegistry.getContext();
+        Bitmap source = ImageDecoder.decodeBitmap(
+                ImageDecoder.createSource(context.getResources(), R.drawable.fountain_night),
+                (decoder, info, source1) -> {
+                    decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+                    decoder.setTargetColorSpace(ColorSpace.get(ColorSpace.Named.DISPLAY_P3));
+                });
+        source.setGainmap(null);
+        assertEquals(source.getColorSpace().getId(), ColorSpace.Named.DISPLAY_P3.ordinal());
 
         while (state.keepRunning()) {
             Bitmap.createScaledBitmap(source, source.getWidth() / 2, source.getHeight() / 2, true)
diff --git a/core/api/current.txt b/core/api/current.txt
index ec8f070..df073dd 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -12932,6 +12932,7 @@
     field public static final String FEATURE_MIDI = "android.software.midi";
     field public static final String FEATURE_NFC = "android.hardware.nfc";
     field public static final String FEATURE_NFC_BEAM = "android.sofware.nfc.beam";
+    field @FlaggedApi("android.nfc.enable_nfc_charging") public static final String FEATURE_NFC_CHARGING = "android.hardware.nfc.charging";
     field public static final String FEATURE_NFC_HOST_CARD_EMULATION = "android.hardware.nfc.hce";
     field public static final String FEATURE_NFC_HOST_CARD_EMULATION_NFCF = "android.hardware.nfc.hcef";
     field public static final String FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE = "android.hardware.nfc.ese";
@@ -28813,6 +28814,7 @@
     method public void enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle);
     method public static android.nfc.NfcAdapter getDefaultAdapter(android.content.Context);
     method @Nullable public android.nfc.NfcAntennaInfo getNfcAntennaInfo();
+    method @FlaggedApi("android.nfc.enable_nfc_charging") @Nullable public android.nfc.WlcLDeviceInfo getWlcLDeviceInfo();
     method public boolean ignore(android.nfc.Tag, int, android.nfc.NfcAdapter.OnTagRemovedListener, android.os.Handler);
     method public boolean isEnabled();
     method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean isObserveModeSupported();
@@ -28820,6 +28822,7 @@
     method @FlaggedApi("android.nfc.enable_nfc_reader_option") public boolean isReaderOptionSupported();
     method public boolean isSecureNfcEnabled();
     method public boolean isSecureNfcSupported();
+    method @FlaggedApi("android.nfc.enable_nfc_charging") public boolean isWlcEnabled();
     field public static final String ACTION_ADAPTER_STATE_CHANGED = "android.nfc.action.ADAPTER_STATE_CHANGED";
     field public static final String ACTION_NDEF_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED";
     field @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public static final String ACTION_PREFERRED_PAYMENT_CHANGED = "android.nfc.action.PREFERRED_PAYMENT_CHANGED";
@@ -28905,6 +28908,20 @@
     ctor public TagLostException(String);
   }
 
+  @FlaggedApi("android.nfc.enable_nfc_charging") public final class WlcLDeviceInfo implements android.os.Parcelable {
+    ctor public WlcLDeviceInfo(double, double, double, int);
+    method public int describeContents();
+    method public double getBatteryLevel();
+    method public double getProductId();
+    method public int getState();
+    method public double getTemperature();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field public static final int CONNECTED_CHARGING = 2; // 0x2
+    field public static final int CONNECTED_DISCHARGING = 3; // 0x3
+    field @NonNull public static final android.os.Parcelable.Creator<android.nfc.WlcLDeviceInfo> CREATOR;
+    field public static final int DISCONNECTED = 1; // 0x1
+  }
+
 }
 
 package android.nfc.cardemulation {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index b15bc0e..0d4169f 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -9884,17 +9884,20 @@
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enable();
     method @FlaggedApi("android.nfc.enable_nfc_reader_option") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableReaderOption(boolean);
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableSecureNfc(boolean);
+    method @FlaggedApi("android.nfc.enable_nfc_charging") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableWlc(boolean);
     method @FlaggedApi("android.nfc.enable_nfc_mainline") public int getAdapterState();
     method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public java.util.Map<java.lang.String,java.lang.Boolean> getTagIntentAppPreferenceForUser(int);
     method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOn();
     method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOnSupported();
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isTagIntentAppPreferenceSupported();
     method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void registerControllerAlwaysOnListener(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener);
+    method @FlaggedApi("android.nfc.enable_nfc_charging") public void registerWlcStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.WlcStateListener);
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean removeNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler);
     method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean setControllerAlwaysOn(boolean);
     method @FlaggedApi("android.nfc.enable_nfc_mainline") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setReaderMode(boolean);
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int setTagIntentAppPreferenceForUser(int, @NonNull String, boolean);
     method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void unregisterControllerAlwaysOnListener(@NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener);
+    method @FlaggedApi("android.nfc.enable_nfc_charging") public void unregisterWlcStateListener(@NonNull android.nfc.NfcAdapter.WlcStateListener);
     field @FlaggedApi("android.nfc.enable_nfc_mainline") public static final String ACTION_REQUIRE_UNLOCK_FOR_NFC = "android.nfc.action.REQUIRE_UNLOCK_FOR_NFC";
     field public static final int TAG_INTENT_APP_PREF_RESULT_PACKAGE_NOT_FOUND = -1; // 0xffffffff
     field public static final int TAG_INTENT_APP_PREF_RESULT_SUCCESS = 0; // 0x0
@@ -9909,6 +9912,10 @@
     method public boolean onUnlockAttempted(android.nfc.Tag);
   }
 
+  @FlaggedApi("android.nfc.enable_nfc_charging") public static interface NfcAdapter.WlcStateListener {
+    method public void onWlcStateChanged(@NonNull android.nfc.WlcLDeviceInfo);
+  }
+
 }
 
 package android.nfc.cardemulation {
diff --git a/core/java/android/app/servertransaction/ClientTransactionListenerController.java b/core/java/android/app/servertransaction/ClientTransactionListenerController.java
index 7418c06..9f97f6f 100644
--- a/core/java/android/app/servertransaction/ClientTransactionListenerController.java
+++ b/core/java/android/app/servertransaction/ClientTransactionListenerController.java
@@ -16,7 +16,7 @@
 
 package android.app.servertransaction;
 
-import static com.android.window.flags.Flags.syncWindowConfigUpdateFlag;
+import static com.android.window.flags.Flags.bundleClientTransactionFlag;
 
 import static java.util.Objects.requireNonNull;
 
@@ -67,7 +67,7 @@
      * window configuration.
      */
     public void onDisplayChanged(int displayId) {
-        if (!isSyncWindowConfigUpdateFlagEnabled()) {
+        if (!isBundleClientTransactionFlagEnabled()) {
             return;
         }
         if (ActivityThread.isSystem()) {
@@ -77,9 +77,9 @@
         mDisplayManager.handleDisplayChangeFromWindowManager(displayId);
     }
 
-    /** Whether {@link #syncWindowConfigUpdateFlag} feature flag is enabled. */
-    public boolean isSyncWindowConfigUpdateFlagEnabled() {
+    /** Whether {@link #bundleClientTransactionFlag} feature flag is enabled. */
+    public boolean isBundleClientTransactionFlagEnabled() {
         // Can't read flag from isolated process.
-        return !Process.isIsolated() && syncWindowConfigUpdateFlag();
+        return !Process.isIsolated() && bundleClientTransactionFlag();
     }
 }
diff --git a/core/java/android/app/servertransaction/TransactionExecutor.java b/core/java/android/app/servertransaction/TransactionExecutor.java
index 9f5e0dc..ee48e43 100644
--- a/core/java/android/app/servertransaction/TransactionExecutor.java
+++ b/core/java/android/app/servertransaction/TransactionExecutor.java
@@ -32,7 +32,7 @@
 import static android.app.servertransaction.TransactionExecutorHelper.tId;
 import static android.app.servertransaction.TransactionExecutorHelper.transactionToString;
 
-import static com.android.window.flags.Flags.syncWindowConfigUpdateFlag;
+import static com.android.window.flags.Flags.bundleClientTransactionFlag;
 
 import android.annotation.NonNull;
 import android.app.ActivityThread.ActivityClientRecord;
@@ -183,9 +183,9 @@
         }
 
         // Can't read flag from isolated process.
-        final boolean isSyncWindowConfigUpdateFlagEnabled = !Process.isIsolated()
-                && syncWindowConfigUpdateFlag();
-        final Context configUpdatedContext = isSyncWindowConfigUpdateFlagEnabled
+        final boolean isBundleClientTransactionFlagEnabled = !Process.isIsolated()
+                && bundleClientTransactionFlag();
+        final Context configUpdatedContext = isBundleClientTransactionFlagEnabled
                 ? item.getContextToUpdate(mTransactionHandler)
                 : null;
         final Configuration preExecutedConfig = configUpdatedContext != null
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index b75c64d..fa76e39 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3547,6 +3547,8 @@
      *
      * @param receiver The BroadcastReceiver to unregister.
      *
+     * @throws IllegalArgumentException if the {@code receiver} was not previously registered or
+     *                                  already unregistered.
      * @see #registerReceiver
      */
     public abstract void unregisterReceiver(BroadcastReceiver receiver);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 69273df..8151a91 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -16,6 +16,8 @@
 
 package android.content.pm;
 
+import static com.android.internal.pm.pkg.parsing.ParsingPackageUtils.PARSE_COLLECT_CERTIFICATES;
+
 import android.Manifest;
 import android.annotation.CallbackExecutor;
 import android.annotation.CheckResult;
@@ -55,7 +57,6 @@
 import android.content.IntentSender;
 import android.content.pm.PackageInstaller.SessionParams;
 import android.content.pm.dex.ArtManager;
-import android.content.pm.pkg.FrameworkPackageUserState;
 import android.content.pm.verify.domain.DomainVerificationManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -91,6 +92,10 @@
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.pm.parsing.PackageInfoCommonUtils;
+import com.android.internal.pm.parsing.PackageParser2;
+import com.android.internal.pm.parsing.PackageParserException;
+import com.android.internal.pm.parsing.pkg.ParsedPackage;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DataClass;
 
@@ -817,6 +822,8 @@
             GET_DISABLED_UNTIL_USED_COMPONENTS,
             GET_UNINSTALLED_PACKAGES,
             MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
+            MATCH_DIRECT_BOOT_AWARE,
+            MATCH_DIRECT_BOOT_UNAWARE,
             GET_ATTRIBUTIONS_LONG,
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -3306,6 +3313,14 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device supports NFC charging.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    @FlaggedApi(android.nfc.Flags.FLAG_ENABLE_NFC_CHARGING)
+    public static final String FEATURE_NFC_CHARGING = "android.hardware.nfc.charging";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The Beam API is enabled on the device.
      */
     @SdkConstant(SdkConstantType.FEATURE)
@@ -3315,7 +3330,7 @@
      * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device supports any
      * one of the {@link #FEATURE_NFC}, {@link #FEATURE_NFC_HOST_CARD_EMULATION},
-     * or {@link #FEATURE_NFC_HOST_CARD_EMULATION_NFCF} features.
+     * {@link #FEATURE_NFC_HOST_CARD_EMULATION_NFCF}, or {@link #FEATURE_NFC_CHARGING} features.
      *
      * @hide
      */
@@ -8620,28 +8635,56 @@
     @Nullable
     public PackageInfo getPackageArchiveInfo(@NonNull String archiveFilePath,
             @NonNull PackageInfoFlags flags) {
-        long flagsBits = flags.getValue();
-        final PackageParser parser = new PackageParser();
-        parser.setCallback(new PackageParser.CallbackImpl(this));
         final File apkFile = new File(archiveFilePath);
-        try {
-            if ((flagsBits & (MATCH_DIRECT_BOOT_UNAWARE | MATCH_DIRECT_BOOT_AWARE)) != 0) {
-                // Caller expressed an explicit opinion about what encryption
-                // aware/unaware components they want to see, so fall through and
-                // give them what they want
-            } else {
-                // Caller expressed no opinion, so match everything
-                flagsBits |= MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
-            }
 
-            PackageParser.Package pkg = parser.parsePackage(apkFile, 0, false);
-            if ((flagsBits & GET_SIGNATURES) != 0 || (flagsBits & GET_SIGNING_CERTIFICATES) != 0) {
-                PackageParser.collectCertificates(pkg, false /* skipVerify */);
-            }
-            return PackageParser.generatePackageInfo(pkg, null, (int) flagsBits, 0, 0, null,
-                    FrameworkPackageUserState.DEFAULT);
-        } catch (PackageParser.PackageParserException e) {
-            Log.w(TAG, "Failure to parse package archive", e);
+        @PackageInfoFlagsBits long flagsBits = flags.getValue();
+        if ((flagsBits & (MATCH_DIRECT_BOOT_UNAWARE | MATCH_DIRECT_BOOT_AWARE)) != 0) {
+            // Caller expressed an explicit opinion about what encryption
+            // aware/unaware components they want to see, so fall through and
+            // give them what they want
+        } else {
+            // Caller expressed no opinion, so match everything
+            flagsBits |= MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
+        }
+
+        int parserFlags = 0;
+        if ((flagsBits & (GET_SIGNATURES | GET_SIGNING_CERTIFICATES)) != 0) {
+            parserFlags |= PARSE_COLLECT_CERTIFICATES;
+        }
+
+        final PackageParser2 parser2 = new PackageParser2(/*separateProcesses*/ null,
+                /*displayMetrics*/ null,/*cacher*/ null,
+                new PackageParser2.Callback() {
+                    @Override
+                    public boolean hasFeature(String feature) {
+                        return PackageManager.this.hasSystemFeature(feature);
+                    }
+
+                    @NonNull
+                    @Override
+                    public Set<String> getHiddenApiWhitelistedApps() {
+                        return Collections.emptySet();
+                    }
+
+                    @NonNull
+                    @Override
+                    public Set<String> getInstallConstraintsAllowlist() {
+                        return Collections.emptySet();
+                    }
+
+                    @Override
+                    public boolean isChangeEnabled(long changeId,
+                            @androidx.annotation.NonNull ApplicationInfo appInfo) {
+                        return false;
+                    }
+                });
+
+        try {
+            ParsedPackage pp = parser2.parsePackage(apkFile, parserFlags, false);
+
+            return PackageInfoCommonUtils.generate(pp, flagsBits, UserHandle.myUserId());
+        } catch (PackageParserException e) {
+            Log.w(TAG, "Failure to parse package archive apkFile= " +apkFile);
             return null;
         }
     }
diff --git a/core/java/android/net/LocalSocket.java b/core/java/android/net/LocalSocket.java
index b69410c..a86396c 100644
--- a/core/java/android/net/LocalSocket.java
+++ b/core/java/android/net/LocalSocket.java
@@ -196,7 +196,8 @@
     }
 
     /**
-     * Retrieves the input stream for this instance.
+     * Retrieves the input stream for this instance. Closing this stream is equivalent to closing
+     * the entire socket and its associated streams using {@link #close()}.
      *
      * @return input stream
      * @throws IOException if socket has been closed or cannot be created.
@@ -207,7 +208,8 @@
     }
 
     /**
-     * Retrieves the output stream for this instance.
+     * Retrieves the output stream for this instance. Closing this stream is equivalent to closing
+     * the entire socket and its associated streams using {@link #close()}.
      *
      * @return output stream
      * @throws IOException if socket has been closed or cannot be created.
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index f6beec1..967a0cc 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -30,8 +30,10 @@
 import android.nfc.INfcUnlockHandler;
 import android.nfc.ITagRemovedCallback;
 import android.nfc.INfcDta;
+import android.nfc.INfcWlcStateListener;
 import android.nfc.NfcAntennaInfo;
 import android.os.Bundle;
+import android.nfc.WlcLDeviceInfo;
 
 /**
  * @hide
@@ -86,4 +88,11 @@
     boolean enableReaderOption(boolean enable);
     boolean isObserveModeSupported();
     boolean setObserveMode(boolean enabled);
+
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)")
+    boolean enableWlc(boolean enable);
+    boolean isWlcEnabled();
+    void registerWlcStateListener(in INfcWlcStateListener listener);
+    void unregisterWlcStateListener(in INfcWlcStateListener listener);
+    WlcLDeviceInfo getWlcLDeviceInfo();
 }
diff --git a/core/java/android/nfc/INfcWlcStateListener.aidl b/core/java/android/nfc/INfcWlcStateListener.aidl
new file mode 100644
index 0000000..c2b7075
--- /dev/null
+++ b/core/java/android/nfc/INfcWlcStateListener.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nfc;
+
+import android.nfc.WlcLDeviceInfo;
+/**
+ * @hide
+ */
+oneway interface INfcWlcStateListener {
+  /**
+   * Called whenever NFC WLC state changes
+   *
+   * @param wlcLDeviceInfo NFC wlc listener information
+   */
+  void onWlcStateChanged(in WlcLDeviceInfo wlcLDeviceInfo);
+}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index f407fb7..21e23ae 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -75,6 +75,7 @@
     static final String TAG = "NFC";
 
     private final NfcControllerAlwaysOnListener mControllerAlwaysOnListener;
+    private final NfcWlcStateListener mNfcWlcStateListener;
 
     /**
      * Intent to start an activity when a tag with NDEF payload is discovered.
@@ -440,6 +441,7 @@
     static boolean sIsInitialized = false;
     static boolean sHasNfcFeature;
     static boolean sHasCeFeature;
+    static boolean sHasNfcWlcFeature;
 
     // Final after first constructor, except for
     // attemptDeadServiceRecovery() when NFC crashes - we accept a best effort
@@ -650,8 +652,9 @@
                     || pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF)
                     || pm.hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC)
                     || pm.hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE);
+            sHasNfcWlcFeature = pm.hasSystemFeature(PackageManager.FEATURE_NFC_CHARGING);
             /* is this device meant to have NFC */
-            if (!sHasNfcFeature && !sHasCeFeature) {
+            if (!sHasNfcFeature && !sHasCeFeature && !sHasNfcWlcFeature) {
                 Log.v(TAG, "this device does not have NFC support");
                 throw new UnsupportedOperationException();
             }
@@ -776,6 +779,7 @@
         mTagRemovedListener = null;
         mLock = new Object();
         mControllerAlwaysOnListener = new NfcControllerAlwaysOnListener(getService());
+        mNfcWlcStateListener = new NfcWlcStateListener(getService());
     }
 
     /**
@@ -944,7 +948,8 @@
                 Log.e(TAG, "Failed to recover NFC Service.");
             }
         }
-        return serviceState && (isTagReadingEnabled() || isCardEmulationEnabled());
+        return serviceState
+                && (isTagReadingEnabled() || isCardEmulationEnabled() || sHasNfcWlcFeature);
     }
 
     /**
@@ -2587,4 +2592,159 @@
             return false;
         }
     }
+
+    /**
+     * Sets NFC charging feature.
+     * <p>This API is for the Settings application.
+     * @return True if successful
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_CHARGING)
+    @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+    public boolean enableWlc(boolean enable) {
+        if (!sHasNfcWlcFeature) {
+            throw new UnsupportedOperationException();
+        }
+        try {
+            return sService.enableWlc(enable);
+        } catch (RemoteException e) {
+            attemptDeadServiceRecovery(e);
+            // Try one more time
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover NFC Service.");
+                return false;
+            }
+            try {
+                return sService.enableWlc(enable);
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to recover NFC Service.");
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Checks NFC charging feature is enabled.
+     *
+     * @return True if NFC charging is enabled, false otherwise
+     * @throws UnsupportedOperationException if FEATURE_NFC_CHARGING
+     * is unavailable
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_CHARGING)
+    public boolean isWlcEnabled() {
+        if (!sHasNfcWlcFeature) {
+            throw new UnsupportedOperationException();
+        }
+        try {
+            return sService.isWlcEnabled();
+        } catch (RemoteException e) {
+            attemptDeadServiceRecovery(e);
+            // Try one more time
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover NFC Service.");
+                return false;
+            }
+            try {
+                return sService.isWlcEnabled();
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to recover NFC Service.");
+            }
+            return false;
+        }
+    }
+
+    /**
+     * A listener to be invoked when NFC controller always on state changes.
+     * <p>Register your {@code ControllerAlwaysOnListener} implementation with {@link
+     * NfcAdapter#registerWlcStateListener} and disable it with {@link
+     * NfcAdapter#unregisterWlcStateListenerListener}.
+     * @see #registerWlcStateListener
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_CHARGING)
+    public interface WlcStateListener {
+        /**
+         * Called on NFC WLC state changes
+         */
+        void onWlcStateChanged(@NonNull WlcLDeviceInfo wlcLDeviceInfo);
+    }
+
+    /**
+     * Register a {@link WlcStateListener} to listen for NFC WLC state changes
+     * <p>The provided listener will be invoked by the given {@link Executor}.
+     *
+     * @param executor an {@link Executor} to execute given listener
+     * @param listener user implementation of the {@link WlcStateListener}
+     * @throws UnsupportedOperationException if FEATURE_NFC_CHARGING
+     * is unavailable
+     *
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_CHARGING)
+    public void registerWlcStateListener(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull WlcStateListener listener) {
+        if (!sHasNfcWlcFeature) {
+            throw new UnsupportedOperationException();
+        }
+        mNfcWlcStateListener.register(executor, listener);
+    }
+
+    /**
+     * Unregister the specified {@link WlcStateListener}
+     * <p>The same {@link WlcStateListener} object used when calling
+     * {@link #registerWlcStateListener(Executor, WlcStateListener)}
+     * must be used.
+     *
+     * <p>Listeners are automatically unregistered when application process goes away
+     *
+     * @param listener user implementation of the {@link WlcStateListener}a
+     * @throws UnsupportedOperationException if FEATURE_NFC_CHARGING
+     * is unavailable
+     *
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_CHARGING)
+    public void unregisterWlcStateListener(
+            @NonNull WlcStateListener listener) {
+        if (!sHasNfcWlcFeature) {
+            throw new UnsupportedOperationException();
+        }
+        mNfcWlcStateListener.unregister(listener);
+    }
+
+    /**
+     * Returns information on the NFC charging listener device
+     *
+     * @return Information on the NFC charging listener device
+     * @throws UnsupportedOperationException if FEATURE_NFC_CHARGING
+     * is unavailable
+     */
+    @FlaggedApi(Flags.FLAG_ENABLE_NFC_CHARGING)
+    @Nullable
+    public WlcLDeviceInfo getWlcLDeviceInfo() {
+        if (!sHasNfcWlcFeature) {
+            throw new UnsupportedOperationException();
+        }
+        try {
+            return sService.getWlcLDeviceInfo();
+        } catch (RemoteException e) {
+            attemptDeadServiceRecovery(e);
+            // Try one more time
+            if (sService == null) {
+                Log.e(TAG, "Failed to recover NFC Service.");
+                return null;
+            }
+            try {
+                return sService.getWlcLDeviceInfo();
+            } catch (RemoteException ee) {
+                Log.e(TAG, "Failed to recover NFC Service.");
+            }
+            return null;
+        }
+    }
 }
diff --git a/core/java/android/nfc/NfcWlcStateListener.java b/core/java/android/nfc/NfcWlcStateListener.java
new file mode 100644
index 0000000..8d79310
--- /dev/null
+++ b/core/java/android/nfc/NfcWlcStateListener.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nfc;
+
+import android.annotation.NonNull;
+import android.nfc.NfcAdapter.WlcStateListener;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Executor;
+
+/**
+ * @hide
+ */
+public class NfcWlcStateListener extends INfcWlcStateListener.Stub {
+    private static final String TAG = NfcWlcStateListener.class.getSimpleName();
+
+    private final INfcAdapter mAdapter;
+
+    private final Map<WlcStateListener, Executor> mListenerMap = new HashMap<>();
+
+    private WlcLDeviceInfo mCurrentState = null;
+    private boolean mIsRegistered = false;
+
+    public NfcWlcStateListener(@NonNull INfcAdapter adapter) {
+        mAdapter = adapter;
+    }
+
+    /**
+     * Register a {@link WlcStateListener} with this
+     * {@link WlcStateListener}
+     *
+     * @param executor an {@link Executor} to execute given listener
+     * @param listener user implementation of the {@link WlcStateListener}
+     */
+    public void register(@NonNull Executor executor, @NonNull WlcStateListener listener) {
+        synchronized (this) {
+            if (mListenerMap.containsKey(listener)) {
+                return;
+            }
+
+            mListenerMap.put(listener, executor);
+
+            if (!mIsRegistered) {
+                try {
+                    mAdapter.registerWlcStateListener(this);
+                    mIsRegistered = true;
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Failed to register");
+                }
+            }
+        }
+    }
+
+    /**
+     * Unregister the specified {@link WlcStateListener}
+     *
+     * @param listener user implementation of the {@link WlcStateListener}
+     */
+    public void unregister(@NonNull WlcStateListener listener) {
+        synchronized (this) {
+            if (!mListenerMap.containsKey(listener)) {
+                return;
+            }
+
+            mListenerMap.remove(listener);
+
+            if (mListenerMap.isEmpty() && mIsRegistered) {
+                try {
+                    mAdapter.unregisterWlcStateListener(this);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Failed to unregister");
+                }
+                mIsRegistered = false;
+            }
+        }
+    }
+
+    private void sendCurrentState(@NonNull WlcStateListener listener) {
+        synchronized (this) {
+            Executor executor = mListenerMap.get(listener);
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                executor.execute(() -> listener.onWlcStateChanged(
+                        mCurrentState));
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+    }
+
+    @Override
+    public void onWlcStateChanged(@NonNull WlcLDeviceInfo wlcLDeviceInfo) {
+        synchronized (this) {
+            mCurrentState = wlcLDeviceInfo;
+
+            for (WlcStateListener cb : mListenerMap.keySet()) {
+                sendCurrentState(cb);
+            }
+        }
+    }
+}
+
diff --git a/core/java/android/nfc/WlcLDeviceInfo.aidl b/core/java/android/nfc/WlcLDeviceInfo.aidl
new file mode 100644
index 0000000..33143fe
--- /dev/null
+++ b/core/java/android/nfc/WlcLDeviceInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nfc;
+
+parcelable WlcLDeviceInfo;
diff --git a/core/java/android/nfc/WlcLDeviceInfo.java b/core/java/android/nfc/WlcLDeviceInfo.java
new file mode 100644
index 0000000..016431e
--- /dev/null
+++ b/core/java/android/nfc/WlcLDeviceInfo.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nfc;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Contains information of the nfc wireless charging listener device information.
+ */
+@FlaggedApi(Flags.FLAG_ENABLE_NFC_CHARGING)
+public final class WlcLDeviceInfo implements Parcelable {
+    public static final int DISCONNECTED = 1;
+
+    public static final int CONNECTED_CHARGING = 2;
+
+    public static final int CONNECTED_DISCHARGING = 3;
+
+    private double mProductId;
+    private double mTemperature;
+    private double mBatteryLevel;
+    private int mState;
+
+    public WlcLDeviceInfo(double productId, double temperature, double batteryLevel, int state) {
+        this.mProductId = productId;
+        this.mTemperature = temperature;
+        this.mBatteryLevel = batteryLevel;
+        this.mState = state;
+    }
+
+    /**
+     * ProductId of the WLC listener device.
+     */
+    public double getProductId() {
+        return mProductId;
+    }
+
+    /**
+     * Temperature of the WLC listener device.
+     */
+    public double getTemperature() {
+        return mTemperature;
+    }
+
+    /**
+     * BatteryLevel of the WLC listener device.
+     */
+    public double getBatteryLevel() {
+        return mBatteryLevel;
+    }
+
+    /**
+     * State of the WLC listener device.
+     */
+    public int getState() {
+        return mState;
+    }
+
+    private WlcLDeviceInfo(Parcel in) {
+        this.mProductId = in.readDouble();
+        this.mTemperature = in.readDouble();
+        this.mBatteryLevel = in.readDouble();
+        this.mState = in.readInt();
+    }
+
+    public static final @NonNull Parcelable.Creator<WlcLDeviceInfo> CREATOR =
+            new Parcelable.Creator<WlcLDeviceInfo>() {
+                @Override
+                public WlcLDeviceInfo createFromParcel(Parcel in) {
+                    return new WlcLDeviceInfo(in);
+                }
+
+                @Override
+                public WlcLDeviceInfo[] newArray(int size) {
+                    return new WlcLDeviceInfo[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeDouble(mProductId);
+        dest.writeDouble(mTemperature);
+        dest.writeDouble(mBatteryLevel);
+        dest.writeDouble(mState);
+    }
+}
diff --git a/core/java/android/nfc/flags.aconfig b/core/java/android/nfc/flags.aconfig
index 0d073cc..ce4f777 100644
--- a/core/java/android/nfc/flags.aconfig
+++ b/core/java/android/nfc/flags.aconfig
@@ -55,3 +55,10 @@
     description: "Enable sending broadcasts to Wallet role holder when a tag enters/leaves the field."
     bug: "306203494"
 }
+
+flag {
+    name: "enable_nfc_charging"
+    namespace: "nfc"
+    description: "Flag for NFC charging changes"
+    bug: "292143899"
+}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1f81a64..fcdad66 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -11910,6 +11910,12 @@
 
                 if (syncBuffer) {
                     boolean result = mBlastBufferQueue.syncNextTransaction(transaction -> {
+                        Runnable timeoutRunnable = () -> Log.e(mTag,
+                                "Failed to submit the sync transaction after 4s. Likely to ANR "
+                                        + "soon");
+                        mHandler.postDelayed(timeoutRunnable, 4L * Build.HW_TIMEOUT_MULTIPLIER);
+                        transaction.addTransactionCommittedListener(mSimpleExecutor,
+                                () -> mHandler.removeCallbacks(timeoutRunnable));
                         surfaceSyncGroup.addTransaction(transaction);
                         surfaceSyncGroup.markSyncReady();
                     });
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index 933cc49..59d7b0e 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -2,13 +2,6 @@
 
 # Project link: https://gantry.corp.google.com/projects/android_platform_windowing_sdk/changes
 
-flag {
-    namespace: "windowing_sdk"
-    name: "sync_window_config_update_flag"
-    description: "Whether the feature to sync different window-related config updates is enabled"
-    bug: "260873529"
-}
-
 # Using a fixed read only flag because there are ClientTransaction scheduling before
 # WindowManagerService creation.
 flag {
@@ -35,13 +28,6 @@
 
 flag {
     namespace: "windowing_sdk"
-    name: "window_state_resize_item_flag"
-    description: "Whether to dispatch window resize through ClientTransaction is enabled"
-    bug: "301870955"
-}
-
-flag {
-    namespace: "windowing_sdk"
     name: "fullscreen_dim_flag"
     description: "Whether to allow showing fullscreen dim on ActivityEmbedding split"
     bug: "253533308"
diff --git a/core/java/com/android/internal/pm/parsing/PackageInfoCommonUtils.java b/core/java/com/android/internal/pm/parsing/PackageInfoCommonUtils.java
new file mode 100644
index 0000000..f05d9cb
--- /dev/null
+++ b/core/java/com/android/internal/pm/parsing/PackageInfoCommonUtils.java
@@ -0,0 +1,652 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.pm.parsing;
+
+import static com.android.internal.pm.pkg.SEInfoUtil.COMPLETE_STR;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.Attribution;
+import android.content.pm.ComponentInfo;
+import android.content.pm.ConfigurationInfo;
+import android.content.pm.FallbackCategoryProvider;
+import android.content.pm.FeatureGroupInfo;
+import android.content.pm.FeatureInfo;
+import android.content.pm.InstrumentationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageItemInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PathPermission;
+import android.content.pm.PermissionInfo;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ServiceInfo;
+import android.content.pm.Signature;
+import android.content.pm.SigningDetails;
+import android.content.pm.SigningInfo;
+import android.os.Debug;
+import android.os.PatternMatcher;
+import android.os.UserHandle;
+import android.util.DebugUtils;
+import android.util.Slog;
+
+import com.android.internal.pm.parsing.pkg.AndroidPackageHidden;
+import com.android.internal.pm.parsing.pkg.AndroidPackageLegacyUtils;
+import com.android.internal.pm.parsing.pkg.PackageImpl;
+import com.android.internal.pm.pkg.component.ComponentParseUtils;
+import com.android.internal.pm.pkg.component.ParsedActivity;
+import com.android.internal.pm.pkg.component.ParsedAttribution;
+import com.android.internal.pm.pkg.component.ParsedComponent;
+import com.android.internal.pm.pkg.component.ParsedInstrumentation;
+import com.android.internal.pm.pkg.component.ParsedMainComponent;
+import com.android.internal.pm.pkg.component.ParsedPermission;
+import com.android.internal.pm.pkg.component.ParsedProvider;
+import com.android.internal.pm.pkg.component.ParsedService;
+import com.android.internal.pm.pkg.component.ParsedUsesPermission;
+import com.android.internal.pm.pkg.parsing.ParsingPackageHidden;
+import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.internal.pm.pkg.parsing.ParsingUtils;
+import com.android.internal.util.ArrayUtils;
+import com.android.server.pm.pkg.AndroidPackage;
+
+import java.util.List;
+
+/**
+ * Method that use a {@link AndroidPackage} to generate a {@link PackageInfo} though
+ * the given {@link PackageManager.PackageInfoFlags}
+ * @hide
+ **/
+// TODO(b/317215254): refactor coped code from PackageInfoUtils
+public class PackageInfoCommonUtils {
+
+    private static final String TAG = ParsingUtils.TAG;
+    private static final boolean DEBUG = false;
+
+    /**
+     * Generates a {@link PackageInfo} from the given {@link AndroidPackage}
+     */
+    @Nullable
+    public static PackageInfo generate(@Nullable AndroidPackage pkg,
+            @PackageManager.PackageInfoFlagsBits long flags, int userId) {
+        if (pkg == null) {
+            return null;
+        }
+        ApplicationInfo applicationInfo = generateApplicationInfo(pkg, flags, userId);
+
+        PackageInfo info = new PackageInfo();
+        info.packageName = pkg.getPackageName();
+        info.splitNames = pkg.getSplitNames();
+        info.versionCode = ((ParsingPackageHidden) pkg).getVersionCode();
+        info.versionCodeMajor = ((ParsingPackageHidden) pkg).getVersionCodeMajor();
+        info.baseRevisionCode = pkg.getBaseRevisionCode();
+        info.splitRevisionCodes = pkg.getSplitRevisionCodes();
+        info.versionName = pkg.getVersionName();
+        info.sharedUserId = pkg.getSharedUserId();
+        info.sharedUserLabel = pkg.getSharedUserLabelResourceId();
+        info.applicationInfo = applicationInfo;
+        info.installLocation = pkg.getInstallLocation();
+        if ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
+                || (info.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
+            info.requiredForAllUsers = pkg.isRequiredForAllUsers();
+        }
+        info.restrictedAccountType = pkg.getRestrictedAccountType();
+        info.requiredAccountType = pkg.getRequiredAccountType();
+        info.overlayTarget = pkg.getOverlayTarget();
+        info.targetOverlayableName = pkg.getOverlayTargetOverlayableName();
+        info.overlayCategory = pkg.getOverlayCategory();
+        info.overlayPriority = pkg.getOverlayPriority();
+        info.mOverlayIsStatic = pkg.isOverlayIsStatic();
+        info.compileSdkVersion = pkg.getCompileSdkVersion();
+        info.compileSdkVersionCodename = pkg.getCompileSdkVersionCodeName();
+        info.isStub = pkg.isStub();
+        info.coreApp = pkg.isCoreApp();
+        info.isApex = pkg.isApex();
+
+        if ((flags & PackageManager.GET_CONFIGURATIONS) != 0) {
+            int size = pkg.getConfigPreferences().size();
+            if (size > 0) {
+                info.configPreferences = new ConfigurationInfo[size];
+                pkg.getConfigPreferences().toArray(info.configPreferences);
+            }
+            size = pkg.getRequestedFeatures().size();
+            if (size > 0) {
+                info.reqFeatures = new FeatureInfo[size];
+                pkg.getRequestedFeatures().toArray(info.reqFeatures);
+            }
+            size = pkg.getFeatureGroups().size();
+            if (size > 0) {
+                info.featureGroups = new FeatureGroupInfo[size];
+                pkg.getFeatureGroups().toArray(info.featureGroups);
+            }
+        }
+        if ((flags & PackageManager.GET_PERMISSIONS) != 0) {
+            int size = ArrayUtils.size(pkg.getPermissions());
+            if (size > 0) {
+                info.permissions = new PermissionInfo[size];
+                for (int i = 0; i < size; i++) {
+                    final var permission = pkg.getPermissions().get(i);
+                    final var permissionInfo = generatePermissionInfo(permission, flags);
+                    info.permissions[i] = permissionInfo;
+                }
+            }
+            final List<ParsedUsesPermission> usesPermissions = pkg.getUsesPermissions();
+            size = usesPermissions.size();
+            if (size > 0) {
+                info.requestedPermissions = new String[size];
+                info.requestedPermissionsFlags = new int[size];
+                for (int i = 0; i < size; i++) {
+                    final ParsedUsesPermission usesPermission = usesPermissions.get(i);
+                    info.requestedPermissions[i] = usesPermission.getName();
+                    // The notion of required permissions is deprecated but for compatibility.
+                    info.requestedPermissionsFlags[i] |=
+                            PackageInfo.REQUESTED_PERMISSION_REQUIRED;
+                    if ((usesPermission.getUsesPermissionFlags()
+                            & ParsedUsesPermission.FLAG_NEVER_FOR_LOCATION) != 0) {
+                        info.requestedPermissionsFlags[i] |=
+                                PackageInfo.REQUESTED_PERMISSION_NEVER_FOR_LOCATION;
+                    }
+                    if (pkg.getImplicitPermissions().contains(info.requestedPermissions[i])) {
+                        info.requestedPermissionsFlags[i] |=
+                                PackageInfo.REQUESTED_PERMISSION_IMPLICIT;
+                    }
+                }
+            }
+        }
+        if ((flags & PackageManager.GET_ATTRIBUTIONS_LONG) != 0) {
+            int size = ArrayUtils.size(pkg.getAttributions());
+            if (size > 0) {
+                info.attributions = new Attribution[size];
+                for (int i = 0; i < size; i++) {
+                    ParsedAttribution parsedAttribution = pkg.getAttributions().get(i);
+                    if (parsedAttribution != null) {
+                        info.attributions[i] = new Attribution(parsedAttribution.getTag(),
+                                parsedAttribution.getLabel());
+                    }
+                }
+            }
+            if (pkg.isAttributionsUserVisible()) {
+                info.applicationInfo.privateFlagsExt
+                        |= ApplicationInfo.PRIVATE_FLAG_EXT_ATTRIBUTIONS_ARE_USER_VISIBLE;
+            } else {
+                info.applicationInfo.privateFlagsExt
+                        &= ~ApplicationInfo.PRIVATE_FLAG_EXT_ATTRIBUTIONS_ARE_USER_VISIBLE;
+            }
+        } else {
+            info.applicationInfo.privateFlagsExt
+                    &= ~ApplicationInfo.PRIVATE_FLAG_EXT_ATTRIBUTIONS_ARE_USER_VISIBLE;
+        }
+
+        final SigningDetails signingDetails = pkg.getSigningDetails();
+        // deprecated method of getting signing certificates
+        if ((flags & PackageManager.GET_SIGNATURES) != 0) {
+            if (signingDetails.hasPastSigningCertificates()) {
+                // Package has included signing certificate rotation information.  Return the oldest
+                // cert so that programmatic checks keep working even if unaware of key rotation.
+                info.signatures = new Signature[1];
+                info.signatures[0] = signingDetails.getPastSigningCertificates()[0];
+            } else if (signingDetails.hasSignatures()) {
+                // otherwise keep old behavior
+                int numberOfSigs = signingDetails.getSignatures().length;
+                info.signatures = new Signature[numberOfSigs];
+                System.arraycopy(signingDetails.getSignatures(), 0, info.signatures, 0,
+                        numberOfSigs);
+            }
+        }
+
+        // replacement for GET_SIGNATURES
+        if ((flags & PackageManager.GET_SIGNING_CERTIFICATES) != 0) {
+            if (signingDetails != SigningDetails.UNKNOWN) {
+                // only return a valid SigningInfo if there is signing information to report
+                info.signingInfo = new SigningInfo(signingDetails);
+            } else {
+                info.signingInfo = null;
+            }
+        }
+
+        if ((flags & PackageManager.GET_ACTIVITIES) != 0) {
+            final int size = pkg.getActivities().size();
+            if (size > 0) {
+                int num = 0;
+                final ActivityInfo[] res = new ActivityInfo[size];
+                for (int i = 0; i < size; i++) {
+                    final ParsedActivity a = pkg.getActivities().get(i);
+                    if (isMatch(pkg, a.isDirectBootAware(), flags)) {
+                        if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(
+                                a.getName())) {
+                            continue;
+                        }
+                        res[num++] = generateActivityInfo(a, flags, applicationInfo);
+                    }
+                }
+                info.activities = ArrayUtils.trimToSize(res, num);
+            }
+        }
+        if ((flags & PackageManager.GET_RECEIVERS) != 0) {
+            final int size = pkg.getReceivers().size();
+            if (size > 0) {
+                int num = 0;
+                final ActivityInfo[] res = new ActivityInfo[size];
+                for (int i = 0; i < size; i++) {
+                    final ParsedActivity a = pkg.getReceivers().get(i);
+                    if (isMatch(pkg, a.isDirectBootAware(), flags)) {
+                        res[num++] = generateActivityInfo(a, flags, applicationInfo);
+                    }
+                }
+                info.receivers = ArrayUtils.trimToSize(res, num);
+            }
+        }
+        if ((flags & PackageManager.GET_SERVICES) != 0) {
+            final int size = pkg.getServices().size();
+            if (size > 0) {
+                int num = 0;
+                final ServiceInfo[] res = new ServiceInfo[size];
+                for (int i = 0; i < size; i++) {
+                    final ParsedService s = pkg.getServices().get(i);
+                    if (isMatch(pkg, s.isDirectBootAware(), flags)) {
+                        res[num++] = generateServiceInfo(s, flags, applicationInfo);
+                    }
+                }
+                info.services = ArrayUtils.trimToSize(res, num);
+            }
+        }
+        if ((flags & PackageManager.GET_PROVIDERS) != 0) {
+            final int size = pkg.getProviders().size();
+            if (size > 0) {
+                int num = 0;
+                final ProviderInfo[] res = new ProviderInfo[size];
+                for (int i = 0; i < size; i++) {
+                    final ParsedProvider pr = pkg.getProviders().get(i);
+                    if (isMatch(pkg, pr.isDirectBootAware(), flags)) {
+                        res[num++] = generateProviderInfo(pkg, pr, flags, applicationInfo, userId);
+                    }
+                }
+                info.providers = ArrayUtils.trimToSize(res, num);
+            }
+        }
+        if ((flags & PackageManager.GET_INSTRUMENTATION) != 0) {
+            final int size = pkg.getInstrumentations().size();
+            if (size > 0) {
+                info.instrumentation = new InstrumentationInfo[size];
+                for (int i = 0; i < size; i++) {
+                    info.instrumentation[i] = generateInstrumentationInfo(
+                            pkg.getInstrumentations().get(i), pkg, flags, userId);
+                }
+            }
+        }
+
+        return info;
+    }
+
+    private static void updateApplicationInfo(ApplicationInfo ai, long flags) {
+        if ((flags & PackageManager.GET_META_DATA) == 0) {
+            ai.metaData = null;
+        }
+        if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) == 0) {
+            ai.sharedLibraryFiles = null;
+            ai.sharedLibraryInfos = null;
+        }
+
+        // CompatibilityMode is global state.
+        if (!ParsingPackageUtils.sCompatibilityModeEnabled) {
+            ai.disableCompatibilityMode();
+        }
+
+        if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
+            ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName);
+        }
+        ai.seInfoUser = COMPLETE_STR;
+    }
+
+    @Nullable
+    private static ApplicationInfo generateApplicationInfo(@NonNull AndroidPackage pkg,
+            @PackageManager.ApplicationInfoFlagsBits long flags, @UserIdInt int userId) {
+
+        // Make shallow copy so we can store the metadata/libraries safely
+        ApplicationInfo info = ((AndroidPackageHidden) pkg).toAppInfoWithoutState();
+
+        updateApplicationInfo(info, flags);
+
+        initForUser(info, pkg, userId);
+
+        info.primaryCpuAbi = AndroidPackageLegacyUtils.getRawPrimaryCpuAbi(pkg);
+        info.secondaryCpuAbi = AndroidPackageLegacyUtils.getRawSecondaryCpuAbi(pkg);
+
+        if ((flags & PackageManager.GET_META_DATA) != 0) {
+            info.metaData = pkg.getMetaData();
+        }
+        if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0) {
+            List<String> usesLibraryFiles = pkg.getUsesLibraries();
+
+            info.sharedLibraryFiles = usesLibraryFiles.isEmpty()
+                    ? null : usesLibraryFiles.toArray(new String[0]);
+        }
+
+        return info;
+    }
+
+    @Nullable
+    private static ActivityInfo generateActivityInfo(ParsedActivity a,
+            @PackageManager.ComponentInfoFlagsBits long flags,
+            @NonNull ApplicationInfo applicationInfo) {
+        if (a == null) return null;
+
+        // Make shallow copies so we can store the metadata safely
+        ActivityInfo ai = new ActivityInfo();
+        ai.targetActivity = a.getTargetActivity();
+        ai.processName = a.getProcessName();
+        ai.exported = a.isExported();
+        ai.theme = a.getTheme();
+        ai.uiOptions = a.getUiOptions();
+        ai.parentActivityName = a.getParentActivityName();
+        ai.permission = a.getPermission();
+        ai.taskAffinity = a.getTaskAffinity();
+        ai.flags = a.getFlags();
+        ai.privateFlags = a.getPrivateFlags();
+        ai.launchMode = a.getLaunchMode();
+        ai.documentLaunchMode = a.getDocumentLaunchMode();
+        ai.maxRecents = a.getMaxRecents();
+        ai.configChanges = a.getConfigChanges();
+        ai.softInputMode = a.getSoftInputMode();
+        ai.persistableMode = a.getPersistableMode();
+        ai.lockTaskLaunchMode = a.getLockTaskLaunchMode();
+        ai.screenOrientation = a.getScreenOrientation();
+        ai.resizeMode = a.getResizeMode();
+        ai.setMaxAspectRatio(a.getMaxAspectRatio());
+        ai.setMinAspectRatio(a.getMinAspectRatio());
+        ai.supportsSizeChanges = a.isSupportsSizeChanges();
+        ai.requestedVrComponent = a.getRequestedVrComponent();
+        ai.rotationAnimation = a.getRotationAnimation();
+        ai.colorMode = a.getColorMode();
+        ai.windowLayout = a.getWindowLayout();
+        ai.attributionTags = a.getAttributionTags();
+        if ((flags & PackageManager.GET_META_DATA) != 0) {
+            var metaData = a.getMetaData();
+            // Backwards compatibility, coerce to null if empty
+            ai.metaData = metaData.isEmpty() ? null : metaData;
+        } else {
+            ai.metaData = null;
+        }
+        ai.applicationInfo = applicationInfo;
+        ai.requiredDisplayCategory = a.getRequiredDisplayCategory();
+        ai.setKnownActivityEmbeddingCerts(a.getKnownActivityEmbeddingCerts());
+        assignFieldsComponentInfoParsedMainComponent(ai, a);
+        return ai;
+    }
+
+    @Nullable
+    private static ServiceInfo generateServiceInfo(ParsedService s,
+            @PackageManager.ComponentInfoFlagsBits long flags,
+            @NonNull ApplicationInfo applicationInfo) {
+        if (s == null) return null;
+
+        // Make shallow copies so we can store the metadata safely
+        ServiceInfo si = new ServiceInfo();
+        si.exported = s.isExported();
+        si.flags = s.getFlags();
+        si.permission = s.getPermission();
+        si.processName = s.getProcessName();
+        si.mForegroundServiceType = s.getForegroundServiceType();
+        si.applicationInfo = applicationInfo;
+        if ((flags & PackageManager.GET_META_DATA) != 0) {
+            var metaData = s.getMetaData();
+            // Backwards compatibility, coerce to null if empty
+            si.metaData = metaData.isEmpty() ? null : metaData;
+        }
+        assignFieldsComponentInfoParsedMainComponent(si, s);
+        return si;
+    }
+
+    @Nullable
+    private static ProviderInfo generateProviderInfo(AndroidPackage pkg, ParsedProvider p,
+            @PackageManager.ComponentInfoFlagsBits long flags,
+            @NonNull ApplicationInfo applicationInfo, int userId) {
+        if (p == null) return null;
+
+        if (!pkg.getPackageName().equals(applicationInfo.packageName)) {
+            Slog.wtf(TAG, "AppInfo's package name is different. Expected=" + pkg.getPackageName()
+                    + " actual=" + applicationInfo.packageName);
+            applicationInfo = generateApplicationInfo(pkg, flags, userId);
+        }
+
+        // Make shallow copies so we can store the metadata safely
+        ProviderInfo pi = new ProviderInfo();
+        pi.exported = p.isExported();
+        pi.flags = p.getFlags();
+        pi.processName = p.getProcessName();
+        pi.authority = p.getAuthority();
+        pi.isSyncable = p.isSyncable();
+        pi.readPermission = p.getReadPermission();
+        pi.writePermission = p.getWritePermission();
+        pi.grantUriPermissions = p.isGrantUriPermissions();
+        pi.forceUriPermissions = p.isForceUriPermissions();
+        pi.multiprocess = p.isMultiProcess();
+        pi.initOrder = p.getInitOrder();
+        pi.uriPermissionPatterns = p.getUriPermissionPatterns().toArray(new PatternMatcher[0]);
+        pi.pathPermissions = p.getPathPermissions().toArray(new PathPermission[0]);
+        if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) {
+            pi.uriPermissionPatterns = null;
+        }
+        if ((flags & PackageManager.GET_META_DATA) != 0) {
+            var metaData = p.getMetaData();
+            // Backwards compatibility, coerce to null if empty
+            pi.metaData = metaData.isEmpty() ? null : metaData;
+        }
+        pi.applicationInfo = applicationInfo;
+        assignFieldsComponentInfoParsedMainComponent(pi, p);
+        return pi;
+    }
+
+    @Nullable
+    private static InstrumentationInfo generateInstrumentationInfo(ParsedInstrumentation i,
+            AndroidPackage pkg, @PackageManager.ComponentInfoFlagsBits long flags, int userId) {
+        if (i == null) return null;
+
+        InstrumentationInfo info = new InstrumentationInfo();
+        info.targetPackage = i.getTargetPackage();
+        info.targetProcesses = i.getTargetProcesses();
+        info.handleProfiling = i.isHandleProfiling();
+        info.functionalTest = i.isFunctionalTest();
+
+        info.sourceDir = pkg.getBaseApkPath();
+        info.publicSourceDir = pkg.getBaseApkPath();
+        info.splitNames = pkg.getSplitNames();
+        info.splitSourceDirs = pkg.getSplitCodePaths().length == 0 ? null : pkg.getSplitCodePaths();
+        info.splitPublicSourceDirs = pkg.getSplitCodePaths().length == 0
+                ? null : pkg.getSplitCodePaths();
+        info.splitDependencies = pkg.getSplitDependencies().size() == 0
+                ? null : pkg.getSplitDependencies();
+
+        initForUser(info, pkg, userId);
+
+        info.primaryCpuAbi = AndroidPackageLegacyUtils.getRawPrimaryCpuAbi(pkg);
+        info.secondaryCpuAbi = AndroidPackageLegacyUtils.getRawSecondaryCpuAbi(pkg);
+        info.nativeLibraryDir = pkg.getNativeLibraryDir();
+        info.secondaryNativeLibraryDir = pkg.getSecondaryNativeLibraryDir();
+
+        assignFieldsPackageItemInfoParsedComponent(info, i);
+
+        if ((flags & PackageManager.GET_META_DATA) == 0) {
+            info.metaData = null;
+        } else {
+            var metaData = i.getMetaData();
+            // Backwards compatibility, coerce to null if empty
+            info.metaData = metaData.isEmpty() ? null : metaData;
+        }
+
+        return info;
+    }
+
+    @Nullable
+    private static PermissionInfo generatePermissionInfo(ParsedPermission p,
+            @PackageManager.ComponentInfoFlagsBits long flags) {
+        // TODO(b/135203078): Remove null checks and make all usages @NonNull
+        if (p == null) return null;
+
+        PermissionInfo pi = new PermissionInfo(p.getBackgroundPermission());
+
+        assignFieldsPackageItemInfoParsedComponent(pi, p);
+
+        pi.group = p.getGroup();
+        pi.requestRes = p.getRequestRes();
+        pi.protectionLevel = p.getProtectionLevel();
+        pi.descriptionRes = p.getDescriptionRes();
+        pi.flags = p.getFlags();
+        pi.knownCerts = p.getKnownCerts();
+
+        if ((flags & PackageManager.GET_META_DATA) == 0) {
+            pi.metaData = null;
+        } else {
+            var metaData = p.getMetaData();
+            // Backwards compatibility, coerce to null if empty
+            pi.metaData = metaData.isEmpty() ? null : metaData;
+        }
+        return pi;
+    }
+
+    private static void assignFieldsComponentInfoParsedMainComponent(
+            @NonNull ComponentInfo info, @NonNull ParsedMainComponent component) {
+        assignFieldsPackageItemInfoParsedComponent(info, component);
+        info.descriptionRes = component.getDescriptionRes();
+        info.directBootAware = component.isDirectBootAware();
+        info.enabled = component.isEnabled();
+        info.splitName = component.getSplitName();
+        info.attributionTags = component.getAttributionTags();
+        info.nonLocalizedLabel = component.getNonLocalizedLabel();
+        info.icon = component.getIcon();
+    }
+
+    private static void assignFieldsPackageItemInfoParsedComponent(
+            @NonNull PackageItemInfo packageItemInfo, @NonNull ParsedComponent component) {
+        packageItemInfo.nonLocalizedLabel = ComponentParseUtils.getNonLocalizedLabel(component);
+        packageItemInfo.icon = ComponentParseUtils.getIcon(component);
+        packageItemInfo.banner = component.getBanner();
+        packageItemInfo.labelRes = component.getLabelRes();
+        packageItemInfo.logo = component.getLogo();
+        packageItemInfo.name = component.getName();
+        packageItemInfo.packageName = component.getPackageName();
+    }
+
+    private static void initForUser(ApplicationInfo output, AndroidPackage input,
+            @UserIdInt int userId) {
+        PackageImpl pkg = ((PackageImpl) input);
+        String packageName = input.getPackageName();
+        output.uid = UserHandle.getUid(userId, UserHandle.getAppId(input.getUid()));
+
+        // For performance reasons, all these paths are built as strings
+        final String credentialDir = pkg.getBaseAppDataCredentialProtectedDirForSystemUser();
+        final String deviceDir = pkg.getBaseAppDataDeviceProtectedDirForSystemUser();
+        if (credentialDir !=  null && deviceDir != null) {
+            if (userId == UserHandle.USER_SYSTEM) {
+                output.credentialProtectedDataDir = credentialDir + packageName;
+                output.deviceProtectedDataDir = deviceDir + packageName;
+            } else {
+                // Convert /data/user/0/ -> /data/user/1/com.example.app
+                String userIdString = String.valueOf(userId);
+                int credentialLength = credentialDir.length();
+                output.credentialProtectedDataDir = new StringBuilder(credentialDir)
+                        .replace(credentialLength - 2, credentialLength - 1, userIdString)
+                        .append(packageName)
+                        .toString();
+                int deviceLength = deviceDir.length();
+                output.deviceProtectedDataDir = new StringBuilder(deviceDir)
+                        .replace(deviceLength - 2, deviceLength - 1, userIdString)
+                        .append(packageName)
+                        .toString();
+            }
+        }
+
+        if (input.isDefaultToDeviceProtectedStorage()
+                && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) {
+            output.dataDir = output.deviceProtectedDataDir;
+        } else {
+            output.dataDir = output.credentialProtectedDataDir;
+        }
+    }
+
+    // This duplicates the ApplicationInfo variant because it uses field assignment and the classes
+    // don't inherit from each other, unfortunately. Consolidating logic would introduce overhead.
+    private static void initForUser(InstrumentationInfo output, AndroidPackage input,
+            @UserIdInt int userId) {
+        PackageImpl pkg = ((PackageImpl) input);
+        String packageName = input.getPackageName();
+
+        // For performance reasons, all these paths are built as strings
+        final String credentialDir = pkg.getBaseAppDataCredentialProtectedDirForSystemUser();
+        final String deviceDir = pkg.getBaseAppDataDeviceProtectedDirForSystemUser();
+        if (credentialDir !=  null && deviceDir != null) {
+            if (userId == UserHandle.USER_SYSTEM) {
+                output.credentialProtectedDataDir = credentialDir + packageName;
+                output.deviceProtectedDataDir = deviceDir + packageName;
+            } else {
+                // Convert /data/user/0/ -> /data/user/1/com.example.app
+                String userIdString = String.valueOf(userId);
+                int credentialLength = credentialDir.length();
+                output.credentialProtectedDataDir = new StringBuilder(credentialDir)
+                        .replace(credentialLength - 2, credentialLength - 1, userIdString)
+                        .append(packageName)
+                        .toString();
+                int deviceLength = deviceDir.length();
+                output.deviceProtectedDataDir = new StringBuilder(deviceDir)
+                        .replace(deviceLength - 2, deviceLength - 1, userIdString)
+                        .append(packageName)
+                        .toString();
+            }
+        }
+
+        if (input.isDefaultToDeviceProtectedStorage()
+                && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) {
+            output.dataDir = output.deviceProtectedDataDir;
+        } else {
+            output.dataDir = output.credentialProtectedDataDir;
+        }
+    }
+
+    /**
+     * Test if the given component is considered system, enabled and a match for the given
+     * flags.
+     *
+     * <p>
+     * Expects at least one of {@link PackageManager#MATCH_DIRECT_BOOT_AWARE} and {@link
+     * PackageManager#MATCH_DIRECT_BOOT_UNAWARE} are specified in {@code flags}.
+     * </p>
+     */
+    private static boolean isMatch(AndroidPackage pkg,
+            boolean isComponentDirectBootAware, long flags) {
+        final boolean isSystem = ((AndroidPackageHidden) pkg).isSystem();
+        if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
+            if (!isSystem) {
+                return reportIfDebug(false, flags);
+            }
+        }
+
+        final boolean matchesUnaware = ((flags & PackageManager.MATCH_DIRECT_BOOT_UNAWARE) != 0)
+                && !isComponentDirectBootAware;
+        final boolean matchesAware = ((flags & PackageManager.MATCH_DIRECT_BOOT_AWARE) != 0)
+                && isComponentDirectBootAware;
+        return reportIfDebug(matchesUnaware || matchesAware, flags);
+    }
+
+    private static boolean reportIfDebug(boolean result, long flags) {
+        if (DEBUG && !result) {
+            Slog.i(TAG, "No match!; flags: "
+                    + DebugUtils.flagsToString(PackageManager.class, "MATCH_", flags) + " "
+                    + Debug.getCaller());
+        }
+        return result;
+    }
+}
diff --git a/core/java/com/android/internal/pm/parsing/PackageParser2.java b/core/java/com/android/internal/pm/parsing/PackageParser2.java
index e413293..2c54672 100644
--- a/core/java/com/android/internal/pm/parsing/PackageParser2.java
+++ b/core/java/com/android/internal/pm/parsing/PackageParser2.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityThread;
+import android.app.Application;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.parsing.PackageLite;
 import android.content.pm.parsing.result.ParseInput;
@@ -40,6 +41,7 @@
 import com.android.internal.util.ArrayUtils;
 
 import java.io.File;
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -78,10 +80,19 @@
             displayMetrics.setToDefaults();
         }
 
-        PermissionManager permissionManager = ActivityThread.currentApplication()
-                .getSystemService(PermissionManager.class);
-        List<PermissionManager.SplitPermissionInfo> splitPermissions = permissionManager
-                .getSplitPermissions();
+        List<PermissionManager.SplitPermissionInfo> splitPermissions = null;
+
+        final Application application = ActivityThread.currentApplication();
+        if (application != null) {
+            final PermissionManager permissionManager =
+                    application.getSystemService(PermissionManager.class);
+            if (permissionManager != null) {
+                splitPermissions = permissionManager.getSplitPermissions();
+            }
+        }
+        if (splitPermissions == null) {
+            splitPermissions = new ArrayList<>();
+        }
 
         mCacher = cacher;
 
diff --git a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java
index 930b1a4..95d5049 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ClientTransactionListenerControllerTest.java
@@ -65,7 +65,7 @@
         mHandler = getInstrumentation().getContext().getMainThreadHandler();
         mController = spy(ClientTransactionListenerController.createInstanceForTesting(
                 mDisplayManager));
-        doReturn(true).when(mController).isSyncWindowConfigUpdateFlagEnabled();
+        doReturn(true).when(mController).isBundleClientTransactionFlagEnabled();
     }
 
     @Test
diff --git a/core/tests/coretests/src/android/window/flags/WindowFlagsTest.java b/core/tests/coretests/src/android/window/flags/WindowFlagsTest.java
index a5bbeb5..9292f66 100644
--- a/core/tests/coretests/src/android/window/flags/WindowFlagsTest.java
+++ b/core/tests/coretests/src/android/window/flags/WindowFlagsTest.java
@@ -16,7 +16,6 @@
 
 package android.window.flags;
 
-import static com.android.window.flags.Flags.syncWindowConfigUpdateFlag;
 import static com.android.window.flags.Flags.taskFragmentSystemOrganizerFlag;
 
 import android.platform.test.annotations.Presubmit;
@@ -39,12 +38,6 @@
 public class WindowFlagsTest {
 
     @Test
-    public void testSyncWindowConfigUpdateFlag() {
-        // No crash when accessing the flag.
-        syncWindowConfigUpdateFlag();
-    }
-
-    @Test
     public void testTaskFragmentSystemOrganizerFlag() {
         // No crash when accessing the flag.
         taskFragmentSystemOrganizerFlag();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index 662a5c4..a76bd26 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -95,7 +95,6 @@
     private int mMinimumFlyoutWidthLargeScreen;
 
     private PointF mRestingStackPosition;
-    private int[] mPaddings = new int[4];
 
     private boolean mShowingInBubbleBar;
     private final Point mBubbleBarPosition = new Point();
@@ -344,46 +343,44 @@
         final int pointerTotalHeight = getPointerSize();
         final int expandedViewLargeScreenInsetFurthestEdge =
                 getExpandedViewLargeScreenInsetFurthestEdge(isOverflow);
+        int[] paddings = new int[4];
         if (mDeviceConfig.isLargeScreen()) {
             // Note:
             // If we're in portrait OR if we're a small tablet, then the two insets values will
             // be equal. If we're landscape and a large tablet, the two values will be different.
             // [left, top, right, bottom]
-            mPaddings[0] = onLeft
+            paddings[0] = onLeft
                     ? mExpandedViewLargeScreenInsetClosestEdge - pointerTotalHeight
                     : expandedViewLargeScreenInsetFurthestEdge;
-            mPaddings[1] = 0;
-            mPaddings[2] = onLeft
+            paddings[1] = 0;
+            paddings[2] = onLeft
                     ? expandedViewLargeScreenInsetFurthestEdge
                     : mExpandedViewLargeScreenInsetClosestEdge - pointerTotalHeight;
             // Overflow doesn't show manage button / get padding from it so add padding here
-            mPaddings[3] = isOverflow ? mExpandedViewPadding : 0;
-            return mPaddings;
+            paddings[3] = isOverflow ? mExpandedViewPadding : 0;
+            return paddings;
         } else {
             int leftPadding = mInsets.left + mExpandedViewPadding;
             int rightPadding = mInsets.right + mExpandedViewPadding;
-            final float expandedViewWidth = isOverflow
-                    ? mOverflowWidth
-                    : mExpandedViewLargeScreenWidth;
             if (showBubblesVertically()) {
                 if (!onLeft) {
                     rightPadding += mBubbleSize - pointerTotalHeight;
                     leftPadding += isOverflow
-                            ? (mPositionRect.width() - rightPadding - expandedViewWidth)
+                            ? (mPositionRect.width() - rightPadding - mOverflowWidth)
                             : 0;
                 } else {
                     leftPadding += mBubbleSize - pointerTotalHeight;
                     rightPadding += isOverflow
-                            ? (mPositionRect.width() - leftPadding - expandedViewWidth)
+                            ? (mPositionRect.width() - leftPadding - mOverflowWidth)
                             : 0;
                 }
             }
             // [left, top, right, bottom]
-            mPaddings[0] = leftPadding;
-            mPaddings[1] = showBubblesVertically() ? 0 : mPointerMargin;
-            mPaddings[2] = rightPadding;
-            mPaddings[3] = 0;
-            return mPaddings;
+            paddings[0] = leftPadding;
+            paddings[1] = showBubblesVertically() ? 0 : mPointerMargin;
+            paddings[2] = rightPadding;
+            paddings[3] = 0;
+            return paddings;
         }
     }
 
@@ -395,7 +392,7 @@
     }
 
     /** Gets the y position of the expanded view if it was top-aligned. */
-    public float getExpandedViewYTopAligned() {
+    public int getExpandedViewYTopAligned() {
         final int top = getAvailableRect().top;
         if (showBubblesVertically()) {
             return top - mPointerWidth + mExpandedViewPadding;
@@ -413,7 +410,7 @@
             return getExpandedViewHeightForLargeScreen();
         }
         // Subtract top insets because availableRect.height would account for that
-        int expandedContainerY = (int) getExpandedViewYTopAligned() - getInsets().top;
+        int expandedContainerY = getExpandedViewYTopAligned() - getInsets().top;
         int paddingTop = showBubblesVertically()
                 ? 0
                 : mPointerHeight;
@@ -474,11 +471,11 @@
     public float getExpandedViewY(BubbleViewProvider bubble, float bubblePosition) {
         boolean isOverflow = bubble == null || BubbleOverflow.KEY.equals(bubble.getKey());
         float expandedViewHeight = getExpandedViewHeight(bubble);
-        float topAlignment = getExpandedViewYTopAligned();
+        int topAlignment = getExpandedViewYTopAligned();
         int manageButtonHeight =
                 isOverflow ? mExpandedViewPadding : mManageButtonHeightIncludingMargins;
 
-        // On largescreen portrait bubbles are bottom aligned.
+        // On large screen portrait bubbles are bottom aligned.
         if (areBubblesBottomAligned() && expandedViewHeight == MAX_HEIGHT) {
             return mPositionRect.bottom - manageButtonHeight
                     - getExpandedViewHeightForLargeScreen() - mPointerWidth;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
index 02af2d0..7798aa7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
@@ -420,7 +420,7 @@
             bubbleView.setTranslationY(y);
         }
 
-        final float expandedY = mPositioner.getExpandedViewYTopAligned();
+        final int expandedY = mPositioner.getExpandedViewYTopAligned();
         final boolean draggedOutEnough =
                 y > expandedY + mBubbleSizePx || y < expandedY - mBubbleSizePx;
         if (draggedOutEnough != mBubbleDraggedOutEnough) {
diff --git a/media/TEST_MAPPING b/media/TEST_MAPPING
index f8176a1..8f5f1f6 100644
--- a/media/TEST_MAPPING
+++ b/media/TEST_MAPPING
@@ -50,7 +50,7 @@
       ]
     }
   ],
-  "presubmit": [
+  "postsubmit": [
     {
       "file_patterns": [
         "[^/]*(LoudnessCodec)[^/]*\\.java"
diff --git a/packages/CredentialManager/res/drawable/autofill_light_selectable_item_background.xml b/packages/CredentialManager/res/drawable/autofill_light_selectable_item_background.xml
new file mode 100644
index 0000000..9d16f32d
--- /dev/null
+++ b/packages/CredentialManager/res/drawable/autofill_light_selectable_item_background.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!-- Copied from //frameworks/base/core/res/res/drawable/item_background_material.xml -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+        android:color="@color/autofill_light_colorControlHighlight">
+    <item android:id="@android:id/mask">
+        <color android:color="@android:color/white"/>
+    </item>
+</ripple>
\ No newline at end of file
diff --git a/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one.xml b/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one.xml
new file mode 100644
index 0000000..2f0c83b
--- /dev/null
+++ b/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:tools="http://schemas.android.com/tools" tools:ignore="NewApi"
+        android:color="@android:color/transparent">
+    <item
+        android:bottom="1dp"
+        android:shape="rectangle"
+        android:top="1dp">
+        <shape>
+            <corners android:radius="28dp" />
+            <solid android:color="@android:color/system_surface_container_high_light" />
+        </shape>
+    </item>
+</ripple>
\ No newline at end of file
diff --git a/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one_dark.xml b/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one_dark.xml
new file mode 100644
index 0000000..39f49ca
--- /dev/null
+++ b/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one_dark.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:tools="http://schemas.android.com/tools" tools:ignore="NewApi"
+        android:color="@android:color/transparent">
+    <item
+        android:bottom="1dp"
+        android:shape="rectangle"
+        android:top="1dp">
+        <shape>
+            <corners android:radius="28dp" />
+            <solid android:color="@android:color/system_surface_container_high_dark" />
+        </shape>
+    </item>
+</ripple>
\ No newline at end of file
diff --git a/packages/CredentialManager/res/layout/autofill_dataset_left_with_item_tag_hint.xml b/packages/CredentialManager/res/layout/autofill_dataset_left_with_item_tag_hint.xml
new file mode 100644
index 0000000..e4e9f7a
--- /dev/null
+++ b/packages/CredentialManager/res/layout/autofill_dataset_left_with_item_tag_hint.xml
@@ -0,0 +1,37 @@
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:id="@android:id/content"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                style="@style/autofill.Dataset">
+    <ImageView
+        android:id="@android:id/icon1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerVertical="true"
+        android:layout_alignParentStart="true"
+        android:background="@null"/>
+    <TextView
+        android:id="@android:id/text1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        android:layout_toEndOf="@android:id/icon1"
+        style="@style/autofill.TextAppearance"/>
+
+</RelativeLayout>
diff --git a/packages/CredentialManager/res/values/colors.xml b/packages/CredentialManager/res/values/colors.xml
new file mode 100644
index 0000000..63b9f24
--- /dev/null
+++ b/packages/CredentialManager/res/values/colors.xml
@@ -0,0 +1,38 @@
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!-- Color palette -->
+<resources>
+    <color name="autofill_light_colorPrimary">@color/primary_material_light</color>
+    <color name="autofill_light_colorAccent">@color/accent_material_light</color>
+    <color name="autofill_light_colorControlHighlight">@color/ripple_material_light</color>
+    <color name="autofill_light_colorButtonNormal">@color/button_material_light</color>
+
+    <!-- Text colors -->
+    <color name="autofill_light_textColorPrimary">@color/abc_primary_text_material_light</color>
+    <color name="autofill_light_textColorSecondary">@color/abc_secondary_text_material_light</color>
+    <color name="autofill_light_textColorHint">@color/abc_hint_foreground_material_light</color>
+    <color name="autofill_light_textColorHintInverse">@color/abc_hint_foreground_material_dark
+    </color>
+    <color name="autofill_light_textColorHighlight">@color/highlighted_text_material_light</color>
+    <color name="autofill_light_textColorLink">@color/autofill_light_colorAccent</color>
+
+    <!-- These colors are used for Remote Views. -->
+    <color name="background_dark_mode">#0E0C0B</color>
+    <color name="background">#F1F3F4</color>
+    <color name="text_primary_dark_mode">#DFDEDB</color>
+    <color name="text_primary">#202124</color>
+</resources>
\ No newline at end of file
diff --git a/packages/CredentialManager/res/values/dimens.xml b/packages/CredentialManager/res/values/dimens.xml
new file mode 100644
index 0000000..67003a3
--- /dev/null
+++ b/packages/CredentialManager/res/values/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+    <dimen name="autofill_view_padding">16dp</dimen>
+    <dimen name="autofill_icon_size">16dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/packages/CredentialManager/res/values/styles.xml b/packages/CredentialManager/res/values/styles.xml
new file mode 100644
index 0000000..4a5761a
--- /dev/null
+++ b/packages/CredentialManager/res/values/styles.xml
@@ -0,0 +1,38 @@
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+    <style name="autofill.TextAppearance.Small" parent="@style/autofill.TextAppearance">
+        <item name="android:textSize">12sp</item>
+    </style>
+
+
+    <style name="autofill.Dataset" parent="">
+        <item name="android:background">@drawable/autofill_light_selectable_item_background</item>
+    </style>
+
+    <style name="autofill.TextAppearance" parent="">
+        <item name="android:textColor">@color/autofill_light_textColorPrimary</item>
+        <item name="android:textColorHint">@color/autofill_light_textColorHint</item>
+        <item name="android:textColorHighlight">@color/autofill_light_textColorHighlight</item>
+        <item name="android:textColorLink">@color/autofill_light_textColorLink</item>
+        <item name="android:textSize">14sp</item>
+    </style>
+
+    <style name="autofill.TextAppearance.Primary">
+        <item name="android:textColor">@color/autofill_light_textColorPrimary</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
index 20d2f09..0ff1c7f 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
@@ -16,6 +16,7 @@
 
 package com.android.credentialmanager.autofill
 
+import android.R
 import android.app.assist.AssistStructure
 import android.content.Context
 import android.credentials.CredentialManager
@@ -41,18 +42,19 @@
 import android.service.credentials.CredentialProviderService
 import android.util.Log
 import android.view.autofill.AutofillId
-import org.json.JSONException
 import android.widget.inline.InlinePresentationSpec
 import androidx.autofill.inline.v1.InlineSuggestionUi
 import androidx.credentials.provider.CustomCredentialEntry
 import androidx.credentials.provider.PasswordCredentialEntry
 import androidx.credentials.provider.PublicKeyCredentialEntry
 import com.android.credentialmanager.GetFlowUtils
-import com.android.credentialmanager.model.get.CredentialEntryInfo
+import com.android.credentialmanager.common.ui.RemoteViewsFactory
 import com.android.credentialmanager.getflow.ProviderDisplayInfo
-import com.android.credentialmanager.model.get.ProviderInfo
 import com.android.credentialmanager.getflow.toProviderDisplayInfo
 import com.android.credentialmanager.ktx.credentialEntry
+import com.android.credentialmanager.model.get.CredentialEntryInfo
+import com.android.credentialmanager.model.get.ProviderInfo
+import org.json.JSONException
 import org.json.JSONObject
 import java.util.concurrent.Executors
 
@@ -127,9 +129,11 @@
                     is PasswordCredentialEntry -> {
                         entryIconMap[entry.key + entry.subkey] = credentialEntry.icon
                     }
+
                     is PublicKeyCredentialEntry -> {
                         entryIconMap[entry.key + entry.subkey] = credentialEntry.icon
                     }
+
                     is CustomCredentialEntry -> {
                         entryIconMap[entry.key + entry.subkey] = credentialEntry.icon
                     }
@@ -172,11 +176,11 @@
     }
 
     private fun processProvidersForAutofillId(
-        filLRequest: FillRequest,
-        autofillId: AutofillId,
-        providerList: List<ProviderInfo>,
-        entryIconMap: Map<String, Icon>,
-        fillResponseBuilder: FillResponse.Builder
+            filLRequest: FillRequest,
+            autofillId: AutofillId,
+            providerList: List<ProviderInfo>,
+            entryIconMap: Map<String, Icon>,
+            fillResponseBuilder: FillResponse.Builder
     ): Boolean {
         if (providerList.isEmpty()) {
             return false
@@ -197,7 +201,7 @@
         var i = 0
         var datasetAdded = false
 
-        providerDisplayInfo.sortedUserNameToCredentialEntryList.forEach usernameLoop@ {
+        providerDisplayInfo.sortedUserNameToCredentialEntryList.forEach usernameLoop@{
             val primaryEntry = it.sortedCredentialEntryList.first()
             val pendingIntent = primaryEntry.pendingIntent
             val fillInIntent = primaryEntry.fillInIntent
@@ -206,37 +210,48 @@
                 Log.e(TAG, "PendingIntent was missing from the entry.")
                 return@usernameLoop
             }
-            if (inlinePresentationSpecs == null || i >= maxItemCount) {
+            if (inlinePresentationSpecs == null) {
+                Log.i(TAG, "Inline presentation spec is null, " +
+                        "building dropdown presentation only")
+            }
+            if (i >= maxItemCount) {
                 Log.e(TAG, "Skipping because reached the max item count.")
                 return@usernameLoop
             }
-            // Create inline presentation
-            val spec: InlinePresentationSpec
-            if (i < inlinePresentationSpecsCount) {
-                spec = inlinePresentationSpecs[i]
-            } else {
-                spec = inlinePresentationSpecs[inlinePresentationSpecsCount - 1]
-            }
-            val sliceBuilder = InlineSuggestionUi
-                    .newContentBuilder(pendingIntent)
-                    .setTitle(primaryEntry.userName)
-            val icon: Icon
-            if (primaryEntry.icon == null) {
+            val icon: Icon = if (primaryEntry.icon == null) {
                 // The empty entry icon has non-null icon reference but null drawable reference.
                 // If the drawable reference is null, then use the default icon.
-                icon = getDefaultIcon()
+                getDefaultIcon()
             } else {
-                icon = entryIconMap[primaryEntry.entryKey + primaryEntry.entrySubkey]
+                entryIconMap[primaryEntry.entryKey + primaryEntry.entrySubkey]
                         ?: getDefaultIcon()
             }
-            sliceBuilder.setStartIcon(icon)
-            val inlinePresentation = InlinePresentation(
-                    sliceBuilder.build().slice, spec, /* pinned= */ false)
+            // Create inline presentation
+            var inlinePresentation: InlinePresentation? = null;
+            if (inlinePresentationSpecs != null) {
+                val spec: InlinePresentationSpec
+                if (i < inlinePresentationSpecsCount) {
+                    spec = inlinePresentationSpecs[i]
+                } else {
+                    spec = inlinePresentationSpecs[inlinePresentationSpecsCount - 1]
+                }
+                val sliceBuilder = InlineSuggestionUi
+                        .newContentBuilder(pendingIntent)
+                        .setTitle(primaryEntry.userName)
+                sliceBuilder.setStartIcon(icon)
+                inlinePresentation = InlinePresentation(
+                        sliceBuilder.build().slice, spec, /* pinned= */ false)
+            }
+            val dropdownPresentation = RemoteViewsFactory.createDropdownPresentation(
+                    this, icon, primaryEntry)
             i++
 
             val dataSetBuilder = Dataset.Builder()
             val presentationBuilder = Presentations.Builder()
-                    .setInlinePresentation(inlinePresentation)
+                    .setMenuPresentation(dropdownPresentation)
+            if (inlinePresentation != null) {
+                presentationBuilder.setInlinePresentation(inlinePresentation)
+            }
 
             fillResponseBuilder.addDataset(
                     dataSetBuilder
@@ -305,7 +320,7 @@
     ): MutableMap<AutofillId, MutableList<CredentialEntryInfo>> {
         val autofillIdToCredentialEntries:
                 MutableMap<AutofillId, MutableList<CredentialEntryInfo>> = mutableMapOf()
-        credentialEntryList.forEach entryLoop@ { credentialEntry ->
+        credentialEntryList.forEach entryLoop@{ credentialEntry ->
             val autofillId: AutofillId? = credentialEntry
                     .fillInIntent
                     ?.getParcelableExtra(
@@ -323,8 +338,8 @@
     }
 
     private fun copyProviderInfo(
-        providerInfo: ProviderInfo,
-        credentialList: List<CredentialEntryInfo>
+            providerInfo: ProviderInfo,
+            credentialList: List<CredentialEntryInfo>
     ): ProviderInfo {
         return ProviderInfo(
                 providerInfo.id,
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt
new file mode 100644
index 0000000..4dc7f00
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.credentialmanager.common.ui
+
+import android.content.Context
+import android.content.res.Configuration
+import android.widget.RemoteViews
+import androidx.core.content.ContextCompat
+import com.android.credentialmanager.model.get.CredentialEntryInfo
+import android.graphics.drawable.Icon
+
+class RemoteViewsFactory {
+
+    companion object {
+        private const val setAdjustViewBoundsMethodName = "setAdjustViewBounds"
+        private const val setMaxHeightMethodName = "setMaxHeight"
+        private const val setBackgroundResourceMethodName = "setBackgroundResource"
+
+        fun createDropdownPresentation(
+                context: Context,
+                icon: Icon,
+                credentialEntryInfo: CredentialEntryInfo
+        ): RemoteViews {
+            val padding = context.resources.getDimensionPixelSize(com.android
+                    .credentialmanager.R.dimen.autofill_view_padding)
+            var layoutId: Int = com.android.credentialmanager.R.layout
+                    .autofill_dataset_left_with_item_tag_hint
+            val remoteViews = RemoteViews(context.packageName, layoutId)
+            setRemoteViewsPaddings(remoteViews, padding)
+            val textColorPrimary = getTextColorPrimary(isDarkMode(context), context);
+            remoteViews.setTextColor(android.R.id.text1, textColorPrimary);
+            remoteViews.setTextViewText(android.R.id.text1, credentialEntryInfo.userName)
+
+            remoteViews.setImageViewIcon(android.R.id.icon1, icon);
+            remoteViews.setBoolean(
+                    android.R.id.icon1, setAdjustViewBoundsMethodName, true);
+            remoteViews.setInt(
+                    android.R.id.icon1,
+                     setMaxHeightMethodName,
+                    context.resources.getDimensionPixelSize(
+                            com.android.credentialmanager.R.dimen.autofill_icon_size));
+            val drawableId = if (isDarkMode(context))
+                com.android.credentialmanager.R.drawable.fill_dialog_dynamic_list_item_one_dark
+            else com.android.credentialmanager.R.drawable.fill_dialog_dynamic_list_item_one
+            remoteViews.setInt(
+                    android.R.id.content, setBackgroundResourceMethodName, drawableId);
+            return remoteViews
+        }
+
+        private fun setRemoteViewsPaddings(
+                remoteViews: RemoteViews,
+                padding: Int) {
+            val halfPadding = padding / 2
+            remoteViews.setViewPadding(
+                    android.R.id.text1,
+                    halfPadding,
+                    halfPadding,
+                    halfPadding,
+                    halfPadding)
+        }
+
+        private fun isDarkMode(context: Context): Boolean {
+            val currentNightMode = context.resources.configuration.uiMode and
+                    Configuration.UI_MODE_NIGHT_MASK
+            return currentNightMode == Configuration.UI_MODE_NIGHT_YES
+        }
+
+        private fun getTextColorPrimary(darkMode: Boolean, context: Context): Int {
+            return if (darkMode) ContextCompat.getColor(
+                    context, com.android.credentialmanager.R.color.text_primary_dark_mode)
+            else ContextCompat.getColor(context, com.android.credentialmanager.R.color.text_primary)
+        }
+    }
+}
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
index 557fbf2..e6122a0 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
@@ -43,7 +43,7 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content" />
         <FrameLayout
-            android:id="@+id/status_view_media_container"
+            android:id="@id/status_view_media_container"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:padding="@dimen/qs_media_padding"
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index d511cab..80725c2 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -225,6 +225,8 @@
     <item type="id" name="communal_tutorial_indicator" />
     <item type="id" name="nssl_placeholder_barrier_bottom" />
     <item type="id" name="ambient_indication_container" />
+    <item type="id" name="status_view_media_container" />
+    <item type="id" name="smart_space_barrier_bottom" />
 
     <!-- Privacy dialog -->
     <item type="id" name="privacy_dialog_close_app_button" />
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 83d415f..ab23564 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -403,13 +403,6 @@
 
             final BiometricPromptLayout view = (BiometricPromptLayout) layoutInflater.inflate(
                     R.layout.biometric_prompt_layout, null, false);
-            /**
-             * View is only set visible in BiometricViewSizeBinder once PromptSize is determined
-             * that accounts for iconView size, to prevent prompt resizing being visible to the
-             * user.
-             * TODO(b/288175072): May be able to remove this once constraint layout is implemented
-             */
-            view.setVisibility(View.INVISIBLE);
             mBiometricView = BiometricViewBinder.bind(view, viewModel, mPanelController,
                     // TODO(b/201510778): This uses the wrong timeout in some cases
                     getJankListener(view, TRANSIT,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
index a7fb6f7..90e4a38 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
@@ -97,13 +97,7 @@
 
         val iconOverlayView = view.requireViewById<LottieAnimationView>(R.id.biometric_icon_overlay)
         val iconView = view.requireViewById<LottieAnimationView>(R.id.biometric_icon)
-        /**
-         * View is only set visible in BiometricViewSizeBinder once PromptSize is determined that
-         * accounts for iconView size, to prevent prompt resizing being visible to the user.
-         *
-         * TODO(b/288175072): May be able to remove this once constraint layout is implemented
-         */
-        iconView.addLottieOnCompositionLoadedListener { viewModel.setIsIconViewLoaded(true) }
+
         PromptIconViewBinder.bind(
             iconView,
             iconOverlayView,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
index f340bd8..7e16d1e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
@@ -30,6 +30,7 @@
 import androidx.core.view.doOnLayout
 import androidx.core.view.isGone
 import androidx.lifecycle.lifecycleScope
+import com.android.systemui.res.R
 import com.android.systemui.biometrics.AuthPanelController
 import com.android.systemui.biometrics.Utils
 import com.android.systemui.biometrics.ui.BiometricPromptLayout
@@ -40,8 +41,6 @@
 import com.android.systemui.biometrics.ui.viewmodel.isNullOrNotSmall
 import com.android.systemui.biometrics.ui.viewmodel.isSmall
 import com.android.systemui.lifecycle.repeatWhenAttached
-import com.android.systemui.res.R
-import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.launch
 
 /** Helper for [BiometricViewBinder] to handle resize transitions. */
@@ -93,22 +92,8 @@
             // TODO(b/251476085): migrate the legacy panel controller and simplify this
             view.repeatWhenAttached {
                 var currentSize: PromptSize? = null
-
                 lifecycleScope.launch {
-                    /**
-                     * View is only set visible in BiometricViewSizeBinder once PromptSize is
-                     * determined that accounts for iconView size, to prevent prompt resizing being
-                     * visible to the user.
-                     *
-                     * TODO(b/288175072): May be able to remove isIconViewLoaded once constraint
-                     *   layout is implemented
-                     */
-                    combine(viewModel.isIconViewLoaded, viewModel.size, ::Pair).collect {
-                        (isIconViewLoaded, size) ->
-                        if (!isIconViewLoaded) {
-                            return@collect
-                        }
-
+                    viewModel.size.collect { size ->
                         // prepare for animated size transitions
                         for (v in viewsToHideWhenSmall) {
                             v.showTextOrHide(forceHide = size.isSmall)
@@ -211,9 +196,8 @@
                                     }
                                 }
                             }
+
                             currentSize = size
-                            view.visibility = View.VISIBLE
-                            viewModel.setIsIconViewLoaded(false)
                             notifyAccessibilityChanged()
                         }
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
index d899827e..6d0a58e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
@@ -192,28 +192,6 @@
     val iconViewModel: PromptIconViewModel =
         PromptIconViewModel(this, displayStateInteractor, promptSelectorInteractor)
 
-    private val _isIconViewLoaded = MutableStateFlow(false)
-
-    /**
-     * For prompts with an iconView, false until the prompt's iconView animation has been loaded in
-     * the view, otherwise true by default. Used for BiometricViewSizeBinder to wait for the icon
-     * asset to be loaded before determining the prompt size.
-     */
-    val isIconViewLoaded: Flow<Boolean> =
-        combine(credentialKind, _isIconViewLoaded.asStateFlow()) { credentialKind, isIconViewLoaded
-            ->
-            if (credentialKind is PromptKind.Biometric) {
-                isIconViewLoaded
-            } else {
-                true
-            }
-        }
-
-    // Sets whether the prompt's iconView animation has been loaded in the view yet.
-    fun setIsIconViewLoaded(iconViewLoaded: Boolean) {
-        _isIconViewLoaded.value = iconViewLoaded
-    }
-
     /** Padding for prompt UI elements */
     val promptPadding: Flow<Rect> =
         combine(size, displayStateInteractor.currentRotation) { size, rotation ->
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index 1f69cc0..0d40511 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -397,8 +397,10 @@
             IntentFilter filter = new IntentFilter();
             filter.addAction(Intent.ACTION_DATE_CHANGED);
             filter.addAction(Intent.ACTION_LOCALE_CHANGED);
-            getContext().registerReceiver(mIntentReceiver, filter, null /* permission*/,
-                    null /* scheduler */);
+            mBgHandler.post(() -> {
+                getContext().registerReceiver(mIntentReceiver, filter, null /* permission*/,
+                        null /* scheduler */);
+            });
             mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
             mRegistered = true;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/SplitShadeKeyguardBlueprint.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/SplitShadeKeyguardBlueprint.kt
index 16539db..5344696b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/SplitShadeKeyguardBlueprint.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/SplitShadeKeyguardBlueprint.kt
@@ -33,6 +33,7 @@
 import com.android.systemui.keyguard.ui.view.layout.sections.SmartspaceSection
 import com.android.systemui.keyguard.ui.view.layout.sections.SplitShadeClockSection
 import com.android.systemui.keyguard.ui.view.layout.sections.SplitShadeGuidelines
+import com.android.systemui.keyguard.ui.view.layout.sections.SplitShadeMediaSection
 import com.android.systemui.keyguard.ui.view.layout.sections.SplitShadeNotificationStackScrollLayoutSection
 import com.android.systemui.util.kotlin.getOrNull
 import java.util.Optional
@@ -63,6 +64,7 @@
     communalTutorialIndicatorSection: CommunalTutorialIndicatorSection,
     smartspaceSection: SmartspaceSection,
     clockSection: SplitShadeClockSection,
+    mediaSection: SplitShadeMediaSection,
 ) : KeyguardBlueprint {
     override val id: String = ID
 
@@ -81,6 +83,7 @@
             aodBurnInSection,
             communalTutorialIndicatorSection,
             clockSection,
+            mediaSection,
             defaultDeviceEntrySection, // Add LAST: Intentionally has z-order above other views.
         )
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeMediaSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeMediaSection.kt
new file mode 100644
index 0000000..5afdbaa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeMediaSection.kt
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.view.layout.sections
+
+import android.content.Context
+import android.view.View
+import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
+import android.widget.FrameLayout
+import androidx.constraintlayout.widget.Barrier
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.constraintlayout.widget.ConstraintSet
+import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
+import androidx.constraintlayout.widget.ConstraintSet.END
+import androidx.constraintlayout.widget.ConstraintSet.MATCH_CONSTRAINT
+import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
+import androidx.constraintlayout.widget.ConstraintSet.START
+import androidx.constraintlayout.widget.ConstraintSet.TOP
+import com.android.systemui.Flags.migrateClocksToBlueprint
+import com.android.systemui.keyguard.shared.model.KeyguardSection
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel
+import com.android.systemui.media.controls.ui.KeyguardMediaController
+import com.android.systemui.res.R
+import com.android.systemui.shade.NotificationPanelView
+import javax.inject.Inject
+
+/** Aligns media on left side for split shade, below smartspace, date, and weather. */
+class SplitShadeMediaSection
+@Inject
+constructor(
+    private val context: Context,
+    private val notificationPanelView: NotificationPanelView,
+    private val keyguardSmartspaceViewModel: KeyguardSmartspaceViewModel,
+    private val keyguardMediaController: KeyguardMediaController
+) : KeyguardSection() {
+    private val mediaContainerId = R.id.status_view_media_container
+    private val smartSpaceBarrier = R.id.smart_space_barrier_bottom
+
+    override fun addViews(constraintLayout: ConstraintLayout) {
+        if (!migrateClocksToBlueprint()) {
+            return
+        }
+
+        notificationPanelView.findViewById<View>(mediaContainerId)?.let {
+            notificationPanelView.removeView(it)
+        }
+
+        val mediaFrame =
+            FrameLayout(context, null).apply {
+                id = mediaContainerId
+                val padding = context.resources.getDimensionPixelSize(R.dimen.qs_media_padding)
+                val horizontalPadding =
+                    padding +
+                        context.resources.getDimensionPixelSize(
+                            R.dimen.status_view_margin_horizontal
+                        )
+
+                setPaddingRelative(horizontalPadding, padding, horizontalPadding, padding)
+            }
+        constraintLayout.addView(mediaFrame)
+        keyguardMediaController.attachSplitShadeContainer(mediaFrame)
+    }
+
+    override fun bindData(constraintLayout: ConstraintLayout) {}
+
+    override fun applyConstraints(constraintSet: ConstraintSet) {
+        if (!migrateClocksToBlueprint()) {
+            return
+        }
+
+        constraintSet.apply {
+            constrainWidth(mediaContainerId, MATCH_CONSTRAINT)
+            constrainHeight(mediaContainerId, WRAP_CONTENT)
+
+            createBarrier(
+                smartSpaceBarrier,
+                Barrier.BOTTOM,
+                0,
+                *intArrayOf(
+                    keyguardSmartspaceViewModel.smartspaceViewId,
+                    keyguardSmartspaceViewModel.dateId,
+                    keyguardSmartspaceViewModel.weatherId,
+                )
+            )
+            connect(mediaContainerId, TOP, smartSpaceBarrier, BOTTOM)
+            connect(mediaContainerId, START, PARENT_ID, START)
+            connect(mediaContainerId, END, R.id.split_shade_guideline, END)
+        }
+    }
+
+    override fun removeViews(constraintLayout: ConstraintLayout) {
+        if (!migrateClocksToBlueprint()) {
+            return
+        }
+
+        constraintLayout.removeView(mediaContainerId)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
index 945bf9a..e15e038 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
@@ -27,6 +27,7 @@
 import android.view.ViewGroup
 import androidx.annotation.VisibleForTesting
 import com.android.systemui.Dumpable
+import com.android.systemui.Flags.migrateClocksToBlueprint
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.dump.DumpManager
@@ -180,7 +181,11 @@
     /** Called whenever the media hosts visibility changes */
     private fun onMediaHostVisibilityChanged(visible: Boolean) {
         refreshMediaPosition(reason = "onMediaHostVisibilityChanged")
+
         if (visible) {
+            if (migrateClocksToBlueprint() && useSplitShade) {
+                return
+            }
             mediaHost.hostView.layoutParams.apply {
                 height = ViewGroup.LayoutParams.WRAP_CONTENT
                 width = ViewGroup.LayoutParams.MATCH_PARENT
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 17eb3c8..286037e 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -1160,9 +1160,9 @@
         // Occluded->Lockscreen
         collectFlow(mView, mKeyguardTransitionInteractor.getOccludedToLockscreenTransition(),
                 mOccludedToLockscreenTransition, mMainDispatcher);
-        if (!KeyguardShadeMigrationNssl.isEnabled()) {
-            collectFlow(mView, mOccludedToLockscreenTransitionViewModel.getLockscreenAlpha(),
+        collectFlow(mView, mOccludedToLockscreenTransitionViewModel.getLockscreenAlpha(),
                 setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
+        if (!KeyguardShadeMigrationNssl.isEnabled()) {
             collectFlow(mView,
                     mOccludedToLockscreenTransitionViewModel.getLockscreenTranslationY(),
                     setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher);
@@ -1192,8 +1192,10 @@
                 mLockscreenToOccludedTransition, mMainDispatcher);
         collectFlow(mView, mLockscreenToOccludedTransitionViewModel.getLockscreenAlpha(),
                 setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
-        collectFlow(mView, mLockscreenToOccludedTransitionViewModel.getLockscreenTranslationY(),
-                setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher);
+        if (!KeyguardShadeMigrationNssl.isEnabled()) {
+            collectFlow(mView, mLockscreenToOccludedTransitionViewModel.getLockscreenTranslationY(),
+                    setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher);
+        }
 
         // Primary bouncer->Gone (ensures lockscreen content is not visible on successful auth)
         collectFlow(mView, mPrimaryBouncerToGoneTransitionViewModel.getLockscreenAlpha(),
@@ -1463,6 +1465,9 @@
     }
 
     private void attachSplitShadeMediaPlayerContainer(FrameLayout container) {
+        if (migrateClocksToBlueprint()) {
+            return;
+        }
         mKeyguardMediaController.attachSplitShadeContainer(container);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index 70ccc4f..80ef14b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.notification.collection.inflation;
 
+import static com.android.systemui.Flags.screenshareNotificationHiding;
 import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED;
 import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED;
 import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_PUBLIC;
@@ -243,7 +244,11 @@
         params.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
         params.setUseLowPriority(isLowPriority);
 
-        if (mNotificationLockscreenUserManager.needsRedaction(entry)) {
+        // If screenshareNotificationHiding is enabled, both public and private views should be
+        // inflated to avoid any latency associated with reinflating all notification views when
+        // screen share starts and stops
+        if (screenshareNotificationHiding()
+                || mNotificationLockscreenUserManager.needsRedaction(entry)) {
             params.requireContentViews(FLAG_CONTENT_VIEW_PUBLIC);
         } else {
             params.markContentViewsFreeable(FLAG_CONTENT_VIEW_PUBLIC);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index eff91e5..5ee38be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -25,6 +25,8 @@
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.StatusBarState.SHADE_LOCKED
+import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
+import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
 import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
@@ -71,6 +73,20 @@
             KeyguardState.PRIMARY_BOUNCER
         )
 
+    private val lockscreenToOccludedRunning =
+        keyguardTransitionInteractor
+            .transition(KeyguardState.LOCKSCREEN, KeyguardState.OCCLUDED)
+            .map { it.transitionState == STARTED || it.transitionState == RUNNING }
+            .distinctUntilChanged()
+            .onStart { emit(false) }
+
+    private val occludedToLockscreenRunning =
+        keyguardTransitionInteractor
+            .transition(KeyguardState.OCCLUDED, KeyguardState.LOCKSCREEN)
+            .map { it.transitionState == STARTED || it.transitionState == RUNNING }
+            .distinctUntilChanged()
+            .onStart { emit(false) }
+
     val shadeCollapseFadeInComplete = MutableStateFlow(false)
 
     val configurationBasedDimensions: Flow<ConfigurationBasedDimensions> =
@@ -122,7 +138,11 @@
             ) { isKeyguard, isShadeVisible, qsExpansion ->
                 isKeyguard && !(isShadeVisible || qsExpansion)
             }
-            .distinctUntilChanged()
+            .stateIn(
+                scope = applicationScope,
+                started = SharingStarted.Eagerly,
+                initialValue = false,
+            )
 
     /** Fade in only for use after the shade collapses */
     val shadeCollpaseFadeIn: Flow<Boolean> =
@@ -182,26 +202,37 @@
             )
 
     val alpha: Flow<Float> =
-        isOnLockscreenWithoutShade
-            .flatMapLatest { isOnLockscreenWithoutShade ->
-                combineTransform(
-                    merge(
-                        occludedToLockscreenTransitionViewModel.lockscreenAlpha,
-                        lockscreenToOccludedTransitionViewModel.lockscreenAlpha,
-                        keyguardInteractor.keyguardAlpha,
-                    ),
-                    shadeCollpaseFadeIn,
-                ) { alpha, shadeCollpaseFadeIn ->
-                    if (isOnLockscreenWithoutShade) {
-                        if (!shadeCollpaseFadeIn) {
-                            emit(alpha)
-                        }
+        // Due to issues with the legacy shade, some shade expansion events are sent incorrectly,
+        // such as when the shade resets. This can happen while the LOCKSCREEN<->OCCLUDED transition
+        // is running. Therefore use a series of flatmaps to prevent unwanted interruptions while
+        // those transitions are in progress. Without this, the alpha value will produce a visible
+        // flicker.
+        lockscreenToOccludedRunning.flatMapLatest { isLockscreenToOccludedRunning ->
+            if (isLockscreenToOccludedRunning) {
+                lockscreenToOccludedTransitionViewModel.lockscreenAlpha
+            } else {
+                occludedToLockscreenRunning.flatMapLatest { isOccludedToLockscreenRunning ->
+                    if (isOccludedToLockscreenRunning) {
+                        occludedToLockscreenTransitionViewModel.lockscreenAlpha.onStart { emit(0f) }
                     } else {
-                        emit(1f)
+                        isOnLockscreenWithoutShade.flatMapLatest { isOnLockscreenWithoutShade ->
+                            combineTransform(
+                                keyguardInteractor.keyguardAlpha,
+                                shadeCollpaseFadeIn,
+                            ) { alpha, shadeCollpaseFadeIn ->
+                                if (isOnLockscreenWithoutShade) {
+                                    if (!shadeCollpaseFadeIn) {
+                                        emit(alpha)
+                                    }
+                                } else {
+                                    emit(1f)
+                                }
+                            }
+                        }
                     }
                 }
             }
-            .distinctUntilChanged()
+        }
 
     /**
      * Under certain scenarios, such as swiping up on the lockscreen, the container will need to be
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java
index 5e57c83..bc50c25 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java
@@ -198,7 +198,7 @@
         AtomicBoolean isBgThreadFailed = new AtomicBoolean(false);
         Thread bgThread = new Thread(() -> {
             assertTrue(getLock(unloadLock, 10));
-            assertTrue(getLock(loadLock, 3000)); // Wait for the foreground thread
+            assertTrue(getLock(loadLock, 4000)); // Wait for the foreground thread
             assertNotNull(mPluginInstance.getPlugin());
             // Attempt to delete the plugin, this should block until the load completes
             mPluginInstance.unloadPlugin();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index 36a4712..20020f2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -43,6 +43,7 @@
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
@@ -418,13 +419,13 @@
         }
 
     @Test
-    fun shadeCollpaseFadeIn() =
+    fun shadeCollapseFadeIn() =
         testScope.runTest {
+            val fadeIn by collectLastValue(underTest.shadeCollpaseFadeIn)
+
             // Start on lockscreen without the shade
             underTest.setShadeCollapseFadeInComplete(false)
             showLockscreen()
-
-            val fadeIn by collectLastValue(underTest.shadeCollpaseFadeIn)
             assertThat(fadeIn).isEqualTo(false)
 
             // ... then the shade expands
@@ -440,10 +441,12 @@
             assertThat(fadeIn).isEqualTo(false)
         }
 
-    private suspend fun showLockscreen() {
+    private suspend fun TestScope.showLockscreen() {
         shadeRepository.setLockscreenShadeExpansion(0f)
         shadeRepository.setQsExpansion(0f)
+        runCurrent()
         keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
+        runCurrent()
         keyguardTransitionRepository.sendTransitionSteps(
             from = KeyguardState.AOD,
             to = KeyguardState.LOCKSCREEN,
@@ -451,10 +454,12 @@
         )
     }
 
-    private suspend fun showLockscreenWithShadeExpanded() {
+    private suspend fun TestScope.showLockscreenWithShadeExpanded() {
         shadeRepository.setLockscreenShadeExpansion(1f)
         shadeRepository.setQsExpansion(0f)
+        runCurrent()
         keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED)
+        runCurrent()
         keyguardTransitionRepository.sendTransitionSteps(
             from = KeyguardState.AOD,
             to = KeyguardState.LOCKSCREEN,
@@ -462,10 +467,12 @@
         )
     }
 
-    private suspend fun showLockscreenWithQSExpanded() {
+    private suspend fun TestScope.showLockscreenWithQSExpanded() {
         shadeRepository.setLockscreenShadeExpansion(0f)
         shadeRepository.setQsExpansion(1f)
+        runCurrent()
         keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED)
+        runCurrent()
         keyguardTransitionRepository.sendTransitionSteps(
             from = KeyguardState.AOD,
             to = KeyguardState.LOCKSCREEN,
diff --git a/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java b/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java
index 4df2581..5d609bc 100644
--- a/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java
+++ b/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java
@@ -54,8 +54,8 @@
 
     @NonNull private final Context mContext;
     @NonNull private final PackageManager mPackageManager;
-    @NonNull private final FaceManager mFaceManager;
-    @NonNull private final FingerprintManager mFingerprintManager;
+    @Nullable private final FaceManager mFaceManager;
+    @Nullable private final FingerprintManager mFingerprintManager;
 
     private final boolean mEnabled;
     private final float mThreshold;
@@ -197,11 +197,11 @@
     }
 
     private boolean hasEnrolledFace(int userId) {
-        return mFaceManager.hasEnrolledTemplates(userId);
+        return mFaceManager != null && mFaceManager.hasEnrolledTemplates(userId);
     }
 
     private boolean hasEnrolledFingerprint(int userId) {
-        return mFingerprintManager.hasEnrolledTemplates(userId);
+        return mFingerprintManager != null && mFingerprintManager.hasEnrolledTemplates(userId);
     }
 
     /**
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
index e546f42..1660c3e 100644
--- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -21,11 +21,13 @@
 import android.Manifest;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.app.admin.DevicePolicyManager;
 import android.app.role.RoleManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
 import android.os.Binder;
 import android.os.BugreportManager.BugreportCallback;
 import android.os.BugreportParams;
@@ -37,7 +39,6 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
-import android.os.UserManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -95,7 +96,6 @@
     private static final long DEFAULT_BUGREPORT_SERVICE_TIMEOUT_MILLIS = 30 * 1000;
 
     private final Object mLock = new Object();
-    private final Injector mInjector;
     private final Context mContext;
     private final AppOpsManager mAppOps;
     private final TelephonyManager mTelephonyManager;
@@ -346,14 +346,6 @@
         AtomicFile getMappingFile() {
             return mMappingFile;
         }
-
-        UserManager getUserManager() {
-            return mContext.getSystemService(UserManager.class);
-        }
-
-        DevicePolicyManager getDevicePolicyManager() {
-            return mContext.getSystemService(DevicePolicyManager.class);
-        }
     }
 
     BugreportManagerServiceImpl(Context context) {
@@ -365,7 +357,6 @@
 
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
     BugreportManagerServiceImpl(Injector injector) {
-        mInjector = injector;
         mContext = injector.getContext();
         mAppOps = mContext.getSystemService(AppOpsManager.class);
         mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
@@ -398,7 +389,12 @@
         int callingUid = Binder.getCallingUid();
         enforcePermission(callingPackage, callingUid, bugreportMode
                 == BugreportParams.BUGREPORT_MODE_TELEPHONY /* checkCarrierPrivileges */);
-        ensureUserCanTakeBugReport(bugreportMode);
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            ensureUserCanTakeBugReport(bugreportMode);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
 
         Slogf.i(TAG, "Starting bugreport for %s / %d", callingPackage, callingUid);
         synchronized (mLock) {
@@ -437,6 +433,7 @@
     @RequiresPermission(value = Manifest.permission.DUMP, conditional = true)
     public void retrieveBugreport(int callingUidUnused, String callingPackage, int userId,
             FileDescriptor bugreportFd, String bugreportFile,
+
             boolean keepBugreportOnRetrievalUnused, IDumpstateListener listener) {
         int callingUid = Binder.getCallingUid();
         enforcePermission(callingPackage, callingUid, false);
@@ -568,48 +565,54 @@
     }
 
     /**
-     * Validates that the calling user is an admin user or, when bugreport is requested remotely
-     * that the user is an affiliated user.
+     * Validates that the current user is an admin user or, when bugreport is requested remotely
+     * that the current user is an affiliated user.
      *
-     * @throws IllegalArgumentException if the calling user is not an admin user
+     * @throws IllegalArgumentException if the current user is not an admin user
      */
     private void ensureUserCanTakeBugReport(int bugreportMode) {
-        // Get the calling userId before clearing the caller identity.
-        int callingUserId = UserHandle.getUserId(Binder.getCallingUid());
-        boolean isAdminUser = false;
-        final long identity = Binder.clearCallingIdentity();
+        UserInfo currentUser = null;
         try {
-            isAdminUser = mInjector.getUserManager().isUserAdmin(callingUserId);
-        } finally {
-            Binder.restoreCallingIdentity(identity);
+            currentUser = ActivityManager.getService().getCurrentUser();
+        } catch (RemoteException e) {
+            // Impossible to get RemoteException for an in-process call.
         }
-        if (!isAdminUser) {
+
+        if (currentUser == null) {
+            logAndThrow("There is no current user, so no bugreport can be requested.");
+        }
+
+        if (!currentUser.isAdmin()) {
             if (bugreportMode == BugreportParams.BUGREPORT_MODE_REMOTE
-                    && isUserAffiliated(callingUserId)) {
+                    && isCurrentUserAffiliated(currentUser.id)) {
                 return;
             }
-            logAndThrow(TextUtils.formatSimple("Calling user %s is not an admin user."
-                    + " Only admin users are allowed to take bugreport.", callingUserId));
+            logAndThrow(TextUtils.formatSimple("Current user %s is not an admin user."
+                    + " Only admin users are allowed to take bugreport.", currentUser.id));
         }
     }
 
     /**
-     * Returns {@code true} if the device has device owner and the specified user is affiliated
+     * Returns {@code true} if the device has device owner and the current user is affiliated
      * with the device owner.
      */
-    private boolean isUserAffiliated(int userId) {
-        DevicePolicyManager dpm = mInjector.getDevicePolicyManager();
+    private boolean isCurrentUserAffiliated(int currentUserId) {
+        DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
         int deviceOwnerUid = dpm.getDeviceOwnerUserId();
         if (deviceOwnerUid == UserHandle.USER_NULL) {
             return false;
         }
 
-        if (DEBUG) {
-            Slog.d(TAG, "callingUid: " + userId + " deviceOwnerUid: " + deviceOwnerUid);
-        }
+        int callingUserId = UserHandle.getUserId(Binder.getCallingUid());
 
-        if (userId != deviceOwnerUid && !dpm.isAffiliatedUser(userId)) {
-            logAndThrow("User " + userId + " is not affiliated to the device owner.");
+        Slog.i(TAG, "callingUid: " + callingUserId + " deviceOwnerUid: " + deviceOwnerUid
+                + " currentUserId: " + currentUserId);
+
+        if (callingUserId != deviceOwnerUid) {
+            logAndThrow("Caller is not device owner on provisioned device.");
+        }
+        if (!dpm.isAffiliatedUser(currentUserId)) {
+            logAndThrow("Current user is not affiliated to the device owner.");
         }
         return true;
     }
diff --git a/services/core/java/com/android/server/pm/BroadcastHelper.java b/services/core/java/com/android/server/pm/BroadcastHelper.java
index 7f58e75e..e830d28 100644
--- a/services/core/java/com/android/server/pm/BroadcastHelper.java
+++ b/services/core/java/com/android/server/pm/BroadcastHelper.java
@@ -827,7 +827,8 @@
             // action. When the targetPkg is set, it sends the broadcast to specific app, e.g.
             // installer app or null for registered apps. The callback only need to send back to the
             // registered apps so we check the null condition here.
-            notifyPackageMonitor(action, pkg, extras, userIds, instantUserIds, broadcastAllowList);
+            notifyPackageMonitor(action, pkg, extras, userIds, instantUserIds, broadcastAllowList,
+                    null /* filterExtras */);
         }
     }
 
@@ -975,14 +976,16 @@
         final Bundle options = new BroadcastOptions()
                 .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE)
                 .toBundle();
+        BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver =
+                (callingUid, intentExtras) -> BroadcastHelper.filterExtrasChangedPackageList(
+                        snapshot, callingUid, intentExtras);
         mHandler.post(() -> sendPackageBroadcast(intent, null /* pkg */,
                 extras, flags, null /* targetPkg */, null /* finishedReceiver */,
                 new int[]{userId}, null /* instantUserIds */, null /* broadcastAllowList */,
-                (callingUid, intentExtras) -> BroadcastHelper.filterExtrasChangedPackageList(
-                        snapshot, callingUid, intentExtras),
+                filterExtrasForReceiver,
                 options));
         notifyPackageMonitor(intent, null /* pkg */, extras, new int[]{userId},
-                null /* instantUserIds */, null /* broadcastAllowList */);
+                null /* instantUserIds */, null /* broadcastAllowList */, filterExtrasForReceiver);
     }
 
     void sendMyPackageSuspendedOrUnsuspended(@NonNull Computer snapshot,
@@ -1068,9 +1071,10 @@
                                       @Nullable Bundle extras,
                                       @NonNull int[] userIds,
                                       @NonNull int[] instantUserIds,
-                                      @Nullable SparseArray<int[]> broadcastAllowList) {
+                                      @Nullable SparseArray<int[]> broadcastAllowList,
+                                      @Nullable BiFunction<Integer, Bundle, Bundle> filterExtras) {
         mPackageMonitorCallbackHelper.notifyPackageMonitor(action, pkg, extras, userIds,
-                instantUserIds, broadcastAllowList, mHandler);
+                instantUserIds, broadcastAllowList, mHandler, filterExtras);
     }
 
     private void notifyResourcesChanged(boolean mediaStatus,
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b7deef0..5225529 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -4626,7 +4626,7 @@
                 });
                 mPackageMonitorCallbackHelper.notifyPackageMonitor(Intent.ACTION_PACKAGE_UNSTOPPED,
                         packageName, extras, userIds, null /* instantUserIds */,
-                        broadcastAllowList, mHandler);
+                        broadcastAllowList, mHandler, null /* filterExtras */);
             }
         }
     }
@@ -7076,7 +7076,7 @@
             }
             mPackageMonitorCallbackHelper.notifyPackageMonitor(Intent.ACTION_PACKAGE_RESTARTED,
                     packageName, extras, userIds, null /* instantUserIds */,
-                    broadcastAllowList, mHandler);
+                    broadcastAllowList, mHandler, null /* filterExtras */);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/pm/PackageMonitorCallbackHelper.java b/services/core/java/com/android/server/pm/PackageMonitorCallbackHelper.java
index 1bb0730..d05e4c6 100644
--- a/services/core/java/com/android/server/pm/PackageMonitorCallbackHelper.java
+++ b/services/core/java/com/android/server/pm/PackageMonitorCallbackHelper.java
@@ -41,6 +41,7 @@
 import com.android.internal.util.ArrayUtils;
 
 import java.util.ArrayList;
+import java.util.function.BiFunction;
 
 /** Helper class to handle PackageMonitorCallback and notify the registered client. This is mainly
  * used by PackageMonitor to improve the broadcast latency. */
@@ -105,8 +106,9 @@
             extras.putBoolean(Intent.EXTRA_ARCHIVAL, true);
         }
         extras.putInt(PackageInstaller.EXTRA_DATA_LOADER_TYPE, dataLoaderType);
-        notifyPackageMonitor(Intent.ACTION_PACKAGE_ADDED, packageName, extras ,
-                userIds /* userIds */, instantUserIds, broadcastAllowList, handler);
+        notifyPackageMonitor(Intent.ACTION_PACKAGE_ADDED, packageName, extras,
+                userIds /* userIds */, instantUserIds, broadcastAllowList, handler,
+                null /* filterExtras */);
     }
 
     public void notifyResourcesChanged(boolean mediaStatus, boolean replacing,
@@ -120,7 +122,8 @@
         String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE
                 : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE;
         notifyPackageMonitor(action, null /* pkg */, extras, null /* userIds */,
-                null /* instantUserIds */, null /* broadcastAllowList */, handler);
+                null /* instantUserIds */, null /* broadcastAllowList */, handler,
+                null /* filterExtras */);
     }
 
     public void notifyPackageChanged(String packageName, boolean dontKillApp,
@@ -137,12 +140,12 @@
             extras.putString(Intent.EXTRA_REASON, reason);
         }
         notifyPackageMonitor(Intent.ACTION_PACKAGE_CHANGED, packageName, extras, userIds,
-                instantUserIds, broadcastAllowList, handler);
+                instantUserIds, broadcastAllowList, handler, null /* filterExtras */);
     }
 
     public void notifyPackageMonitor(String action, String pkg, Bundle extras,
             int[] userIds, int[] instantUserIds, SparseArray<int[]> broadcastAllowList,
-            Handler handler) {
+            Handler handler, BiFunction<Integer, Bundle, Bundle> filterExtras) {
         if (!isAllowedCallbackAction(action)) {
             return;
         }
@@ -160,10 +163,11 @@
 
             if (ArrayUtils.isEmpty(instantUserIds)) {
                 doNotifyCallbacksByAction(
-                        action, pkg, extras, resolvedUserIds, broadcastAllowList, handler);
+                        action, pkg, extras, resolvedUserIds, broadcastAllowList, handler,
+                        filterExtras);
             } else {
                 doNotifyCallbacksByAction(action, pkg, extras, instantUserIds, broadcastAllowList,
-                        handler);
+                        handler, filterExtras);
             }
         } catch (RemoteException e) {
             // do nothing
@@ -199,11 +203,13 @@
         synchronized (mLock) {
             callbacks = mCallbacks;
         }
-        doNotifyCallbacks(callbacks, intent, userId, broadcastAllowList, handler);
+        doNotifyCallbacks(callbacks, intent, userId, broadcastAllowList, handler,
+                null /* filterExtrasFunction */);
     }
 
     private void doNotifyCallbacksByAction(String action, String pkg, Bundle extras, int[] userIds,
-            SparseArray<int[]> broadcastAllowList, Handler handler) {
+            SparseArray<int[]> broadcastAllowList, Handler handler,
+            BiFunction<Integer, Bundle, Bundle> filterExtrasFunction) {
         RemoteCallbackList<IRemoteCallback> callbacks;
         synchronized (mLock) {
             callbacks = mCallbacks;
@@ -223,12 +229,13 @@
 
             final int[] allowUids =
                     broadcastAllowList != null ? broadcastAllowList.get(userId) : null;
-            doNotifyCallbacks(callbacks, intent, userId, allowUids, handler);
+            doNotifyCallbacks(callbacks, intent, userId, allowUids, handler, filterExtrasFunction);
         }
     }
 
     private void doNotifyCallbacks(RemoteCallbackList<IRemoteCallback> callbacks,
-            Intent intent, int userId, int[] allowUids, Handler handler) {
+            Intent intent, int userId, int[] allowUids, Handler handler,
+            BiFunction<Integer, Bundle, Bundle> filterExtrasFunction) {
         handler.post(() -> callbacks.broadcast((callback, user) -> {
             RegisterUser registerUser = (RegisterUser) user;
             if ((registerUser.getUserId() != UserHandle.USER_ALL) && (registerUser.getUserId()
@@ -236,6 +243,15 @@
                 return;
             }
             int registerUid = registerUser.getUid();
+            if (filterExtrasFunction != null) {
+                final Bundle extras = intent.getExtras();
+                if (extras != null) {
+                    final Bundle filteredExtras = filterExtrasFunction.apply(registerUid, extras);
+                    if (filteredExtras != null) {
+                        intent.replaceExtras(filteredExtras);
+                    }
+                }
+            }
             if (allowUids != null && registerUid != Process.SYSTEM_UID
                     && !ArrayUtils.contains(allowUids, registerUid)) {
                 if (DEBUG) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 145eb3b..ca8afe1 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -223,7 +223,6 @@
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
 import static com.android.server.wm.ActivityTaskManagerService.getInputDispatchingTimeoutMillisLocked;
-import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.IdentifierProto.HASH_CODE;
 import static com.android.server.wm.IdentifierProto.TITLE;
 import static com.android.server.wm.IdentifierProto.USER_ID;
@@ -949,7 +948,7 @@
     private int mConfigurationSeq;
 
     /**
-     * Temp configs used in {@link #ensureActivityConfiguration(int, boolean)}
+     * Temp configs used in {@link #ensureActivityConfiguration()}
      */
     private final Configuration mTmpConfig = new Configuration();
     private final Rect mTmpBounds = new Rect();
@@ -1511,7 +1510,7 @@
                 updatePictureInPictureMode(null, false);
             } else {
                 mLastReportedMultiWindowMode = inMultiWindowMode;
-                ensureActivityConfiguration(0 /* globalChanges */, PRESERVE_WINDOWS);
+                ensureActivityConfiguration();
             }
         }
     }
@@ -1530,8 +1529,7 @@
             // precede the configuration change from the resize.
             mLastReportedPictureInPictureMode = inPictureInPictureMode;
             mLastReportedMultiWindowMode = inPictureInPictureMode;
-            ensureActivityConfiguration(0 /* globalChanges */, PRESERVE_WINDOWS,
-                    true /* ignoreVisibility */);
+            ensureActivityConfiguration(true /* ignoreVisibility */);
             if (inPictureInPictureMode && findMainWindow() == null) {
                 // Prevent malicious app entering PiP without valid WindowState, which can in turn
                 // result a non-touchable PiP window since the InputConsumer for PiP requires it.
@@ -3107,7 +3105,7 @@
         // {@link #returningOptions} of the activity under this one can be applied in
         // {@link #handleAlreadyVisible()}.
         if (changed || !occludesParent) {
-            mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
+            mRootWindowContainer.ensureActivitiesVisible();
         }
         return changed;
     }
@@ -3747,8 +3745,8 @@
             }
 
             if (ensureVisibility) {
-                mDisplayContent.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
-                        false /* preserveWindows */, true /* notifyClients */);
+                mDisplayContent.ensureActivitiesVisible(null /* starting */,
+                        true /* notifyClients */);
             }
         }
 
@@ -4165,8 +4163,7 @@
         if (rootTask != null && rootTask.shouldSleepOrShutDownActivities()) {
             // Activity is always relaunched to either resumed or paused state. If it was
             // relaunched while hidden (by keyguard or smth else), it should be stopped.
-            rootTask.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
-                    false /* preserveWindows */);
+            rootTask.ensureActivitiesVisible(null /* starting */);
         }
     }
 
@@ -4681,14 +4678,12 @@
 
     void setShowWhenLocked(boolean showWhenLocked) {
         mShowWhenLocked = showWhenLocked;
-        mAtmService.mRootWindowContainer.ensureActivitiesVisible(null /* starting */,
-                0 /* configChanges */, false /* preserveWindows */);
+        mAtmService.mRootWindowContainer.ensureActivitiesVisible();
     }
 
     void setInheritShowWhenLocked(boolean inheritShowWhenLocked) {
         mInheritShownWhenLocked = inheritShowWhenLocked;
-        mAtmService.mRootWindowContainer.ensureActivitiesVisible(null /* starting */,
-                0 /* configChanges */, false /* preserveWindows */);
+        mAtmService.mRootWindowContainer.ensureActivitiesVisible();
     }
 
     /**
@@ -6413,7 +6408,7 @@
         }
 
         mDisplayContent.handleActivitySizeCompatModeIfNeeded(this);
-        mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
+        mRootWindowContainer.ensureActivitiesVisible();
     }
 
     /**
@@ -7894,7 +7889,7 @@
     void applyFixedRotationTransform(DisplayInfo info, DisplayFrames displayFrames,
             Configuration config) {
         super.applyFixedRotationTransform(info, displayFrames, config);
-        ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
+        ensureActivityConfiguration();
     }
 
     /**
@@ -7989,7 +7984,7 @@
         startFreezingScreen(originalDisplayRotation);
         // This activity may relaunch or perform configuration change so once it has reported drawn,
         // the screen can be unfrozen.
-        ensureActivityConfiguration(0 /* globalChanges */, !PRESERVE_WINDOWS);
+        ensureActivityConfiguration();
         if (mTransitionController.isCollecting(this)) {
             // In case the task was changed from PiP but still keeps old transform.
             task.resetSurfaceControlTransforms();
@@ -8017,7 +8012,7 @@
         // the request is handled at task level with letterbox.
         if (!getMergedOverrideConfiguration().equals(
                 mLastReportedConfiguration.getMergedConfiguration())) {
-            ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */,
+            ensureActivityConfiguration(
                     false /* ignoreVisibility */, true /* isRequestedOrientationChanged */);
             if (mTransitionController.inPlayingTransition(this)) {
                 mTransitionController.mValidateActivityCompat.add(this);
@@ -9525,14 +9520,12 @@
         return mLastReportedDisplayId != getDisplayId();
     }
 
-    boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow) {
-        return ensureActivityConfiguration(globalChanges, preserveWindow,
-                false /* ignoreVisibility */, false /* isRequestedOrientationChanged */);
+    boolean ensureActivityConfiguration() {
+        return ensureActivityConfiguration(false /* ignoreVisibility */);
     }
 
-    boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow,
-            boolean ignoreVisibility) {
-        return ensureActivityConfiguration(globalChanges, preserveWindow, ignoreVisibility,
+    boolean ensureActivityConfiguration(boolean ignoreVisibility) {
+        return ensureActivityConfiguration(ignoreVisibility,
                 false /* isRequestedOrientationChanged */);
     }
 
@@ -9540,9 +9533,6 @@
      * Make sure the given activity matches the current configuration. Ensures the HistoryRecord
      * is updated with the correct configuration and all other bookkeeping is handled.
      *
-     * @param globalChanges The changes to the global configuration.
-     * @param preserveWindow If the activity window should be preserved on screen if the activity
-     *                       is relaunched.
      * @param ignoreVisibility If we should try to relaunch the activity even if it is invisible
      *                         (stopped state). This is useful for the case where we know the
      *                         activity will be visible soon and we want to ensure its configuration
@@ -9552,8 +9542,8 @@
      * @return False if the activity was relaunched and true if it wasn't relaunched because we
      *         can't or the app handles the specific configuration that is changing.
      */
-    boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow,
-            boolean ignoreVisibility, boolean isRequestedOrientationChanged) {
+    boolean ensureActivityConfiguration(boolean ignoreVisibility,
+            boolean isRequestedOrientationChanged) {
         final Task rootTask = getRootTask();
         if (rootTask.mConfigWillChange) {
             ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check "
@@ -9667,10 +9657,21 @@
         if (shouldRelaunchLocked(changes, mTmpConfig)) {
             // Aha, the activity isn't handling the change, so DIE DIE DIE.
             configChangeFlags |= changes;
-            startFreezingScreenLocked(globalChanges);
+            if (mVisible && mAtmService.mTmpUpdateConfigurationResult.mIsUpdating
+                    && !mTransitionController.isShellTransitionsEnabled()) {
+                startFreezingScreenLocked(mAtmService.mTmpUpdateConfigurationResult.changes);
+            }
+            final boolean displayMayChange = mTmpConfig.windowConfiguration.getDisplayRotation()
+                    != getWindowConfiguration().getDisplayRotation()
+                    || !mTmpConfig.windowConfiguration.getMaxBounds().equals(
+                            getWindowConfiguration().getMaxBounds());
+            final boolean isAppResizeOnly = !displayMayChange
+                    && (changes & ~(CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE
+                            | CONFIG_ORIENTATION | CONFIG_SCREEN_LAYOUT)) == 0;
             // Do not preserve window if it is freezing screen because the original window won't be
             // able to update drawn state that causes freeze timeout.
-            preserveWindow &= isResizeOnlyChange(changes) && !mFreezingScreen;
+            // TODO(b/258618073): Always preserve if possible.
+            final boolean preserveWindow = isAppResizeOnly && !mFreezingScreen;
             final boolean hasResizeChange = hasResizeChange(changes & ~info.getRealConfigChanged());
             if (hasResizeChange) {
                 final boolean isDragResizing = task.isDragResizing();
@@ -9834,11 +9835,6 @@
         return changes;
     }
 
-    private static boolean isResizeOnlyChange(int change) {
-        return (change & ~(CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE | CONFIG_ORIENTATION
-                | CONFIG_SCREEN_LAYOUT)) == 0;
-    }
-
     private static boolean hasResizeChange(int change) {
         return (change & (CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE | CONFIG_ORIENTATION
                 | CONFIG_SCREEN_LAYOUT)) != 0;
@@ -9882,8 +9878,6 @@
                     task.mTaskId, shortComponentName, Integer.toHexString(configChangeFlags));
         }
 
-        startFreezingScreenLocked(0);
-
         try {
             ProtoLog.i(WM_DEBUG_STATES, "Moving to %s Relaunching %s callers=%s" ,
                     (andResume ? "RESUMED" : "PAUSED"), this, Debug.getCallers(6));
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index cb2adbc..d90d017 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -73,7 +73,6 @@
 import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
 import static com.android.server.wm.ActivityTaskSupervisor.DEFER_RESUME;
 import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP;
-import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.BackgroundActivityStartController.BAL_ALLOW_DEFAULT;
 import static com.android.server.wm.BackgroundActivityStartController.BAL_BLOCK;
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS;
@@ -1733,6 +1732,7 @@
             // So disallow the transient hide activity to move itself to front, e.g. trampoline.
             if (!avoidMoveToFront() && (mService.mHomeProcess == null
                     || mService.mHomeProcess.mUid != realCallingUid)
+                    && (prevTopTask != null && prevTopTask.isActivityTypeHomeOrRecents())
                     && r.mTransitionController.isTransientHide(targetTask)) {
                 mCanMoveToFrontCode = MOVE_TO_FRONT_AVOID_LEGACY;
             }
@@ -1859,8 +1859,7 @@
                 // over is removed.
                 // Passing {@code null} as the start parameter ensures all activities are made
                 // visible.
-                mTargetRootTask.ensureActivitiesVisible(null /* starting */,
-                        0 /* configChanges */, !PRESERVE_WINDOWS);
+                mTargetRootTask.ensureActivitiesVisible(null /* starting */);
                 // Go ahead and tell window manager to execute app transition for this activity
                 // since the app transition will not be triggered through the resume channel.
                 mTargetRootTask.mDisplayContent.executeAppTransition();
@@ -2867,7 +2866,7 @@
                 mRootWindowContainer.resumeFocusedTasksTopActivities(mTargetRootTask, null,
                         mOptions, mTransientLaunch);
             } else {
-                mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
+                mRootWindowContainer.ensureActivitiesVisible();
             }
         } else {
             ActivityOptions.abort(mOptions);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index dbae29b..f43c1b0 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -118,7 +118,6 @@
 import static com.android.server.wm.ActivityTaskManagerService.UiHandler.DISMISS_DIALOG_UI_MSG;
 import static com.android.server.wm.ActivityTaskSupervisor.DEFER_RESUME;
 import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP;
-import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.ActivityTaskSupervisor.REMOVE_FROM_RECENTS;
 import static com.android.server.wm.BackgroundActivityStartController.BalVerdict;
 import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_DONT_LOCK;
@@ -496,16 +495,13 @@
     final UpdateConfigurationResult mTmpUpdateConfigurationResult =
             new UpdateConfigurationResult();
 
+    // TODO(b/258618073): Remove this and make the related methods return whether config is changed.
     static final class UpdateConfigurationResult {
         // Configuration changes that were updated.
         int changes;
         // If the activity was relaunched to match the new configuration.
         boolean activityRelaunched;
-
-        void reset() {
-            changes = 0;
-            activityRelaunched = false;
-        }
+        boolean mIsUpdating;
     }
 
     /** Current sequencing integer of the configuration, for skipping old configurations. */
@@ -3834,8 +3830,7 @@
                     Settings.System.clearConfiguration(values);
                 }
                 updateConfigurationLocked(values, null, false, false /* persistent */,
-                        UserHandle.USER_NULL, false /* deferResume */,
-                        mTmpUpdateConfigurationResult);
+                        UserHandle.USER_NULL, false /* deferResume */);
                 return mTmpUpdateConfigurationResult.changes != 0;
             } finally {
                 Binder.restoreCallingIdentity(origId);
@@ -4507,12 +4502,6 @@
         }
     }
 
-    private boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
-            boolean initLocale, boolean persistent, int userId, boolean deferResume) {
-        return updateConfigurationLocked(values, starting, initLocale, persistent, userId,
-                deferResume, null /* result */);
-    }
-
     /**
      * Do either or both things: (1) change the current configuration, and (2)
      * make sure the given activity is running with the (now) current
@@ -4524,8 +4513,7 @@
      *               for that particular user
      */
     boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
-            boolean initLocale, boolean persistent, int userId, boolean deferResume,
-            ActivityTaskManagerService.UpdateConfigurationResult result) {
+            boolean initLocale, boolean persistent, int userId, boolean deferResume) {
         int changes = 0;
         boolean kept = true;
 
@@ -4533,19 +4521,18 @@
         try {
             if (values != null) {
                 changes = updateGlobalConfigurationLocked(values, initLocale, persistent, userId);
+                mTmpUpdateConfigurationResult.changes = changes;
+                mTmpUpdateConfigurationResult.mIsUpdating = true;
             }
 
             if (!deferResume) {
                 kept = ensureConfigAndVisibilityAfterUpdate(starting, changes);
             }
         } finally {
+            mTmpUpdateConfigurationResult.mIsUpdating = false;
             continueWindowLayout();
         }
-
-        if (result != null) {
-            result.changes = changes;
-            result.activityRelaunched = !kept;
-        }
+        mTmpUpdateConfigurationResult.activityRelaunched = !kept;
         return kept;
     }
 
@@ -5325,12 +5312,10 @@
             }
 
             if (starting != null) {
-                kept = starting.ensureActivityConfiguration(changes,
-                        false /* preserveWindow */);
+                kept = starting.ensureActivityConfiguration();
                 // And we need to make sure at this point that all other activities
                 // are made visible with the correct configuration.
-                mRootWindowContainer.ensureActivitiesVisible(starting, changes,
-                        !PRESERVE_WINDOWS);
+                mRootWindowContainer.ensureActivitiesVisible(starting);
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 10efb94..1872f6e 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -1462,7 +1462,7 @@
                 }
                 mLaunchingActivityWakeLock.release();
             }
-            mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
+            mRootWindowContainer.ensureActivitiesVisible();
         }
 
         // Atomically retrieve all of the other things to do.
@@ -1603,7 +1603,7 @@
          */
         rootTask.cancelAnimation();
         rootTask.setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, true /* set */);
-        rootTask.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
+        rootTask.ensureActivitiesVisible(null /* starting */);
         activityIdleInternal(null /* idleActivity */, false /* fromTimeout */,
                 true /* processPausingActivities */, null /* configuration */);
 
@@ -1622,7 +1622,7 @@
             // Follow on the workaround: activities are kept force hidden till the new windowing
             // mode is set.
             rootTask.setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, false /* set */);
-            mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
+            mRootWindowContainer.ensureActivitiesVisible();
             mRootWindowContainer.resumeFocusedTasksTopActivities();
         } finally {
             mService.continueWindowLayout();
@@ -2026,7 +2026,7 @@
 
         final Task rootTask = r.getRootTask();
         if (rootTask.getDisplayArea().allResumedActivitiesComplete()) {
-            mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
+            mRootWindowContainer.ensureActivitiesVisible();
             // Make sure activity & window visibility should be identical
             // for all displays in this stage.
             mRootWindowContainer.executeAppTransitionForAllDisplay();
@@ -2042,7 +2042,7 @@
 
         mRecentTasks.add(task);
         mService.getTaskChangeNotificationController().notifyTaskStackChanged();
-        rootTask.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
+        rootTask.ensureActivitiesVisible(null /* starting */);
 
         // When launching tasks behind, update the last active time of the top task after the new
         // task has been shown briefly
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index c3f1e41..22d17b5 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -1614,7 +1614,7 @@
                 "Setting Activity.mLauncherTaskBehind to true. Activity=%s", activity);
         activity.mTaskSupervisor.mStoppingActivities.remove(activity);
         activity.getDisplayContent().ensureActivitiesVisible(null /* starting */,
-                0 /* configChanges */, false /* preserveWindows */, true);
+                true /* notifyClients */);
     }
 
     private static void restoreLaunchBehind(@NonNull ActivityRecord activity) {
diff --git a/services/core/java/com/android/server/wm/ClientLifecycleManager.java b/services/core/java/com/android/server/wm/ClientLifecycleManager.java
index 2e47677..e4eb7b3 100644
--- a/services/core/java/com/android/server/wm/ClientLifecycleManager.java
+++ b/services/core/java/com/android/server/wm/ClientLifecycleManager.java
@@ -74,13 +74,13 @@
     }
 
     /**
-     * Similar to {@link #scheduleTransactionItem}, but is called without WM lock.
+     * Similar to {@link #scheduleTransactionItem}, but it sends the transaction immediately and
+     * it can be called without WM lock.
      *
      * @see WindowProcessController#setReportedProcState(int)
      */
-    void scheduleTransactionItemUnlocked(@NonNull IApplicationThread client,
+    void scheduleTransactionItemNow(@NonNull IApplicationThread client,
             @NonNull ClientTransactionItem transactionItem) throws RemoteException {
-        // Immediately dispatching to client, and must not access WMS.
         final ClientTransaction clientTransaction = ClientTransaction.obtain(client);
         if (transactionItem.isActivityLifecycleItem()) {
             clientTransaction.setLifecycleStateRequest((ActivityLifecycleItem) transactionItem);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index f8dc9c7..e7ecf52 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -779,7 +779,7 @@
 
     /**
      * Used to prevent recursions when calling
-     * {@link #ensureActivitiesVisible(ActivityRecord, int, boolean, boolean)}
+     * {@link #ensureActivitiesVisible(ActivityRecord, boolean)}
      */
     private boolean mInEnsureActivitiesVisible = false;
 
@@ -1713,7 +1713,7 @@
         if (handled && requestingContainer instanceof ActivityRecord) {
             final ActivityRecord activityRecord = (ActivityRecord) requestingContainer;
             final boolean kept = updateDisplayOverrideConfigurationLocked(config, activityRecord,
-                    false /* deferResume */, null /* result */);
+                    false /* deferResume */);
             if (!kept) {
                 mRootWindowContainer.resumeFocusedTasksTopActivities();
             }
@@ -1721,7 +1721,7 @@
             // We have a new configuration to push so we need to update ATMS for now.
             // TODO: Clean up display configuration push between ATMS and WMS after unification.
             updateDisplayOverrideConfigurationLocked(config, null /* starting */,
-                    false /* deferResume */, null);
+                    false /* deferResume */);
         }
         return handled;
     }
@@ -6333,7 +6333,7 @@
 
         Settings.System.clearConfiguration(values);
         updateDisplayOverrideConfigurationLocked(values, null /* starting */,
-                false /* deferResume */, mAtmService.mTmpUpdateConfigurationResult);
+                false /* deferResume */);
         return mAtmService.mTmpUpdateConfigurationResult.changes != 0;
     }
 
@@ -6342,8 +6342,7 @@
      * new one will be computed in WM based on current display info.
      */
     boolean updateDisplayOverrideConfigurationLocked(Configuration values,
-            ActivityRecord starting, boolean deferResume,
-            ActivityTaskManagerService.UpdateConfigurationResult result) {
+            ActivityRecord starting, boolean deferResume) {
 
         int changes = 0;
         boolean kept = true;
@@ -6361,19 +6360,19 @@
                 } else {
                     changes = performDisplayOverrideConfigUpdate(values);
                 }
+                mAtmService.mTmpUpdateConfigurationResult.changes = changes;
+                mAtmService.mTmpUpdateConfigurationResult.mIsUpdating = true;
             }
 
             if (!deferResume) {
                 kept = mAtmService.ensureConfigAndVisibilityAfterUpdate(starting, changes);
             }
         } finally {
+            mAtmService.mTmpUpdateConfigurationResult.mIsUpdating = false;
             mAtmService.continueWindowLayout();
         }
 
-        if (result != null) {
-            result.changes = changes;
-            result.activityRelaunched = !kept;
-        }
+        mAtmService.mTmpUpdateConfigurationResult.activityRelaunched = !kept;
         return kept;
     }
 
@@ -6569,8 +6568,7 @@
     }
 
 
-    void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
-            boolean preserveWindows, boolean notifyClients) {
+    void ensureActivitiesVisible(ActivityRecord starting, boolean notifyClients) {
         if (mInEnsureActivitiesVisible) {
             // Don't do recursive work.
             return;
@@ -6579,8 +6577,7 @@
         try {
             mInEnsureActivitiesVisible = true;
             forAllRootTasks(rootTask -> {
-                rootTask.ensureActivitiesVisible(starting, configChanges, preserveWindows,
-                        notifyClients);
+                rootTask.ensureActivitiesVisible(starting, notifyClients);
             });
             if (mTransitionController.useShellTransitionsRotation()
                     && mTransitionController.isCollecting()
@@ -6619,7 +6616,7 @@
         if (!wasTransitionSet) {
             prepareAppTransition(TRANSIT_NONE);
         }
-        mRootWindowContainer.ensureActivitiesVisible(null, 0, false /* preserveWindows */);
+        mRootWindowContainer.ensureActivitiesVisible();
 
         // If there was a transition set already we don't want to interfere with it as we might be
         // starting it too early.
diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
index 9cc311d..f40eb24 100644
--- a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
+++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java
@@ -33,8 +33,6 @@
     private boolean mAboveTop;
     private boolean mContainerShouldBeVisible;
     private boolean mBehindFullyOccludedContainer;
-    private int mConfigChanges;
-    private boolean mPreserveWindows;
     private boolean mNotifyClients;
 
     EnsureActivitiesVisibleHelper(TaskFragment container) {
@@ -45,14 +43,10 @@
      * Update all attributes except {@link mTaskFragment} to use in subsequent calculations.
      *
      * @param starting The activity that is being started
-     * @param configChanges Parts of the configuration that changed for this activity for evaluating
-     *                      if the screen should be frozen.
-     * @param preserveWindows Flag indicating whether windows should be preserved when updating.
      * @param notifyClients Flag indicating whether the configuration and visibility changes shoulc
      *                      be sent to the clients.
      */
-    void reset(ActivityRecord starting, int configChanges, boolean preserveWindows,
-            boolean notifyClients) {
+    void reset(ActivityRecord starting, boolean notifyClients) {
         mStarting = starting;
         mTopRunningActivity = mTaskFragment.topRunningActivity();
         // If the top activity is not fullscreen, then we need to make sure any activities under it
@@ -60,33 +54,26 @@
         mAboveTop = mTopRunningActivity != null;
         mContainerShouldBeVisible = mTaskFragment.shouldBeVisible(mStarting);
         mBehindFullyOccludedContainer = !mContainerShouldBeVisible;
-        mConfigChanges = configChanges;
-        mPreserveWindows = preserveWindows;
         mNotifyClients = notifyClients;
     }
 
     /**
      * Update and commit visibility with an option to also update the configuration of visible
      * activities.
-     * @see Task#ensureActivitiesVisible(ActivityRecord, int, boolean)
-     * @see RootWindowContainer#ensureActivitiesVisible(ActivityRecord, int, boolean)
+     * @see Task#ensureActivitiesVisible(ActivityRecord)
+     * @see RootWindowContainer#ensureActivitiesVisible()
      * @param starting The top most activity in the task.
      *                 The activity is either starting or resuming.
      *                 Caller should ensure starting activity is visible.
      *
-     * @param configChanges Parts of the configuration that changed for this activity for evaluating
-     *                      if the screen should be frozen.
-     * @param preserveWindows Flag indicating whether windows should be preserved when updating.
      * @param notifyClients Flag indicating whether the configuration and visibility changes shoulc
      *                      be sent to the clients.
      */
-    void process(@Nullable ActivityRecord starting, int configChanges, boolean preserveWindows,
-            boolean notifyClients) {
-        reset(starting, configChanges, preserveWindows, notifyClients);
+    void process(@Nullable ActivityRecord starting, boolean notifyClients) {
+        reset(starting, notifyClients);
 
         if (DEBUG_VISIBILITY) {
-            Slog.v(TAG_VISIBILITY, "ensureActivitiesVisible behind " + mTopRunningActivity
-                    + " configChanges=0x" + Integer.toHexString(configChanges));
+            Slog.v(TAG_VISIBILITY, "ensureActivitiesVisible behind " + mTopRunningActivity);
         }
         if (mTopRunningActivity != null && mTaskFragment.asTask() != null) {
             // TODO(14709632): Check if this needed to be implemented in TaskFragment.
@@ -107,8 +94,7 @@
             final TaskFragment childTaskFragment = child.asTaskFragment();
             if (childTaskFragment != null
                     && childTaskFragment.getTopNonFinishingActivity() != null) {
-                childTaskFragment.updateActivityVisibilities(starting, configChanges,
-                        preserveWindows, notifyClients);
+                childTaskFragment.updateActivityVisibilities(starting, notifyClients);
                 // The TaskFragment should fully occlude the activities below if the bounds
                 // equals to its parent task, unless it is translucent.
                 mBehindFullyOccludedContainer |=
@@ -188,13 +174,11 @@
             // First: if this is not the current activity being started, make
             // sure it matches the current configuration.
             if (r != mStarting && mNotifyClients) {
-                r.ensureActivityConfiguration(0 /* globalChanges */, mPreserveWindows,
-                        true /* ignoreVisibility */);
+                r.ensureActivityConfiguration(true /* ignoreVisibility */);
             }
 
             if (!r.attachedToProcess()) {
-                makeVisibleAndRestartIfNeeded(mStarting, mConfigChanges,
-                        resumeTopActivity && isTop, r);
+                makeVisibleAndRestartIfNeeded(mStarting, resumeTopActivity && isTop, r);
             } else if (r.isVisibleRequested()) {
                 // If this activity is already visible, then there is nothing to do here.
                 if (DEBUG_VISIBILITY) {
@@ -213,8 +197,6 @@
             } else {
                 r.makeVisibleIfNeeded(mStarting, mNotifyClients);
             }
-            // Aggregate current change flags.
-            mConfigChanges |= r.configChangeFlags;
         } else {
             if (DEBUG_VISIBILITY) {
                 Slog.v(TAG_VISIBILITY, "Make invisible? " + r
@@ -242,16 +224,13 @@
         }
     }
 
-    private void makeVisibleAndRestartIfNeeded(ActivityRecord starting, int configChanges,
+    private void makeVisibleAndRestartIfNeeded(ActivityRecord starting,
             boolean andResume, ActivityRecord r) {
         // This activity needs to be visible, but isn't even running...
         // get it started and resume if no other root task in this root task is resumed.
         if (DEBUG_VISIBILITY) {
             Slog.v(TAG_VISIBILITY, "Start and freeze screen for " + r);
         }
-        if (r != starting) {
-            r.startFreezingScreenLocked(configChanges);
-        }
         if (!r.isVisibleRequested() || r.mLaunchTaskBehind) {
             if (DEBUG_VISIBILITY) {
                 Slog.v(TAG_VISIBILITY, "Starting and making visible: " + r);
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index cbc7b83..6d11804 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -43,7 +43,6 @@
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.KeyguardControllerProto.AOD_SHOWING;
 import static com.android.server.wm.KeyguardControllerProto.KEYGUARD_GOING_AWAY;
 import static com.android.server.wm.KeyguardControllerProto.KEYGUARD_PER_DISPLAY;
@@ -239,7 +238,7 @@
         // Update the sleep token first such that ensureActivitiesVisible has correct sleep token
         // state when evaluating visibilities.
         updateKeyguardSleepToken();
-        mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
+        mRootWindowContainer.ensureActivitiesVisible();
         InputMethodManagerInternal.get().updateImeWindowStatus(false /* disableImeIcon */,
                 displayId);
         setWakeTransitionReady();
@@ -291,7 +290,7 @@
 
             // Some stack visibility might change (e.g. docked stack)
             mRootWindowContainer.resumeFocusedTasksTopActivities();
-            mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
+            mRootWindowContainer.ensureActivitiesVisible();
             mRootWindowContainer.addStartingWindowsForVisibleActivities();
             mWindowManager.executeAppTransition();
         } finally {
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 5269d35..7b23004 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -28,7 +28,6 @@
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS;
 import static com.android.server.wm.ActivityRecord.State.STOPPED;
 import static com.android.server.wm.ActivityRecord.State.STOPPING;
-import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
 import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
 import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_TOP;
@@ -126,8 +125,7 @@
                 // The activity may be relaunched if it cannot handle the current configuration
                 // changes. The activity will be paused state if it is relaunched, otherwise it
                 // keeps the original stopped state.
-                targetActivity.ensureActivityConfiguration(0 /* globalChanges */,
-                        false /* preserveWindow */, true /* ignoreVisibility */);
+                targetActivity.ensureActivityConfiguration(true /* ignoreVisibility */);
                 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Updated config=%s",
                         targetActivity.getConfiguration());
             }
@@ -261,7 +259,7 @@
 
             // If we updated the launch-behind state, update the visibility of the activities after
             // we fetch the visible tasks to be controlled by the animation
-            mService.mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
+            mService.mRootWindowContainer.ensureActivitiesVisible();
 
             ActivityOptions options = null;
             if (eventTime > 0) {
@@ -380,8 +378,7 @@
                         // transition (the target activity will be one of closing apps).
                         if (!controller.shouldDeferCancelWithScreenshot()
                                 && !targetRootTask.isFocusedRootTaskOnDisplay()) {
-                            targetRootTask.ensureActivitiesVisible(null /* starting */,
-                                    0 /* starting */, false /* preserveWindows */);
+                            targetRootTask.ensureActivitiesVisible(null /* starting */);
                         }
                         // Keep target root task in place, nothing changes, so ignore the transition
                         // logic below
@@ -389,7 +386,7 @@
                     }
 
                     mWindowManager.prepareAppTransitionNone();
-                    mService.mRootWindowContainer.ensureActivitiesVisible(null, 0, false);
+                    mService.mRootWindowContainer.ensureActivitiesVisible();
                     mService.mRootWindowContainer.resumeFocusedTasksTopActivities();
 
                     // No reason to wait for the pausing activity in this case, as the hiding of
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 9a75dae..ca66a66 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -63,7 +63,6 @@
 import static com.android.server.wm.ActivityTaskManagerService.isPip2ExperimentEnabled;
 import static com.android.server.wm.ActivityTaskSupervisor.DEFER_RESUME;
 import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP;
-import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.ActivityTaskSupervisor.dumpHistoryList;
 import static com.android.server.wm.ActivityTaskSupervisor.printThisActivity;
 import static com.android.server.wm.KeyguardController.KEYGUARD_SLEEP_TOKEN_TAG;
@@ -1753,8 +1752,7 @@
         // activities are affecting configuration now.
         // Passing null here for 'starting' param value, so that visibility of actual starting
         // activity will be properly updated.
-        ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
-                false /* preserveWindows */, false /* notifyClients */);
+        ensureActivitiesVisible(null /* starting */, false /* notifyClients */);
 
         if (displayId == INVALID_DISPLAY) {
             // The caller didn't provide a valid display id, skip updating config.
@@ -1778,7 +1776,7 @@
         if (displayContent != null) {
             // Update the configuration of the activities on the display.
             return displayContent.updateDisplayOverrideConfigurationLocked(config, starting,
-                    deferResume, null /* result */);
+                    deferResume);
         } else {
             return true;
         }
@@ -1865,16 +1863,18 @@
      * Make sure that all activities that need to be visible in the system actually are and update
      * their configuration.
      */
-    void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
-            boolean preserveWindows) {
-        ensureActivitiesVisible(starting, configChanges, preserveWindows, true /* notifyClients */);
+    void ensureActivitiesVisible() {
+        ensureActivitiesVisible(null /* starting */);
+    }
+
+    void ensureActivitiesVisible(ActivityRecord starting) {
+        ensureActivitiesVisible(starting, true /* notifyClients */);
     }
 
     /**
-     * @see #ensureActivitiesVisible(ActivityRecord, int, boolean)
+     * @see #ensureActivitiesVisible()
      */
-    void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
-            boolean preserveWindows, boolean notifyClients) {
+    void ensureActivitiesVisible(ActivityRecord starting, boolean notifyClients) {
         if (mTaskSupervisor.inActivityVisibilityUpdate()
                 || mTaskSupervisor.isRootVisibilityUpdateDeferred()) {
             // Don't do recursive work.
@@ -1885,8 +1885,7 @@
             // First the front root tasks. In case any are not fullscreen and are in front of home.
             for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
                 final DisplayContent display = getChildAt(displayNdx);
-                display.ensureActivitiesVisible(starting, configChanges, preserveWindows,
-                        notifyClients);
+                display.ensureActivitiesVisible(starting, notifyClients);
             }
         } finally {
             mTaskSupervisor.endActivityVisibilityUpdate();
@@ -2237,7 +2236,7 @@
             try {
                 if (localVisibilityDeferred) {
                     mTaskSupervisor.setDeferRootVisibilityUpdate(false);
-                    ensureActivitiesVisible(null, 0, false /* preserveWindows */);
+                    ensureActivitiesVisible();
                 }
             } finally {
                 transitionController.continueTransitionReady();
@@ -2370,7 +2369,7 @@
             // It may be nothing to resume because there are pausing activities or all the top
             // activities are resumed. Then it still needs to make sure all visible activities are
             // running in case the tasks were reordered or there are non-top visible activities.
-            ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, !PRESERVE_WINDOWS);
+            ensureActivitiesVisible();
         }
     }
 
@@ -2542,8 +2541,7 @@
                     // display orientation can be updated first if needed. Otherwise there may
                     // have redundant configuration changes due to apply outdated display
                     // orientation (from keyguard) to activity.
-                    rootTask.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
-                            false /* preserveWindows */);
+                    rootTask.ensureActivitiesVisible(null /* starting */);
                 }
             });
         }
@@ -2885,8 +2883,7 @@
             if (allowDelay) {
                 result[0] &= task.goToSleepIfPossible(shuttingDown);
             } else {
-                task.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
-                        !PRESERVE_WINDOWS);
+                task.ensureActivitiesVisible(null /* starting */);
             }
         });
         return result[0];
@@ -3774,8 +3771,7 @@
                 }
             }
             if (!mHasActivityStarted) {
-                ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
-                        false /* preserveWindows */);
+                ensureActivitiesVisible();
             }
             return mHasActivityStarted;
         }
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 7995028..ed54ea8 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -771,6 +771,7 @@
             if (mLastReportedAnimatorScale != mService.getCurrentAnimatorScale()) {
                 mService.dispatchNewAnimatorScaleLocked(this);
             }
+            mProcess.mWindowSession = this;
         }
         mAddedWindows.add(w);
     }
@@ -782,6 +783,9 @@
         }
     }
 
+    boolean hasWindow() {
+        return !mAddedWindows.isEmpty();
+    }
 
     void onWindowSurfaceVisibilityChanged(WindowSurfaceController surfaceController,
             boolean visible, int type) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index dbfcc22..c674176 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -90,7 +90,6 @@
 import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_ACTIVITY_TASK_MSG;
 import static com.android.server.wm.ActivityTaskSupervisor.DEFER_RESUME;
 import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP;
-import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.ActivityTaskSupervisor.REMOVE_FROM_RECENTS;
 import static com.android.server.wm.ActivityTaskSupervisor.printThisActivity;
 import static com.android.server.wm.IdentifierProto.HASH_CODE;
@@ -760,7 +759,7 @@
             return;
         }
         mResizeMode = resizeMode;
-        mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
+        mRootWindowContainer.ensureActivitiesVisible();
         mRootWindowContainer.resumeFocusedTasksTopActivities();
         updateTaskDescription();
     }
@@ -801,15 +800,14 @@
             if (setBounds(bounds, forced) != BOUNDS_CHANGE_NONE) {
                 final ActivityRecord r = topRunningActivityLocked();
                 if (r != null) {
-                    kept = r.ensureActivityConfiguration(0 /* globalChanges */,
-                            preserveWindow);
+                    kept = r.ensureActivityConfiguration();
                     // Preserve other windows for resizing because if resizing happens when there
                     // is a dialog activity in the front, the activity that still shows some
                     // content to the user will become black and cause flickers. Note in most cases
                     // this won't cause tons of irrelevant windows being preserved because only
                     // activities in this task may experience a bounds change. Configs for other
                     // activities stay the same.
-                    mRootWindowContainer.ensureActivitiesVisible(r, 0, preserveWindow);
+                    mRootWindowContainer.ensureActivitiesVisible(r);
                     if (!kept) {
                         mRootWindowContainer.resumeFocusedTasksTopActivities();
                     }
@@ -915,7 +913,7 @@
         if (!deferResume) {
             // The task might have already been running and its visibility needs to be synchronized
             // with the visibility of the root task / windows.
-            root.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
+            root.ensureActivitiesVisible();
             root.resumeFocusedTasksTopActivities();
         }
 
@@ -4752,7 +4750,7 @@
         }
 
         if (!mTaskSupervisor.isRootVisibilityUpdateDeferred()) {
-            mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
+            mRootWindowContainer.ensureActivitiesVisible();
             mRootWindowContainer.resumeFocusedTasksTopActivities();
         }
     }
@@ -4793,8 +4791,7 @@
         mRootWindowContainer.resumeFocusedTasksTopActivities();
         // Update visibility of activities before notifying WM. This way it won't try to resize
         // windows that are no longer visible.
-        mRootWindowContainer.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
-                !PRESERVE_WINDOWS);
+        mRootWindowContainer.ensureActivitiesVisible();
     }
 
     final boolean isOnHomeDisplay() {
@@ -4938,41 +4935,27 @@
      * @param starting The top most activity in the task.
      *                 The activity is either starting or resuming.
      *                 Caller should ensure starting activity is visible.
-     * @param preserveWindows Flag indicating whether windows should be preserved when updating
-     *                        configuration in {@link EnsureActivitiesVisibleHelper}.
-     * @param configChanges Parts of the configuration that changed for this activity for evaluating
-     *                      if the screen should be frozen as part of
-     *                      {@link EnsureActivitiesVisibleHelper}.
-     *
      */
-    void ensureActivitiesVisible(@Nullable ActivityRecord starting, int configChanges,
-            boolean preserveWindows) {
-        ensureActivitiesVisible(starting, configChanges, preserveWindows, true /* notifyClients */);
+    void ensureActivitiesVisible(@Nullable ActivityRecord starting) {
+        ensureActivitiesVisible(starting, true /* notifyClients */);
     }
 
     /**
      * Ensure visibility with an option to also update the configuration of visible activities.
-     * @see #ensureActivitiesVisible(ActivityRecord, int, boolean)
-     * @see RootWindowContainer#ensureActivitiesVisible(ActivityRecord, int, boolean)
+     * @see #ensureActivitiesVisible(ActivityRecord)
+     * @see RootWindowContainer#ensureActivitiesVisible()
      * @param starting The top most activity in the task.
      *                 The activity is either starting or resuming.
      *                 Caller should ensure starting activity is visible.
      * @param notifyClients Flag indicating whether the visibility updates should be sent to the
      *                      clients in {@link EnsureActivitiesVisibleHelper}.
-     * @param preserveWindows Flag indicating whether windows should be preserved when updating
-     *                        configuration in {@link EnsureActivitiesVisibleHelper}.
-     * @param configChanges Parts of the configuration that changed for this activity for evaluating
-     *                      if the screen should be frozen as part of
-     *                      {@link EnsureActivitiesVisibleHelper}.
      */
     // TODO: Should be re-worked based on the fact that each task as a root task in most cases.
-    void ensureActivitiesVisible(@Nullable ActivityRecord starting, int configChanges,
-            boolean preserveWindows, boolean notifyClients) {
+    void ensureActivitiesVisible(@Nullable ActivityRecord starting, boolean notifyClients) {
         mTaskSupervisor.beginActivityVisibilityUpdate();
         try {
             forAllLeafTasks(task -> {
-                task.updateActivityVisibilities(starting, configChanges, preserveWindows,
-                        notifyClients);
+                task.updateActivityVisibilities(starting, notifyClients);
             }, true /* traverseTopToBottom */);
 
             if (mTranslucentActivityWaiting != null &&
@@ -5273,7 +5256,7 @@
             // tell WindowManager that r is visible even though it is at the back of the root
             // task.
             r.setVisibility(true);
-            ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
+            ensureActivitiesVisible(null /* starting */);
             // If launching behind, the app will start regardless of what's above it, so mark it
             // as unknown even before prior `pause`. This also prevents a race between set-ready
             // and activityPause. Launch-behind is basically only used for dream now.
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index c57983c..90a3b253 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -1777,13 +1777,11 @@
         void onRootTaskOrderChanged(Task rootTask);
     }
 
-    void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
-            boolean preserveWindows, boolean notifyClients) {
+    void ensureActivitiesVisible(ActivityRecord starting, boolean notifyClients) {
         mAtmService.mTaskSupervisor.beginActivityVisibilityUpdate();
         try {
             forAllRootTasks(rootTask -> {
-                rootTask.ensureActivitiesVisible(starting, configChanges, preserveWindows,
-                        notifyClients);
+                rootTask.ensureActivitiesVisible(starting, notifyClients);
             });
         } finally {
             mAtmService.mTaskSupervisor.endActivityVisibilityUpdate();
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 5d01912..d425bdf 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -57,7 +57,6 @@
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TRANSITION;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.ActivityTaskSupervisor.printThisActivity;
 import static com.android.server.wm.IdentifierProto.HASH_CODE;
 import static com.android.server.wm.IdentifierProto.TITLE;
@@ -950,8 +949,7 @@
         }
 
         if (shouldSleep) {
-            updateActivityVisibilities(null /* starting */, 0 /* configChanges */,
-                    !PRESERVE_WINDOWS, true /* notifyClients */);
+            updateActivityVisibilities(null /* starting */, true /* notifyClients */);
         }
 
         return shouldSleep;
@@ -1218,12 +1216,11 @@
         return top != null && top.mLaunchTaskBehind;
     }
 
-    final void updateActivityVisibilities(@Nullable ActivityRecord starting, int configChanges,
-            boolean preserveWindows, boolean notifyClients) {
+    final void updateActivityVisibilities(@Nullable ActivityRecord starting,
+            boolean notifyClients) {
         mTaskSupervisor.beginActivityVisibilityUpdate();
         try {
-            mEnsureActivitiesVisibleHelper.process(
-                    starting, configChanges, preserveWindows, notifyClients);
+            mEnsureActivitiesVisibleHelper.process(starting, notifyClients);
         } finally {
             mTaskSupervisor.endActivityVisibilityUpdate();
         }
@@ -1249,8 +1246,7 @@
         if (mResumedActivity == next && next.isState(RESUMED)
                 && taskDisplayArea.allResumedActivitiesComplete()) {
             // Ensure the visibility gets updated before execute app transition.
-            taskDisplayArea.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
-                    false /* preserveWindows */, true /* notifyClients */);
+            taskDisplayArea.ensureActivitiesVisible(null /* starting */, true /* notifyClients */);
             // Make sure we have executed any pending transitions, since there
             // should be nothing left to do at this point.
             executeAppTransition(options);
@@ -1907,7 +1903,7 @@
             prev.resumeKeyDispatchingLocked();
         }
 
-        mRootWindowContainer.ensureActivitiesVisible(resuming, 0, !PRESERVE_WINDOWS);
+        mRootWindowContainer.ensureActivitiesVisible(resuming);
 
         // Notify when the task stack has changed, but only if visibilities changed (not just
         // focus). Also if there is an active root pinned task - we always want to notify it about
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 3117db5..b12855e 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -1136,8 +1136,7 @@
             // The transient hide tasks could be occluded now, e.g. returning to home. So trigger
             // the update to make the activities in the tasks invisible-requested, then the next
             // step can continue to commit the visibility.
-            mController.mAtm.mRootWindowContainer.ensureActivitiesVisible(null /* starting */,
-                    0 /* configChanges */, true /* preserveWindows */);
+            mController.mAtm.mRootWindowContainer.ensureActivitiesVisible();
             // Record all the now-hiding activities so that they are committed. Just use
             // mParticipants because we can avoid a new list this way.
             for (int i = 0; i < mTransientHideTasks.size(); ++i) {
@@ -2863,8 +2862,7 @@
      * check whether to deliver the new configuration to clients.
      */
     @Nullable
-    ArrayList<ActivityRecord> applyDisplayChangeIfNeeded() {
-        ArrayList<ActivityRecord> activitiesMayChange = null;
+    void applyDisplayChangeIfNeeded(@NonNull ArraySet<WindowContainer<?>> activitiesMayChange) {
         for (int i = mParticipants.size() - 1; i >= 0; --i) {
             final WindowContainer<?> wc = mParticipants.valueAt(i);
             final DisplayContent dc = wc.asDisplayContent();
@@ -2881,18 +2879,13 @@
             // If the update is deferred, sendNewConfiguration won't deliver new configuration to
             // clients, then it is the caller's responsibility to deliver the changes.
             if (mController.mAtm.mTaskSupervisor.isRootVisibilityUpdateDeferred()) {
-                if (activitiesMayChange == null) {
-                    activitiesMayChange = new ArrayList<>();
-                }
-                final ArrayList<ActivityRecord> visibleActivities = activitiesMayChange;
                 dc.forAllActivities(r -> {
                     if (r.isVisibleRequested()) {
-                        visibleActivities.add(r);
+                        activitiesMayChange.add(r);
                     }
                 });
             }
         }
-        return activitiesMayChange;
     }
 
     boolean getLegacyIsReady() {
diff --git a/services/core/java/com/android/server/wm/WindowManagerFlags.java b/services/core/java/com/android/server/wm/WindowManagerFlags.java
index 89a70e5..7b0d931 100644
--- a/services/core/java/com/android/server/wm/WindowManagerFlags.java
+++ b/services/core/java/com/android/server/wm/WindowManagerFlags.java
@@ -43,8 +43,6 @@
 
     /* Start Available Flags */
 
-    final boolean mWindowStateResizeItemFlag = Flags.windowStateResizeItemFlag();
-
     final boolean mWallpaperOffsetAsync = Flags.wallpaperOffsetAsync();
 
     final boolean mAllowsScreenSizeDecoupledFromStatusBarAndCutout =
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c1310a6..dda33f3 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3105,7 +3105,7 @@
         try {
             synchronized (mGlobalLock) {
                 if (mAtmService.mKeyguardController.isKeyguardShowing(DEFAULT_DISPLAY)) {
-                    mRoot.ensureActivitiesVisible(null, 0, false /* preserveWindows */);
+                    mRoot.ensureActivitiesVisible();
                 }
             }
         } finally {
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 4b99432..9e4a31c 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -65,7 +65,6 @@
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
 import static com.android.server.wm.ActivityRecord.State.PAUSING;
 import static com.android.server.wm.ActivityTaskManagerService.enforceTaskPermission;
-import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS;
 import static com.android.server.wm.ActivityTaskSupervisor.REMOVE_FROM_RECENTS;
 import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_PINNED_TASK;
 import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG;
@@ -571,14 +570,15 @@
         mService.deferWindowLayout();
         mService.mTaskSupervisor.setDeferRootVisibilityUpdate(true /* deferUpdate */);
         try {
-            final ArrayList<ActivityRecord> activitiesMayChange =
-                    transition != null ? transition.applyDisplayChangeIfNeeded() : null;
-            if (activitiesMayChange != null) {
-                effects |= TRANSACT_EFFECTS_CLIENT_CONFIG;
+            final ArraySet<WindowContainer<?>> haveConfigChanges = new ArraySet<>();
+            if (transition != null) {
+                transition.applyDisplayChangeIfNeeded(haveConfigChanges);
+                if (!haveConfigChanges.isEmpty()) {
+                    effects |= TRANSACT_EFFECTS_CLIENT_CONFIG;
+                }
             }
             final List<WindowContainerTransaction.HierarchyOp> hops = t.getHierarchyOps();
             final int hopSize = hops.size();
-            final ArraySet<WindowContainer<?>> haveConfigChanges = new ArraySet<>();
             Iterator<Map.Entry<IBinder, WindowContainerTransaction.Change>> entries =
                     t.getChanges().entrySet().iterator();
             while (entries.hasNext()) {
@@ -626,7 +626,7 @@
                     // When removing pip, make sure that onStop is sent to the app ahead of
                     // onPictureInPictureModeChanged.
                     // See also PinnedStackTests#testStopBeforeMultiWindowCallbacksOnDismiss
-                    wc.asTask().ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
+                    wc.asTask().ensureActivitiesVisible(null /* starting */);
                     wc.asTask().mTaskSupervisor.processStoppingAndFinishingActivities(
                             null /* launchedActivity */, false /* processPausingActivities */,
                             "force-stop-on-removing-pip");
@@ -692,29 +692,16 @@
             if ((effects & TRANSACT_EFFECTS_LIFECYCLE) != 0) {
                 mService.mTaskSupervisor.setDeferRootVisibilityUpdate(false /* deferUpdate */);
                 // Already calls ensureActivityConfig
-                mService.mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
+                mService.mRootWindowContainer.ensureActivitiesVisible();
                 mService.mRootWindowContainer.resumeFocusedTasksTopActivities();
             } else if ((effects & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) {
                 for (int i = haveConfigChanges.size() - 1; i >= 0; --i) {
                     haveConfigChanges.valueAt(i).forAllActivities(r -> {
-                        r.ensureActivityConfiguration(0, PRESERVE_WINDOWS);
-                        if (activitiesMayChange != null) {
-                            activitiesMayChange.remove(r);
+                        if (r.isVisibleRequested()) {
+                            r.ensureActivityConfiguration(true /* ignoreVisibility */);
                         }
                     });
                 }
-                // TODO(b/258618073): Combine with haveConfigChanges after confirming that there
-                //  is no problem to always preserve window. Currently this uses the parameters
-                //  as ATMS#ensureConfigAndVisibilityAfterUpdate.
-                if (activitiesMayChange != null) {
-                    for (int i = activitiesMayChange.size() - 1; i >= 0; --i) {
-                        final ActivityRecord ar = activitiesMayChange.get(i);
-                        if (!ar.isVisibleRequested()) continue;
-                        ar.ensureActivityConfiguration(0 /* globalChanges */,
-                                !PRESERVE_WINDOWS, true /* ignoreVisibility */,
-                                false /* isRequestedOrientationChanged */);
-                    }
-                }
             }
 
             if (effects != 0) {
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 5721750..b8fa5e5 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -188,6 +188,10 @@
     // Set to true when process was launched with a wrapper attached
     private volatile boolean mUsingWrapper;
 
+    /** Non-null if this process may have a window. */
+    @Nullable
+    Session mWindowSession;
+
     // Thread currently set for VR scheduling
     int mVrThreadTid;
 
@@ -399,7 +403,7 @@
             // the latest configuration in their lifecycle callbacks (e.g. onReceive, onCreate).
             try {
                 // No WM lock here.
-                mAtm.getLifecycleManager().scheduleTransactionItemUnlocked(
+                mAtm.getLifecycleManager().scheduleTransactionItemNow(
                         thread, configurationChangeItem);
             } catch (Exception e) {
                 Slog.e(TAG_CONFIGURATION, "Failed to schedule ConfigurationChangeItem="
@@ -989,7 +993,7 @@
             if (packageName.equals(r.packageName)
                     && r.applyAppSpecificConfig(nightMode, localesOverride, gender)
                     && r.isVisibleRequested()) {
-                r.ensureActivityConfiguration(0 /* globalChanges */, true /* preserveWindow */);
+                r.ensureActivityConfiguration();
             }
         }
     }
@@ -1675,7 +1679,12 @@
     private void scheduleClientTransactionItem(@NonNull IApplicationThread thread,
             @NonNull ClientTransactionItem transactionItem) {
         try {
-            mAtm.getLifecycleManager().scheduleTransactionItem(thread, transactionItem);
+            if (mWindowSession != null && mWindowSession.hasWindow()) {
+                mAtm.getLifecycleManager().scheduleTransactionItem(thread, transactionItem);
+            } else {
+                // Non-UI process can handle the change directly.
+                mAtm.getLifecycleManager().scheduleTransactionItemNow(thread, transactionItem);
+            }
         } catch (DeadObjectException e) {
             // Expected if the process has been killed.
             Slog.w(TAG_CONFIGURATION, "Failed for dead process. ClientTransactionItem="
@@ -1723,7 +1732,7 @@
             overrideConfig.assetsSeq = assetSeq;
             r.onRequestedOverrideConfigurationChanged(overrideConfig);
             if (r.isVisibleRequested()) {
-                r.ensureActivityConfiguration(0, true);
+                r.ensureActivityConfiguration();
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 32638e0..58ade1b 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -252,6 +252,7 @@
 import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
 import com.android.server.wm.RefreshRatePolicy.FrameRateVote;
 import com.android.server.wm.SurfaceAnimator.AnimationType;
+import com.android.window.flags.Flags;
 
 import dalvik.annotation.optimization.NeverCompile;
 
@@ -3675,7 +3676,7 @@
 
         markRedrawForSyncReported();
 
-        if (mWmService.mFlags.mWindowStateResizeItemFlag) {
+        if (Flags.bundleClientTransactionFlag()) {
             getProcess().scheduleClientTransactionItem(
                     WindowStateResizeItem.obtain(mClient, mClientWindowFrames, reportDraw,
                             mLastReportedConfiguration, getCompatInsetsState(), forceRelayout,
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
index 4a2e1cb..686b2a8 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
@@ -65,7 +65,6 @@
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.content.PackageMonitor;
 import com.android.server.credentials.metrics.ApiName;
 import com.android.server.credentials.metrics.ApiStatus;
 import com.android.server.infra.AbstractMasterSystemService;
@@ -1204,6 +1203,9 @@
         // If the app being removed matches any of the package names from
         // this list then don't add it in the output.
         Set<String> providers = new HashSet<>();
+        if (rawProviders == null || packageName == null) {
+            return providers;
+        }
         for (String rawComponentName : rawProviders.split(":")) {
             if (TextUtils.isEmpty(rawComponentName)
                     || rawComponentName.equals("null")) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageMonitorCallbackHelperTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/PackageMonitorCallbackHelperTest.java
index 6c44fd0..60cedcf 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageMonitorCallbackHelperTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageMonitorCallbackHelperTest.java
@@ -44,6 +44,7 @@
 import org.mockito.ArgumentCaptor;
 
 import java.util.ArrayList;
+import java.util.function.BiFunction;
 
 /**
  * A unit test for PackageMonitorCallbackHelper implementation.
@@ -78,7 +79,8 @@
 
         mPackageMonitorCallbackHelper.notifyPackageMonitor(Intent.ACTION_PACKAGE_ADDED,
                 FAKE_PACKAGE_NAME, createFakeBundle(), new int[]{0} /* userIds */,
-                null /* instantUserIds */, null /* broadcastAllowList */, mHandler);
+                null /* instantUserIds */, null /* broadcastAllowList */, mHandler,
+                null /* filterExtras */);
 
         verify(callback, after(WAIT_CALLBACK_CALLED_IN_MS).never()).sendResult(any());
     }
@@ -91,7 +93,7 @@
                 Binder.getCallingUid());
         mPackageMonitorCallbackHelper.notifyPackageMonitor(Intent.ACTION_PACKAGE_ADDED,
                 FAKE_PACKAGE_NAME, createFakeBundle(), new int[]{0}, null /* instantUserIds */,
-                null /* broadcastAllowList */, mHandler);
+                null /* broadcastAllowList */, mHandler, null /* filterExtras */);
 
         verify(callback, after(WAIT_CALLBACK_CALLED_IN_MS).times(1)).sendResult(any());
 
@@ -99,12 +101,41 @@
         mPackageMonitorCallbackHelper.unregisterPackageMonitorCallback(callback);
         mPackageMonitorCallbackHelper.notifyPackageMonitor(Intent.ACTION_PACKAGE_ADDED,
                 FAKE_PACKAGE_NAME, createFakeBundle(), new int[]{0} /* userIds */,
-                null /* instantUserIds */, null /* broadcastAllowList */, mHandler);
+                null /* instantUserIds */, null /* broadcastAllowList */, mHandler,
+                null /* filterExtras */);
 
         verify(callback, after(WAIT_CALLBACK_CALLED_IN_MS).never()).sendResult(any());
     }
 
     @Test
+    public void testPackageMonitorCallback_SuspendCallbackCalled() throws Exception {
+        Bundle result = new Bundle();
+        result.putInt(Intent.EXTRA_UID, FAKE_PACKAGE_UID);
+        result.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, new String[]{FAKE_PACKAGE_NAME});
+        BiFunction<Integer, Bundle, Bundle> filterExtras = (callingUid, intentExtras) -> result;
+
+        IRemoteCallback callback = createMockPackageMonitorCallback();
+        mPackageMonitorCallbackHelper.registerPackageMonitorCallback(callback, 0 /* userId */,
+                Binder.getCallingUid());
+        mPackageMonitorCallbackHelper.notifyPackageMonitor(Intent.ACTION_PACKAGES_SUSPENDED,
+                FAKE_PACKAGE_NAME, createFakeBundle(), new int[]{0}, null /* instantUserIds */,
+                null /* broadcastAllowList */, mHandler, filterExtras);
+
+        ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
+        verify(callback, after(WAIT_CALLBACK_CALLED_IN_MS).times(1)).sendResult(
+                bundleCaptor.capture());
+        Bundle bundle = bundleCaptor.getValue();
+        Intent intent = bundle.getParcelable(
+                PackageManager.EXTRA_PACKAGE_MONITOR_CALLBACK_RESULT, Intent.class);
+        assertThat(intent).isNotNull();
+        assertThat(intent.getAction()).isEqualTo(Intent.ACTION_PACKAGES_SUSPENDED);
+        String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
+        assertThat(pkgList).isNotNull();
+        assertThat(pkgList.length).isEqualTo(1);
+        assertThat(pkgList[0]).isEqualTo(FAKE_PACKAGE_NAME);
+    }
+
+    @Test
     public void testRegisterPackageMonitorCallback_callbackCalled() throws Exception {
         IRemoteCallback callback = createMockPackageMonitorCallback();
 
@@ -112,7 +143,8 @@
                 Binder.getCallingUid());
         mPackageMonitorCallbackHelper.notifyPackageMonitor(Intent.ACTION_PACKAGE_ADDED,
                 FAKE_PACKAGE_NAME, createFakeBundle(), new int[]{0} /* userIds */,
-                null /* instantUserIds */, null /* broadcastAllowList */, mHandler);
+                null /* instantUserIds */, null /* broadcastAllowList */, mHandler,
+                null /* filterExtras */);
 
         ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
         verify(callback, after(WAIT_CALLBACK_CALLED_IN_MS).times(1)).sendResult(
@@ -136,7 +168,8 @@
         // Notify for user 10
         mPackageMonitorCallbackHelper.notifyPackageMonitor(Intent.ACTION_PACKAGE_ADDED,
                 FAKE_PACKAGE_NAME, createFakeBundle(), new int[]{10} /* userIds */,
-                null /* instantUserIds */, null /* broadcastAllowList */, mHandler);
+                null /* instantUserIds */, null /* broadcastAllowList */, mHandler,
+                null /* filterExtras */);
 
         verify(callback, after(WAIT_CALLBACK_CALLED_IN_MS).never()).sendResult(any());
     }
@@ -239,7 +272,8 @@
         mPackageMonitorCallbackHelper.onUserRemoved(10);
         mPackageMonitorCallbackHelper.notifyPackageMonitor(Intent.ACTION_PACKAGE_ADDED,
                 FAKE_PACKAGE_NAME, createFakeBundle(), new int[]{10} /* userIds */,
-                null /* instantUserIds */, null /* broadcastAllowList */, mHandler);
+                null /* instantUserIds */, null /* broadcastAllowList */, mHandler,
+                null /* filterExtras */);
 
         verify(callback, after(WAIT_CALLBACK_CALLED_IN_MS).never()).sendResult(any());
     }
@@ -255,7 +289,7 @@
                 Binder.getCallingUid());
         mPackageMonitorCallbackHelper.notifyPackageMonitor(Intent.ACTION_PACKAGE_ADDED,
                 FAKE_PACKAGE_NAME, createFakeBundle(), new int[]{0} /* userIds */,
-                null /* instantUserIds */, broadcastAllowList, mHandler);
+                null /* instantUserIds */, broadcastAllowList, mHandler, null /* filterExtras */);
 
         verify(callback, after(WAIT_CALLBACK_CALLED_IN_MS).times(1)).sendResult(any());
     }
@@ -271,7 +305,7 @@
                 Binder.getCallingUid());
         mPackageMonitorCallbackHelper.notifyPackageMonitor(Intent.ACTION_PACKAGE_ADDED,
                 FAKE_PACKAGE_NAME, createFakeBundle(), new int[]{0} /* userIds */,
-                null /* instantUserIds */, broadcastAllowList, mHandler);
+                null /* instantUserIds */, broadcastAllowList, mHandler, null /* filterExtras */);
 
         verify(callback, after(WAIT_CALLBACK_CALLED_IN_MS).never()).sendResult(any());
     }
@@ -287,7 +321,7 @@
                 Process.SYSTEM_UID);
         mPackageMonitorCallbackHelper.notifyPackageMonitor(Intent.ACTION_PACKAGE_ADDED,
                 FAKE_PACKAGE_NAME, createFakeBundle(), new int[]{0} /* userIds */,
-                null /* instantUserIds */, broadcastAllowList, mHandler);
+                null /* instantUserIds */, broadcastAllowList, mHandler, null /* filterExtras */);
 
         verify(callback, after(WAIT_CALLBACK_CALLED_IN_MS).times(1)).sendResult(any());
     }
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java
index d2e83e9..9eeb4f3 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java
@@ -271,6 +271,7 @@
                 .thenReturn(true);
         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(false);
         when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+        when(mContext.getSystemService(Context.FACE_SERVICE)).thenReturn(null);
 
         mAuthenticationStatsCollector.authenticate(USER_ID_1, false /* authenticated */);
 
diff --git a/services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java
index fd1abff..d850c73 100644
--- a/services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java
@@ -53,6 +53,12 @@
     }
 
     @Test
+    public void getStoredProviders_nullValue_success() {
+        Set<String> providers = CredentialManagerService.getStoredProviders(null, null);
+        assertThat(providers.size()).isEqualTo(0);
+    }
+
+    @Test
     public void getStoredProviders_success() {
         Set<String> providers =
                 CredentialManagerService.getStoredProviders(
diff --git a/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
index 21b8a94..dc1d2c5 100644
--- a/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
@@ -16,26 +16,23 @@
 
 package com.android.server.os;
 
+import android.app.admin.flags.Flags;
+import static android.app.admin.flags.Flags.onboardingBugreportV2Enabled;
+
 import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
 
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertThrows;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.when;
 
-import android.app.admin.DevicePolicyManager;
-import android.app.admin.flags.Flags;
 import android.app.role.RoleManager;
 import android.content.Context;
 import android.os.Binder;
 import android.os.BugreportManager.BugreportCallback;
-import android.os.BugreportParams;
 import android.os.IBinder;
 import android.os.IDumpstateListener;
 import android.os.Process;
 import android.os.RemoteException;
-import android.os.UserManager;
 import android.platform.test.annotations.RequiresFlagsEnabled;
 import android.platform.test.flag.junit.CheckFlagsRule;
 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
@@ -51,8 +48,6 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
 
 import java.io.FileDescriptor;
 import java.util.concurrent.CompletableFuture;
@@ -71,11 +66,6 @@
     private BugreportManagerServiceImpl mService;
     private BugreportManagerServiceImpl.BugreportFileManager mBugreportFileManager;
 
-    @Mock
-    private UserManager mMockUserManager;
-    @Mock
-    private DevicePolicyManager mMockDevicePolicyManager;
-
     private int mCallingUid = 1234;
     private String mCallingPackage  = "test.package";
     private AtomicFile mMappingFile;
@@ -85,17 +75,14 @@
 
     @Before
     public void setUp() {
-        MockitoAnnotations.initMocks(this);
         mContext = InstrumentationRegistry.getInstrumentation().getContext();
         mMappingFile = new AtomicFile(mContext.getFilesDir(), "bugreport-mapping.xml");
         ArraySet<String> mAllowlistedPackages = new ArraySet<>();
         mAllowlistedPackages.add(mContext.getPackageName());
         mService = new BugreportManagerServiceImpl(
-                new TestInjector(mContext, mAllowlistedPackages, mMappingFile,
-                        mMockUserManager, mMockDevicePolicyManager));
+                new BugreportManagerServiceImpl.Injector(mContext, mAllowlistedPackages,
+                        mMappingFile));
         mBugreportFileManager = new BugreportManagerServiceImpl.BugreportFileManager(mMappingFile);
-        // The calling user is an admin user by default.
-        when(mMockUserManager.isUserAdmin(anyInt())).thenReturn(true);
     }
 
     @After
@@ -178,36 +165,6 @@
     }
 
     @Test
-    public void testStartBugreport_throwsForNonAdminUser() throws Exception {
-        when(mMockUserManager.isUserAdmin(anyInt())).thenReturn(false);
-
-        Exception thrown = assertThrows(Exception.class,
-                () -> mService.startBugreport(mCallingUid, mContext.getPackageName(),
-                        new FileDescriptor(), /* screenshotFd= */ null,
-                        BugreportParams.BUGREPORT_MODE_FULL,
-                        /* flags= */ 0, new Listener(new CountDownLatch(1)),
-                        /* isScreenshotRequested= */ false));
-
-        assertThat(thrown.getMessage()).contains("not an admin user");
-    }
-
-    @Test
-    public void testStartBugreport_throwsForNotAffiliatedUser() throws Exception {
-        when(mMockUserManager.isUserAdmin(anyInt())).thenReturn(false);
-        when(mMockDevicePolicyManager.getDeviceOwnerUserId()).thenReturn(-1);
-        when(mMockDevicePolicyManager.isAffiliatedUser(anyInt())).thenReturn(false);
-
-        Exception thrown = assertThrows(Exception.class,
-                () -> mService.startBugreport(mCallingUid, mContext.getPackageName(),
-                        new FileDescriptor(), /* screenshotFd= */ null,
-                        BugreportParams.BUGREPORT_MODE_REMOTE,
-                        /* flags= */ 0, new Listener(new CountDownLatch(1)),
-                        /* isScreenshotRequested= */ false));
-
-        assertThat(thrown.getMessage()).contains("not affiliated to the device owner");
-    }
-
-    @Test
     public void testRetrieveBugreportWithoutFilesForCaller() throws Exception {
         CountDownLatch latch = new CountDownLatch(1);
         Listener listener = new Listener(latch);
@@ -250,8 +207,7 @@
 
     private void clearAllowlist() {
         mService = new BugreportManagerServiceImpl(
-                new TestInjector(mContext, new ArraySet<>(), mMappingFile,
-                        mMockUserManager, mMockDevicePolicyManager));
+                new BugreportManagerServiceImpl.Injector(mContext, new ArraySet<>(), mMappingFile));
     }
 
     private static class Listener implements IDumpstateListener {
@@ -302,27 +258,4 @@
             complete(successful);
         }
     }
-
-    private static class TestInjector extends BugreportManagerServiceImpl.Injector {
-
-        private final UserManager mUserManager;
-        private final DevicePolicyManager mDevicePolicyManager;
-
-        TestInjector(Context context, ArraySet<String> allowlistedPackages, AtomicFile mappingFile,
-                UserManager um, DevicePolicyManager dpm) {
-            super(context, allowlistedPackages, mappingFile);
-            mUserManager = um;
-            mDevicePolicyManager = dpm;
-        }
-
-        @Override
-        public UserManager getUserManager() {
-            return mUserManager;
-        }
-
-        @Override
-        public DevicePolicyManager getDevicePolicyManager() {
-            return mDevicePolicyManager;
-        }
-    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 718c598..e88a00b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -161,6 +161,7 @@
 
 import com.android.internal.R;
 import com.android.server.wm.ActivityRecord.State;
+import com.android.window.flags.Flags;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -320,7 +321,7 @@
     }
 
     private void ensureActivityConfiguration(ActivityRecord activity) {
-        activity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
+        activity.ensureActivityConfiguration();
     }
 
     @Test
@@ -718,7 +719,7 @@
 
         // Clear size compat.
         activity.clearSizeCompatMode();
-        activity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
+        activity.ensureActivityConfiguration();
         mDisplayContent.sendNewConfiguration();
 
         // Relaunching the app should still respect the orientation request.
@@ -819,8 +820,7 @@
 
             task.onConfigurationChanged(newConfig);
 
-            activity.ensureActivityConfiguration(0 /* globalChanges */,
-                    false /* preserveWindow */, true /* ignoreVisibility */);
+            activity.ensureActivityConfiguration(true /* ignoreVisibility */);
 
             final ActivityConfigurationChangeItem expected =
                     ActivityConfigurationChangeItem.obtain(activity.token,
@@ -1563,8 +1563,7 @@
         topActivity.nowVisible = true;
         topActivity.setState(RESUMED, "true");
         doCallRealMethod().when(mRootWindowContainer).ensureActivitiesVisible(
-                any() /* starting */, anyInt() /* configChanges */,
-                anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */);
+                any() /* starting */, anyBoolean() /* notifyClients */);
         topActivity.setShowWhenLocked(true);
 
         // Verify the stack-top activity is occluded keyguard.
@@ -1624,7 +1623,6 @@
         secondActivity.finishing = true;
         secondActivity.completeFinishing("test");
         verify(secondActivity.mDisplayContent).ensureActivitiesVisible(null /* starting */,
-                0 /* configChanges */ , false /* preserveWindows */,
                 true /* notifyClients */);
 
         // Finish the first activity
@@ -1632,7 +1630,6 @@
         firstActivity.setVisibleRequested(true);
         firstActivity.completeFinishing("test");
         verify(firstActivity.mDisplayContent, times(2)).ensureActivitiesVisible(null /* starting */,
-                0 /* configChanges */ , false /* preserveWindows */,
                 true /* notifyClients */);
 
         // Remove the translucent activity and clear invocations for next test
@@ -1960,6 +1957,7 @@
         display.continueUpdateOrientationForDiffOrienLaunchingApp();
         assertTrue(display.isFixedRotationLaunchingApp(activity));
 
+        activity.stopFreezingScreen(true /* unfreezeSurfaceNow */, true /* force */);
         // Simulate the rotation has been updated to previous one, e.g. sensor updates before the
         // remote rotation is completed.
         doReturn(originalRotation).when(displayRotation).rotationForOrientation(
@@ -1970,14 +1968,12 @@
         activity.finishFixedRotationTransform();
         final ScreenRotationAnimation rotationAnim = display.getRotationAnimation();
         assertNotNull(rotationAnim);
-        rotationAnim.setRotation(display.getPendingTransaction(), originalRotation);
 
         // Because the display doesn't rotate, the rotated activity needs to cancel the fixed
         // rotation. There should be a rotation animation to cover the change of activity.
         verify(activity).onCancelFixedRotationTransform(rotatedInfo.rotation);
         assertTrue(activity.isFreezingScreen());
         assertFalse(displayRotation.isRotatingSeamlessly());
-        assertTrue(rotationAnim.isRotating());
 
         // Simulate the remote rotation has completed and the configuration doesn't change, then
         // the rotated activity should also be restored by clearing the transform.
@@ -3370,7 +3366,7 @@
         // to client if the app didn't request IME visible.
         assertFalse(app2.mActivityRecord.mImeInsetsFrozenUntilStartInput);
 
-        if (mWm.mFlags.mWindowStateResizeItemFlag) {
+        if (Flags.bundleClientTransactionFlag()) {
             verify(app2.getProcess()).scheduleClientTransactionItem(
                     isA(WindowStateResizeItem.class));
         } else {
@@ -3697,7 +3693,7 @@
         doReturn(false).when(activity).showToCurrentUser();
         spyOn(taskFragment);
         doReturn(false).when(taskFragment).shouldBeVisible(any());
-        display.ensureActivitiesVisible(null, 0, false, false);
+        display.ensureActivitiesVisible(null /* starting */, false /* notifyClients */);
         assertFalse(activity.isVisibleRequested());
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/ClientLifecycleManagerTests.java b/services/tests/wmtests/src/com/android/server/wm/ClientLifecycleManagerTests.java
index c757457..09f677e7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ClientLifecycleManagerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ClientLifecycleManagerTests.java
@@ -172,7 +172,7 @@
     @Test
     public void testScheduleTransactionItemUnlocked() throws RemoteException {
         // Use non binder client to get non-recycled ClientTransaction.
-        mLifecycleManager.scheduleTransactionItemUnlocked(mNonBinderClient, mTransactionItem);
+        mLifecycleManager.scheduleTransactionItemNow(mNonBinderClient, mTransactionItem);
 
         // Dispatch immediately.
         assertTrue(mLifecycleManager.mPendingTransactions.isEmpty());
@@ -217,6 +217,8 @@
 
     @Test
     public void testDispatchPendingTransactions() throws RemoteException {
+        mSetFlagsRule.enableFlags(FLAG_BUNDLE_CLIENT_TRANSACTION_FLAG);
+
         mLifecycleManager.mPendingTransactions.put(mClientBinder, mTransaction);
 
         mLifecycleManager.dispatchPendingTransactions();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index dfe79bf..6497ee9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -75,7 +75,6 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.same;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP;
@@ -490,7 +489,7 @@
         newOverrideConfig.fontScale += 0.3;
 
         defaultDisplay.updateDisplayOverrideConfigurationLocked(newOverrideConfig,
-                null /* starting */, false /* deferResume */, null /* result */);
+                null /* starting */, false /* deferResume */);
 
         // Check that global configuration is updated, as we've updated default display's config.
         Configuration globalConfig = mWm.mRoot.getConfiguration();
@@ -499,7 +498,7 @@
 
         // Return back to original values.
         defaultDisplay.updateDisplayOverrideConfigurationLocked(currentConfig,
-                null /* starting */, false /* deferResume */, null /* result */);
+                null /* starting */, false /* deferResume */);
         globalConfig = mWm.mRoot.getConfiguration();
         assertEquals(currentConfig.densityDpi, globalConfig.densityDpi);
         assertEquals(currentConfig.fontScale, globalConfig.fontScale, 0.1 /* delta */);
@@ -1176,7 +1175,7 @@
         activity.setRequestedOrientation(newOrientation);
 
         verify(dc, never()).updateDisplayOverrideConfigurationLocked(any(), eq(activity),
-                anyBoolean(), same(null));
+                anyBoolean());
         assertEquals(ROTATION_180, dc.getRotation());
     }
 
@@ -2123,10 +2122,8 @@
         // Once transition starts, rotation is applied and transition shows DC rotating.
         testPlayer.startTransition();
         waitUntilHandlersIdle();
-        verify(activity1).ensureActivityConfiguration(anyInt(), anyBoolean(), anyBoolean(),
-                anyBoolean());
-        verify(activity2).ensureActivityConfiguration(anyInt(), anyBoolean(), anyBoolean(),
-                anyBoolean());
+        verify(activity1).ensureActivityConfiguration(anyBoolean(), anyBoolean());
+        verify(activity2).ensureActivityConfiguration(anyBoolean(), anyBoolean());
         assertNotEquals(origRot, dc.getConfiguration().windowConfiguration.getRotation());
         assertNotNull(testPlayer.mLastReady);
         assertTrue(testPlayer.mController.isPlaying());
@@ -2248,11 +2245,11 @@
             // The assertion will fail if DisplayArea#ensureActivitiesVisible is called twice.
             assertFalse(called[0]);
             called[0] = true;
-            mDisplayContent.ensureActivitiesVisible(null, 0, false, false);
+            mDisplayContent.ensureActivitiesVisible(null, false);
             return null;
-        }).when(mockTda).ensureActivitiesVisible(any(), anyInt(), anyBoolean(), anyBoolean());
+        }).when(mockTda).ensureActivitiesVisible(any(), anyBoolean());
 
-        mDisplayContent.ensureActivitiesVisible(null, 0, false, false);
+        mDisplayContent.ensureActivitiesVisible(null, false);
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index 8de45b0..32b3558 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -106,8 +106,7 @@
         topActivity.getRootTask().moveToFront("testRecentsActivityVisiblility");
 
         doCallRealMethod().when(mRootWindowContainer).ensureActivitiesVisible(
-                any() /* starting */, anyInt() /* configChanges */,
-                anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */);
+                any() /* starting */, anyBoolean() /* notifyClients */);
 
         RecentsAnimationCallbacks recentsAnimation = startRecentsActivity(
                 mRecentsComponent, true /* getRecentsAnimation */);
@@ -178,8 +177,7 @@
         mAtm.startRecentsActivity(recentsIntent, 0 /* eventTime */,
                 null /* recentsAnimationRunner */);
 
-        verify(recentsActivity).ensureActivityConfiguration(anyInt() /* globalChanges */,
-                anyBoolean() /* preserveWindow */, eq(true) /* ignoreVisibility */);
+        verify(recentsActivity).ensureActivityConfiguration(eq(true) /* ignoreVisibility */);
         assertThat(mSupervisor.mStoppingActivities).contains(recentsActivity);
     }
 
@@ -199,8 +197,7 @@
                 "testRestartRecentsActivity");
 
         doCallRealMethod().when(mRootWindowContainer).ensureActivitiesVisible(
-                any() /* starting */, anyInt() /* configChanges */,
-                anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */);
+                any() /* starting */, anyBoolean() /* notifyClients */);
         doReturn(app).when(mAtm).getProcessController(eq(recentActivity.processName), anyInt());
         doNothing().when(mClientLifecycleManager).scheduleTransaction(any());
 
@@ -354,8 +351,7 @@
 
         doReturn(TEST_USER_ID).when(mAtm).getCurrentUserId();
         doCallRealMethod().when(mRootWindowContainer).ensureActivitiesVisible(
-                any() /* starting */, anyInt() /* configChanges */,
-                anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */);
+                any() /* starting */, anyBoolean() /* notifyClients */);
 
         startRecentsActivity(otherUserHomeActivity.getTask().getBaseIntent().getComponent(),
                 true);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
index 89cd726..b5883b1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
@@ -823,8 +823,7 @@
                 .build();
 
         doReturn(false).when(secondActivity).occludesParent();
-        homeRootTask.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
-                false /* preserveWindows */);
+        homeRootTask.ensureActivitiesVisible(null /* starting */);
 
         assertTrue(firstActivity.shouldBeVisible());
     }
@@ -1419,8 +1418,7 @@
 
         // Any common path that updates activity visibility should clear the unknown visibility
         // records that are no longer visible according to hierarchy.
-        task.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
-                false /* preserveWindows */);
+        task.ensureActivitiesVisible(null /* starting */);
         // Assume the top activity relayouted, just remove it directly.
         unknownAppVisibilityController.appRemovedOrHidden(activities[1]);
         // All unresolved records should be removed.
@@ -1441,8 +1439,7 @@
         doNothing().when(mSupervisor).startSpecificActivity(any(), anyBoolean(),
                 anyBoolean());
 
-        task.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
-                false /* preserveWindows */);
+        task.ensureActivitiesVisible(null /* starting */);
         verify(mSupervisor).startSpecificActivity(any(), eq(false) /* andResume */,
                 anyBoolean());
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index c3102e0..5518c60 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -947,7 +947,7 @@
 
         // Recompute the natural configuration in the new display.
         mActivity.clearSizeCompatMode();
-        mActivity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
+        mActivity.ensureActivityConfiguration();
         // Because the display cannot rotate, the portrait activity will fit the short side of
         // display with keeping portrait bounds [200, 0 - 700, 1000] in center.
         assertEquals(newDisplayBounds.height(), currentBounds.height());
@@ -4858,7 +4858,7 @@
         }
         // Make sure to use the provided configuration to construct the size compat fields.
         activity.clearSizeCompatMode();
-        activity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
+        activity.ensureActivityConfiguration();
         // Make sure the display configuration reflects the change of activity.
         if (activity.mDisplayContent.updateOrientation()) {
             activity.mDisplayContent.sendNewConfiguration();
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 8cd9ff3..90493d4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -375,8 +375,7 @@
         // Always keep things awake.
         doReturn(true).when(mWmService.mRoot).hasAwakeDisplay();
         // Called when moving activity to pinned stack.
-        doNothing().when(mWmService.mRoot).ensureActivitiesVisible(any(),
-                anyInt(), anyBoolean(), anyBoolean());
+        doNothing().when(mWmService.mRoot).ensureActivitiesVisible(any(), anyBoolean());
         spyOn(mWmService.mDisplayWindowSettings);
         spyOn(mWmService.mDisplayWindowSettingsProvider);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
index ec068be..00e22fd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
@@ -269,8 +269,7 @@
         mTaskFragment.getTask().addChild(activityBelow, 0);
 
         // Ensure the activity below is visible
-        mTaskFragment.getTask().ensureActivitiesVisible(null /* starting */, 0 /* configChanges */,
-                false /* preserveWindows */);
+        mTaskFragment.getTask().ensureActivitiesVisible(null /* starting */);
         assertEquals(true, activityBelow.isVisibleRequested());
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index da7612b..45e1e95 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -339,16 +339,14 @@
         // Check visibility of occluded tasks
         doReturn(false).when(leafTask1).shouldBeVisible(any());
         doReturn(true).when(leafTask2).shouldBeVisible(any());
-        rootTask.ensureActivitiesVisible(
-                null /* starting */ , 0 /* configChanges */, false /* preserveWindows */);
+        rootTask.ensureActivitiesVisible(null /* starting */);
         assertFalse(activity1.isVisible());
         assertTrue(activity2.isVisible());
 
         // Check visibility of not occluded tasks
         doReturn(true).when(leafTask1).shouldBeVisible(any());
         doReturn(true).when(leafTask2).shouldBeVisible(any());
-        rootTask.ensureActivitiesVisible(
-                null /* starting */ , 0 /* configChanges */, false /* preserveWindows */);
+        rootTask.ensureActivitiesVisible(null /* starting */);
         assertTrue(activity1.isVisible());
         assertTrue(activity2.isVisible());
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 71447e7..fddd771 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -1495,8 +1495,7 @@
         verify(taskSnapshotController, times(0)).recordSnapshot(eq(task1));
 
         enteringAnimReports.clear();
-        doCallRealMethod().when(mWm.mRoot).ensureActivitiesVisible(any(),
-                anyInt(), anyBoolean(), anyBoolean());
+        doCallRealMethod().when(mWm.mRoot).ensureActivitiesVisible(any(), anyBoolean());
         final boolean[] wasInFinishingTransition = { false };
         controller.registerLegacyListener(new WindowManagerInternal.AppTransitionListener() {
             @Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index e31ee11..400e4b6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -38,7 +38,6 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.clearInvocations;
@@ -306,10 +305,12 @@
 
     @Test
     public void testCachedStateConfigurationChange() throws RemoteException {
-        doNothing().when(mClientLifecycleManager).scheduleTransactionItemUnlocked(any(), any());
+        doNothing().when(mClientLifecycleManager).scheduleTransactionItemNow(any(), any());
         final IApplicationThread thread = mWpc.getThread();
         final Configuration newConfig = new Configuration(mWpc.getConfiguration());
         newConfig.densityDpi += 100;
+        mWpc.mWindowSession = getTestSession();
+        mWpc.mWindowSession.onWindowAdded(mock(WindowState.class));
         // Non-cached state will send the change directly.
         mWpc.setReportedProcState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
         clearInvocations(mClientLifecycleManager);
@@ -322,13 +323,13 @@
         newConfig.densityDpi += 100;
         mWpc.onConfigurationChanged(newConfig);
         verify(mClientLifecycleManager, never()).scheduleTransactionItem(eq(thread), any());
-        verify(mClientLifecycleManager, never()).scheduleTransactionItemUnlocked(eq(thread), any());
+        verify(mClientLifecycleManager, never()).scheduleTransactionItemNow(eq(thread), any());
 
         // Cached -> non-cached will send the previous deferred config immediately.
         mWpc.setReportedProcState(ActivityManager.PROCESS_STATE_RECEIVER);
         final ArgumentCaptor<ConfigurationChangeItem> captor =
                 ArgumentCaptor.forClass(ConfigurationChangeItem.class);
-        verify(mClientLifecycleManager).scheduleTransactionItemUnlocked(
+        verify(mClientLifecycleManager).scheduleTransactionItemNow(
                 eq(thread), captor.capture());
         final ClientTransactionHandler client = mock(ClientTransactionHandler.class);
         captor.getValue().preExecute(client);
@@ -432,7 +433,7 @@
         mWpc.updateAppSpecificSettingsForAllActivitiesInPackage(DEFAULT_COMPONENT_PACKAGE_NAME,
                 Configuration.UI_MODE_NIGHT_YES, LocaleList.forLanguageTags("en-XA"),
                 GRAMMATICAL_GENDER_NOT_SPECIFIED);
-        verify(activity).ensureActivityConfiguration(anyInt(), anyBoolean());
+        verify(activity).ensureActivityConfiguration();
     }
 
     @Test
@@ -443,7 +444,7 @@
                 Configuration.UI_MODE_NIGHT_YES, LocaleList.forLanguageTags("en-XA"),
                 GRAMMATICAL_GENDER_NOT_SPECIFIED);
         verify(activity, never()).applyAppSpecificConfig(anyInt(), any(), anyInt());
-        verify(activity, never()).ensureActivityConfiguration(anyInt(), anyBoolean());
+        verify(activity, never()).ensureActivityConfiguration();
     }
 
     @Test