Merge "Log lots more about notification inflation" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index fd92979b..16170d9 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -23,6 +23,7 @@
         ":camera_platform_flags_core_java_lib{.generated_srcjars}",
         ":com.android.window.flags.window-aconfig-java{.generated_srcjars}",
         ":com.android.text.flags-aconfig-java{.generated_srcjars}",
+        ":android.companion.virtual.flags-aconfig-java{.generated_srcjars}",
     ],
 }
 
@@ -80,6 +81,14 @@
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
 
+java_aconfig_library {
+    name: "android.security.flags-aconfig-java-host",
+    aconfig_declarations: "android.security.flags-aconfig",
+    host_supported: true,
+    test: true,
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
 // OS
 aconfig_declarations {
     name: "android.os.flags-aconfig",
@@ -92,3 +101,16 @@
     aconfig_declarations: "android.os.flags-aconfig",
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
+
+// VirtualDeviceManager
+java_aconfig_library {
+    name: "android.companion.virtual.flags-aconfig-java",
+    aconfig_declarations: "android.companion.virtual.flags-aconfig",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
+aconfig_declarations {
+    name: "android.companion.virtual.flags-aconfig",
+    package: "android.companion.virtual.flags",
+    srcs: ["core/java/android/companion/virtual/*.aconfig"],
+}
diff --git a/boot/preloaded-classes b/boot/preloaded-classes
index 2a9375c..19d6f04 100644
--- a/boot/preloaded-classes
+++ b/boot/preloaded-classes
@@ -12682,7 +12682,6 @@
 com.android.internal.util.LatencyTracker$Action
 com.android.internal.util.LatencyTracker$ActionProperties
 com.android.internal.util.LatencyTracker$FrameworkStatsLogEvent
-com.android.internal.util.LatencyTracker$SLatencyTrackerHolder
 com.android.internal.util.LatencyTracker$Session$$ExternalSyntheticLambda0
 com.android.internal.util.LatencyTracker$Session
 com.android.internal.util.LatencyTracker
diff --git a/cmds/idmap2/libidmap2/XmlParser.cpp b/cmds/idmap2/libidmap2/XmlParser.cpp
index 1d78460..7807155 100644
--- a/cmds/idmap2/libidmap2/XmlParser.cpp
+++ b/cmds/idmap2/libidmap2/XmlParser.cpp
@@ -130,11 +130,14 @@
 }
 
 Result<Res_value> XmlParser::Node::GetAttributeValue(const std::string& name) const {
+  String16 name16;
   return FindAttribute(parser_, name, [&](size_t index) -> bool {
-    size_t len;
-    const String16 key16(parser_.getAttributeName(index, &len));
-    std::string key = String8(key16).c_str();
-    return key == name;
+    if (name16.empty()) {
+        name16 = String16(name.c_str(), name.size());
+    }
+    size_t key_len;
+    const auto key16 = parser_.getAttributeName(index, &key_len);
+    return key16 && name16.size() == key_len && name16 == key16;
   });
 }
 
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 214b12c..0351a00 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -12713,7 +12713,6 @@
 com.android.internal.util.LatencyTracker$Action
 com.android.internal.util.LatencyTracker$ActionProperties
 com.android.internal.util.LatencyTracker$FrameworkStatsLogEvent
-com.android.internal.util.LatencyTracker$SLatencyTrackerHolder
 com.android.internal.util.LatencyTracker$Session$$ExternalSyntheticLambda0
 com.android.internal.util.LatencyTracker$Session
 com.android.internal.util.LatencyTracker
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index adbd06c..adf1da9 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -17321,7 +17321,6 @@
     field public static final int NT_RADIO_TECHNOLOGY_NR_NTN = 2; // 0x2
     field public static final int NT_RADIO_TECHNOLOGY_PROPRIETARY = 4; // 0x4
     field public static final int NT_RADIO_TECHNOLOGY_UNKNOWN = 0; // 0x0
-    field public static final int SATELLITE_ACCESS_BARRED = 16; // 0x10
     field public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_IDLE = 0; // 0x0
     field public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_FAILED = 7; // 0x7
     field public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_RECEIVE_NONE = 6; // 0x6
@@ -17331,13 +17330,6 @@
     field public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_FAILED = 3; // 0x3
     field public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_SEND_SUCCESS = 2; // 0x2
     field public static final int SATELLITE_DATAGRAM_TRANSFER_STATE_UNKNOWN = -1; // 0xffffffff
-    field public static final int SATELLITE_ERROR = 1; // 0x1
-    field public static final int SATELLITE_ERROR_NONE = 0; // 0x0
-    field public static final int SATELLITE_INVALID_ARGUMENTS = 8; // 0x8
-    field public static final int SATELLITE_INVALID_MODEM_STATE = 7; // 0x7
-    field public static final int SATELLITE_INVALID_TELEPHONY_STATE = 6; // 0x6
-    field public static final int SATELLITE_MODEM_BUSY = 22; // 0x16
-    field public static final int SATELLITE_MODEM_ERROR = 4; // 0x4
     field public static final int SATELLITE_MODEM_STATE_DATAGRAM_RETRYING = 3; // 0x3
     field public static final int SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING = 2; // 0x2
     field public static final int SATELLITE_MODEM_STATE_IDLE = 0; // 0x0
@@ -17345,21 +17337,29 @@
     field public static final int SATELLITE_MODEM_STATE_OFF = 4; // 0x4
     field public static final int SATELLITE_MODEM_STATE_UNAVAILABLE = 5; // 0x5
     field public static final int SATELLITE_MODEM_STATE_UNKNOWN = -1; // 0xffffffff
-    field public static final int SATELLITE_NETWORK_ERROR = 5; // 0x5
-    field public static final int SATELLITE_NETWORK_TIMEOUT = 17; // 0x11
-    field public static final int SATELLITE_NOT_AUTHORIZED = 19; // 0x13
-    field public static final int SATELLITE_NOT_REACHABLE = 18; // 0x12
-    field public static final int SATELLITE_NOT_SUPPORTED = 20; // 0x14
-    field public static final int SATELLITE_NO_RESOURCES = 12; // 0xc
-    field public static final int SATELLITE_RADIO_NOT_AVAILABLE = 10; // 0xa
-    field public static final int SATELLITE_REQUEST_ABORTED = 15; // 0xf
-    field public static final int SATELLITE_REQUEST_FAILED = 9; // 0x9
-    field public static final int SATELLITE_REQUEST_IN_PROGRESS = 21; // 0x15
-    field public static final int SATELLITE_REQUEST_NOT_SUPPORTED = 11; // 0xb
-    field public static final int SATELLITE_SERVER_ERROR = 2; // 0x2
-    field public static final int SATELLITE_SERVICE_ERROR = 3; // 0x3
-    field public static final int SATELLITE_SERVICE_NOT_PROVISIONED = 13; // 0xd
-    field public static final int SATELLITE_SERVICE_PROVISION_IN_PROGRESS = 14; // 0xe
+    field public static final int SATELLITE_RESULT_ACCESS_BARRED = 16; // 0x10
+    field public static final int SATELLITE_RESULT_ERROR = 1; // 0x1
+    field public static final int SATELLITE_RESULT_INVALID_ARGUMENTS = 8; // 0x8
+    field public static final int SATELLITE_RESULT_INVALID_MODEM_STATE = 7; // 0x7
+    field public static final int SATELLITE_RESULT_INVALID_TELEPHONY_STATE = 6; // 0x6
+    field public static final int SATELLITE_RESULT_MODEM_BUSY = 22; // 0x16
+    field public static final int SATELLITE_RESULT_MODEM_ERROR = 4; // 0x4
+    field public static final int SATELLITE_RESULT_NETWORK_ERROR = 5; // 0x5
+    field public static final int SATELLITE_RESULT_NETWORK_TIMEOUT = 17; // 0x11
+    field public static final int SATELLITE_RESULT_NOT_AUTHORIZED = 19; // 0x13
+    field public static final int SATELLITE_RESULT_NOT_REACHABLE = 18; // 0x12
+    field public static final int SATELLITE_RESULT_NOT_SUPPORTED = 20; // 0x14
+    field public static final int SATELLITE_RESULT_NO_RESOURCES = 12; // 0xc
+    field public static final int SATELLITE_RESULT_RADIO_NOT_AVAILABLE = 10; // 0xa
+    field public static final int SATELLITE_RESULT_REQUEST_ABORTED = 15; // 0xf
+    field public static final int SATELLITE_RESULT_REQUEST_FAILED = 9; // 0x9
+    field public static final int SATELLITE_RESULT_REQUEST_IN_PROGRESS = 21; // 0x15
+    field public static final int SATELLITE_RESULT_REQUEST_NOT_SUPPORTED = 11; // 0xb
+    field public static final int SATELLITE_RESULT_SERVER_ERROR = 2; // 0x2
+    field public static final int SATELLITE_RESULT_SERVICE_ERROR = 3; // 0x3
+    field public static final int SATELLITE_RESULT_SERVICE_NOT_PROVISIONED = 13; // 0xd
+    field public static final int SATELLITE_RESULT_SERVICE_PROVISION_IN_PROGRESS = 14; // 0xe
+    field public static final int SATELLITE_RESULT_SUCCESS = 0; // 0x0
   }
 
   public static class SatelliteManager.SatelliteException extends java.lang.Exception {
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index 060a5c8..af41370 100644
--- a/core/java/android/companion/virtual/VirtualDeviceManager.java
+++ b/core/java/android/companion/virtual/VirtualDeviceManager.java
@@ -32,6 +32,7 @@
 import android.companion.AssociationInfo;
 import android.companion.virtual.audio.VirtualAudioDevice;
 import android.companion.virtual.audio.VirtualAudioDevice.AudioConfigurationChangeCallback;
+import android.companion.virtual.flags.Flags;
 import android.companion.virtual.sensor.VirtualSensor;
 import android.content.ComponentName;
 import android.content.Context;
@@ -173,6 +174,9 @@
             int associationId,
             @NonNull VirtualDeviceParams params) {
         Objects.requireNonNull(params, "params must not be null");
+        if (Flags.moreLogs()) {
+            Log.i(TAG, "Creating VirtualDevice");
+        }
         try {
             return new VirtualDevice(mService, mContext, associationId, params);
         } catch (RemoteException e) {
diff --git a/core/java/android/companion/virtual/flags.aconfig b/core/java/android/companion/virtual/flags.aconfig
new file mode 100644
index 0000000..39b99c6
--- /dev/null
+++ b/core/java/android/companion/virtual/flags.aconfig
@@ -0,0 +1,8 @@
+package: "android.companion.virtual.flags"
+
+flag {
+  name: "more_logs"
+  namespace: "virtual_devices"
+  description: "More logs to test flags with"
+  bug: "291725823"
+}
diff --git a/core/java/android/content/pm/ArchivedPackageParcel.aidl b/core/java/android/content/pm/ArchivedPackageParcel.aidl
new file mode 100644
index 0000000..b34b708
--- /dev/null
+++ b/core/java/android/content/pm/ArchivedPackageParcel.aidl
@@ -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.
+ */
+
+package android.content.pm;
+
+import android.content.pm.SigningDetails;
+
+/**
+ * Contains fields required for archived package installation,
+ * i.e. installation without an APK.
+ * @hide
+ */
+parcelable ArchivedPackageParcel {
+    String packageName;
+    SigningDetails signingDetails;
+    int versionCode;
+    int versionCodeMajor;
+    int targetSdkVersion;
+    boolean clearUserDataAllowed;
+    boolean backupAllowed;
+    boolean defaultToDeviceProtectedStorage;
+    boolean requestLegacyExternalStorage;
+    boolean userDataFragile;
+    boolean clearUserDataOnFailedRestoreAllowed;
+}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 4ed4dd3..916c249 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -22,6 +22,7 @@
 import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.ArchivedPackageParcel;
 import android.content.pm.ChangedPackages;
 import android.content.pm.InstantAppInfo;
 import android.content.pm.FeatureInfo;
@@ -833,4 +834,6 @@
     void registerPackageMonitorCallback(IRemoteCallback callback, int userId);
 
     void unregisterPackageMonitorCallback(IRemoteCallback callback);
+
+    ArchivedPackageParcel getArchivedPackage(in String apkPath);
 }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index d2173a6..c384389 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1682,6 +1682,13 @@
     public static final int INSTALL_FROM_MANAGED_USER_OR_PROFILE = 1 << 26;
 
     /**
+     * Flag parameter for {@link PackageInstaller.SessionParams} to indicate that this
+     * session is for archived package installation.
+     * @hide
+     */
+    public static final int INSTALL_ARCHIVED = 1 << 27;
+
+    /**
      * Flag parameter for {@link #installPackage} to force a non-staged update of an APEX. This is
      * a development-only feature and should not be used on end user devices.
      *
diff --git a/core/java/android/content/pm/SigningDetails.aidl b/core/java/android/content/pm/SigningDetails.aidl
new file mode 100644
index 0000000..95f3ca7
--- /dev/null
+++ b/core/java/android/content/pm/SigningDetails.aidl
@@ -0,0 +1,18 @@
+/*
+ * 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.content.pm;
+
+parcelable SigningDetails;
diff --git a/core/java/android/content/pm/parsing/ApkLite.java b/core/java/android/content/pm/parsing/ApkLite.java
index 269bec2..71cfd1b 100644
--- a/core/java/android/content/pm/parsing/ApkLite.java
+++ b/core/java/android/content/pm/parsing/ApkLite.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.pm.ArchivedPackageParcel;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.SigningDetails;
@@ -138,6 +139,39 @@
      */
     private final boolean mIsSdkLibrary;
 
+    /**
+     * Indicates whether this application's data will be cleared on a failed restore.
+     */
+    private final boolean mClearUserDataAllowed;
+
+    /**
+     *  Set to <code>false</code> if the application does not wish to permit any OS-driven
+     *  backups of its data; <code>true</code> otherwise.
+     */
+    private final boolean mBackupAllowed;
+
+    /**
+     * When set, the default data storage directory for this app is pointed at
+     * the device-protected location.
+     */
+    private final boolean mDefaultToDeviceProtectedStorage;
+
+    /**
+     * If {@code true} this app requests full external storage access.
+     */
+    private final boolean mRequestLegacyExternalStorage;
+
+    /**
+     * Indicates whether this application has declared its user data as fragile, causing the
+     * system to prompt the user on whether to keep the user data on uninstall.
+     */
+    private final boolean mUserDataFragile;
+
+    /**
+     * Indicates whether this application's data will be cleared on a failed restore.
+     */
+    private final boolean mClearUserDataOnFailedRestoreAllowed;
+
     public ApkLite(String path, String packageName, String splitName, boolean isFeatureSplit,
             String configForSplit, String usesSplitName, boolean isSplitRequired, int versionCode,
             int versionCodeMajor, int revisionCode, int installLocation,
@@ -148,7 +182,10 @@
             String requiredSystemPropertyName, String requiredSystemPropertyValue,
             int minSdkVersion, int targetSdkVersion, int rollbackDataPolicy,
             Set<String> requiredSplitTypes, Set<String> splitTypes,
-            boolean hasDeviceAdminReceiver, boolean isSdkLibrary) {
+            boolean hasDeviceAdminReceiver, boolean isSdkLibrary, boolean clearUserDataAllowed,
+            boolean backupAllowed, boolean defaultToDeviceProtectedStorage,
+            boolean requestLegacyExternalStorage, boolean userDataFragile,
+            boolean clearUserDataOnFailedRestoreAllowed) {
         mPath = path;
         mPackageName = packageName;
         mSplitName = splitName;
@@ -182,6 +219,54 @@
         mRollbackDataPolicy = rollbackDataPolicy;
         mHasDeviceAdminReceiver = hasDeviceAdminReceiver;
         mIsSdkLibrary = isSdkLibrary;
+        mClearUserDataAllowed = clearUserDataAllowed;
+        mBackupAllowed = backupAllowed;
+        mDefaultToDeviceProtectedStorage = defaultToDeviceProtectedStorage;
+        mRequestLegacyExternalStorage = requestLegacyExternalStorage;
+        mUserDataFragile = userDataFragile;
+        mClearUserDataOnFailedRestoreAllowed = clearUserDataOnFailedRestoreAllowed;
+    }
+
+    public ApkLite(String path, ArchivedPackageParcel archivedPackage) {
+        mPath = path;
+        mPackageName = archivedPackage.packageName;
+        mSplitName = null; // base.apk
+        mSplitTypes = null;
+        mFeatureSplit = false;
+        mConfigForSplit = null;
+        mUsesSplitName = null;
+        mRequiredSplitTypes = null;
+        mSplitRequired = hasAnyRequiredSplitTypes();
+        mVersionCode = archivedPackage.versionCode;
+        mVersionCodeMajor = archivedPackage.versionCodeMajor;
+        mRevisionCode = 0;
+        mInstallLocation = PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
+        mVerifiers = new VerifierInfo[]{};
+        mSigningDetails = archivedPackage.signingDetails;
+        mCoreApp = false;
+        mDebuggable = false;
+        mProfileableByShell = false;
+        mMultiArch = false;
+        mUse32bitAbi = false;
+        mUseEmbeddedDex = false;
+        mExtractNativeLibs = false;
+        mIsolatedSplits = false;
+        mTargetPackageName = null;
+        mOverlayIsStatic = false;
+        mOverlayPriority = 0;
+        mRequiredSystemPropertyName = null;
+        mRequiredSystemPropertyValue = null;
+        mMinSdkVersion = ApkLiteParseUtils.DEFAULT_MIN_SDK_VERSION;
+        mTargetSdkVersion = archivedPackage.targetSdkVersion;
+        mRollbackDataPolicy = 0;
+        mHasDeviceAdminReceiver = false;
+        mIsSdkLibrary = false;
+        mClearUserDataAllowed = archivedPackage.clearUserDataAllowed;
+        mBackupAllowed = archivedPackage.backupAllowed;
+        mDefaultToDeviceProtectedStorage = archivedPackage.defaultToDeviceProtectedStorage;
+        mRequestLegacyExternalStorage = archivedPackage.requestLegacyExternalStorage;
+        mUserDataFragile = archivedPackage.userDataFragile;
+        mClearUserDataOnFailedRestoreAllowed = archivedPackage.clearUserDataOnFailedRestoreAllowed;
     }
 
     /**
@@ -474,6 +559,9 @@
         return mRollbackDataPolicy;
     }
 
+    /**
+     * Indicates if this app contains a {@link android.app.admin.DeviceAdminReceiver}.
+     */
     @DataClass.Generated.Member
     public boolean isHasDeviceAdminReceiver() {
         return mHasDeviceAdminReceiver;
@@ -487,11 +575,62 @@
         return mIsSdkLibrary;
     }
 
+    /**
+     * Indicates whether this application's data will be cleared on a failed restore.
+     */
+    @DataClass.Generated.Member
+    public boolean isClearUserDataAllowed() {
+        return mClearUserDataAllowed;
+    }
+
+    /**
+     *  Set to <code>false</code> if the application does not wish to permit any OS-driven
+     *  backups of its data; <code>true</code> otherwise.
+     */
+    @DataClass.Generated.Member
+    public boolean isBackupAllowed() {
+        return mBackupAllowed;
+    }
+
+    /**
+     * When set, the default data storage directory for this app is pointed at
+     * the device-protected location.
+     */
+    @DataClass.Generated.Member
+    public boolean isDefaultToDeviceProtectedStorage() {
+        return mDefaultToDeviceProtectedStorage;
+    }
+
+    /**
+     * If {@code true} this app requests full external storage access.
+     */
+    @DataClass.Generated.Member
+    public boolean isRequestLegacyExternalStorage() {
+        return mRequestLegacyExternalStorage;
+    }
+
+    /**
+     * Indicates whether this application has declared its user data as fragile, causing the
+     * system to prompt the user on whether to keep the user data on uninstall.
+     */
+    @DataClass.Generated.Member
+    public boolean isUserDataFragile() {
+        return mUserDataFragile;
+    }
+
+    /**
+     * Indicates whether this application's data will be cleared on a failed restore.
+     */
+    @DataClass.Generated.Member
+    public boolean isClearUserDataOnFailedRestoreAllowed() {
+        return mClearUserDataOnFailedRestoreAllowed;
+    }
+
     @DataClass.Generated(
-            time = 1643063342990L,
+            time = 1693422809896L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/content/pm/parsing/ApkLite.java",
-            inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.Nullable java.lang.String mUsesSplitName\nprivate final @android.annotation.Nullable java.lang.String mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mSplitTypes\nprivate final  int mVersionCodeMajor\nprivate final  int mVersionCode\nprivate final  int mRevisionCode\nprivate final  int mInstallLocation\nprivate final  int mMinSdkVersion\nprivate final  int mTargetSdkVersion\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final  boolean mFeatureSplit\nprivate final  boolean mIsolatedSplits\nprivate final  boolean mSplitRequired\nprivate final  boolean mCoreApp\nprivate final  boolean mDebuggable\nprivate final  boolean mProfileableByShell\nprivate final  boolean mMultiArch\nprivate final  boolean mUse32bitAbi\nprivate final  boolean mExtractNativeLibs\nprivate final  boolean mUseEmbeddedDex\nprivate final @android.annotation.Nullable java.lang.String mTargetPackageName\nprivate final  boolean mOverlayIsStatic\nprivate final  int mOverlayPriority\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyName\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyValue\nprivate final  int mRollbackDataPolicy\nprivate final  boolean mHasDeviceAdminReceiver\nprivate final  boolean mIsSdkLibrary\npublic  long getLongVersionCode()\nprivate  boolean hasAnyRequiredSplitTypes()\nclass ApkLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
+            inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.Nullable java.lang.String mUsesSplitName\nprivate final @android.annotation.Nullable java.lang.String mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mSplitTypes\nprivate final  int mVersionCodeMajor\nprivate final  int mVersionCode\nprivate final  int mRevisionCode\nprivate final  int mInstallLocation\nprivate final  int mMinSdkVersion\nprivate final  int mTargetSdkVersion\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final  boolean mFeatureSplit\nprivate final  boolean mIsolatedSplits\nprivate final  boolean mSplitRequired\nprivate final  boolean mCoreApp\nprivate final  boolean mDebuggable\nprivate final  boolean mProfileableByShell\nprivate final  boolean mMultiArch\nprivate final  boolean mUse32bitAbi\nprivate final  boolean mExtractNativeLibs\nprivate final  boolean mUseEmbeddedDex\nprivate final @android.annotation.Nullable java.lang.String mTargetPackageName\nprivate final  boolean mOverlayIsStatic\nprivate final  int mOverlayPriority\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyName\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyValue\nprivate final  int mRollbackDataPolicy\nprivate final  boolean mHasDeviceAdminReceiver\nprivate final  boolean mIsSdkLibrary\nprivate final  boolean mClearUserDataAllowed\nprivate final  boolean mBackupAllowed\nprivate final  boolean mDefaultToDeviceProtectedStorage\nprivate final  boolean mRequestLegacyExternalStorage\nprivate final  boolean mUserDataFragile\nprivate final  boolean mClearUserDataOnFailedRestoreAllowed\npublic  long getLongVersionCode()\nprivate  boolean hasAnyRequiredSplitTypes()\nclass ApkLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index 4f6bcb6..066ff689 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -40,6 +40,7 @@
 import android.util.Slog;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.XmlUtils;
 
 import libcore.io.IoUtils;
 
@@ -73,7 +74,7 @@
     // Constants copied from services.jar side since they're not accessible
     private static final String ANDROID_RES_NAMESPACE =
             "http://schemas.android.com/apk/res/android";
-    private static final int DEFAULT_MIN_SDK_VERSION = 1;
+    public static final int DEFAULT_MIN_SDK_VERSION = 1;
     private static final int DEFAULT_TARGET_SDK_VERSION = 0;
     public static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
     private static final int PARSE_IS_SYSTEM_DIR = 1 << 4;
@@ -446,6 +447,13 @@
         int overlayPriority = 0;
         int rollbackDataPolicy = 0;
 
+        boolean clearUserDataAllowed = true;
+        boolean backupAllowed = true;
+        boolean defaultToDeviceProtectedStorage = false;
+        String requestLegacyExternalStorage = null;
+        boolean userDataFragile = false;
+        boolean clearUserDataOnFailedRestoreAllowed = true;
+
         String requiredSystemPropertyName = null;
         String requiredSystemPropertyValue = null;
 
@@ -484,6 +492,23 @@
                         "extractNativeLibs", true);
                 useEmbeddedDex = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE,
                         "useEmbeddedDex", false);
+
+                clearUserDataAllowed = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE,
+                        "allowClearUserDataOnFailedRestore", true);
+                backupAllowed = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE,
+                        "allowBackup", true);
+                defaultToDeviceProtectedStorage = parser.getAttributeBooleanValue(
+                        ANDROID_RES_NAMESPACE,
+                        "defaultToDeviceProtectedStorage", false);
+                userDataFragile = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE,
+                        "hasFragileUserData", false);
+                clearUserDataOnFailedRestoreAllowed = parser.getAttributeBooleanValue(
+                        ANDROID_RES_NAMESPACE,
+                        "allowClearUserDataOnFailedRestore", true);
+
+                requestLegacyExternalStorage = parser.getAttributeValue(ANDROID_RES_NAMESPACE,
+                        "requestLegacyExternalStorage");
+
                 rollbackDataPolicy = parser.getAttributeIntValue(ANDROID_RES_NAMESPACE,
                         "rollbackDataPolicy", 0);
                 String permission = parser.getAttributeValue(ANDROID_RES_NAMESPACE,
@@ -604,6 +629,9 @@
             return input.skip(message);
         }
 
+        boolean isRequestLegacyExternalStorage = XmlUtils.convertValueToBoolean(
+                requestLegacyExternalStorage, targetSdkVersion < Build.VERSION_CODES.Q);
+
         return input.success(
                 new ApkLite(codePath, packageSplit.first, packageSplit.second, isFeatureSplit,
                         configForSplit, usesSplitName, isSplitRequired, versionCode,
@@ -613,7 +641,9 @@
                         overlayIsStatic, overlayPriority, requiredSystemPropertyName,
                         requiredSystemPropertyValue, minSdkVersion, targetSdkVersion,
                         rollbackDataPolicy, requiredSplitTypes.first, requiredSplitTypes.second,
-                        hasDeviceAdminReceiver, isSdkLibrary));
+                        hasDeviceAdminReceiver, isSdkLibrary, clearUserDataAllowed, backupAllowed,
+                        defaultToDeviceProtectedStorage, isRequestLegacyExternalStorage,
+                        userDataFragile, clearUserDataOnFailedRestoreAllowed));
     }
 
     private static boolean isDeviceAdminReceiver(
diff --git a/core/java/android/content/pm/parsing/PackageLite.java b/core/java/android/content/pm/parsing/PackageLite.java
index e2789c9..4638af7 100644
--- a/core/java/android/content/pm/parsing/PackageLite.java
+++ b/core/java/android/content/pm/parsing/PackageLite.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.pm.PackageInfo;
+import android.content.pm.SigningDetails;
 import android.content.pm.VerifierInfo;
 
 import com.android.internal.util.ArrayUtils;
@@ -78,6 +79,8 @@
     private final int mInstallLocation;
     /** Information about a package verifiers as used during package verification */
     private final @NonNull VerifierInfo[] mVerifiers;
+    /** Signing-related data of an application package */
+    private final @NonNull SigningDetails mSigningDetails;
 
     /** Indicate whether any split APKs that are features. Ordered by splitName */
     private final @Nullable boolean[] mIsFeatureSplits;
@@ -109,6 +112,33 @@
      * Indicates if this package is a sdk.
      */
     private final boolean mIsSdkLibrary;
+    /**
+     * Indicates whether this application's data will be cleared on a failed restore.
+     */
+    private final boolean mClearUserDataAllowed;
+    /**
+     *  Set to <code>false</code> if the application does not wish to permit any OS-driven
+     *  backups of its data; <code>true</code> otherwise.
+     */
+    private final boolean mBackupAllowed;
+    /**
+     * When set, the default data storage directory for this app is pointed at
+     * the device-protected location.
+     */
+    private final boolean mDefaultToDeviceProtectedStorage;
+    /**
+     * If {@code true} this app requests full external storage access.
+     */
+    private final boolean mRequestLegacyExternalStorage;
+    /**
+     * Indicates whether this application has declared its user data as fragile, causing the
+     * system to prompt the user on whether to keep the user data on uninstall.
+     */
+    private final boolean mUserDataFragile;
+    /**
+     * Indicates whether this application's data will be cleared on a failed restore.
+     */
+    private final boolean mClearUserDataOnFailedRestoreAllowed;
 
     public PackageLite(String path, String baseApkPath, ApkLite baseApk,
             String[] splitNames, boolean[] isFeatureSplits, String[] usesSplitNames,
@@ -123,6 +153,7 @@
         mVersionCodeMajor = baseApk.getVersionCodeMajor();
         mInstallLocation = baseApk.getInstallLocation();
         mVerifiers = baseApk.getVerifiers();
+        mSigningDetails = baseApk.getSigningDetails();
         mBaseRevisionCode = baseApk.getRevisionCode();
         mCoreApp = baseApk.isCoreApp();
         mDebuggable = baseApk.isDebuggable();
@@ -144,6 +175,12 @@
         mSplitApkPaths = splitApkPaths;
         mSplitRevisionCodes = splitRevisionCodes;
         mTargetSdk = targetSdk;
+        mClearUserDataAllowed = baseApk.isClearUserDataAllowed();
+        mBackupAllowed = baseApk.isBackupAllowed();
+        mDefaultToDeviceProtectedStorage = baseApk.isDefaultToDeviceProtectedStorage();
+        mRequestLegacyExternalStorage = baseApk.isRequestLegacyExternalStorage();
+        mUserDataFragile = baseApk.isUserDataFragile();
+        mClearUserDataOnFailedRestoreAllowed = baseApk.isClearUserDataOnFailedRestoreAllowed();
     }
 
     /**
@@ -325,6 +362,14 @@
     }
 
     /**
+     * Signing-related data of an application package
+     */
+    @DataClass.Generated.Member
+    public @NonNull SigningDetails getSigningDetails() {
+        return mSigningDetails;
+    }
+
+    /**
      * Indicate whether any split APKs that are features. Ordered by splitName
      */
     @DataClass.Generated.Member
@@ -414,12 +459,62 @@
         return mIsSdkLibrary;
     }
 
+    /**
+     * Indicates whether this application's data will be cleared on a failed restore.
+     */
+    @DataClass.Generated.Member
+    public boolean isClearUserDataAllowed() {
+        return mClearUserDataAllowed;
+    }
+
+    /**
+     *  Set to <code>false</code> if the application does not wish to permit any OS-driven
+     *  backups of its data; <code>true</code> otherwise.
+     */
+    @DataClass.Generated.Member
+    public boolean isBackupAllowed() {
+        return mBackupAllowed;
+    }
+
+    /**
+     * When set, the default data storage directory for this app is pointed at
+     * the device-protected location.
+     */
+    @DataClass.Generated.Member
+    public boolean isDefaultToDeviceProtectedStorage() {
+        return mDefaultToDeviceProtectedStorage;
+    }
+
+    /**
+     * If {@code true} this app requests full external storage access.
+     */
+    @DataClass.Generated.Member
+    public boolean isRequestLegacyExternalStorage() {
+        return mRequestLegacyExternalStorage;
+    }
+
+    /**
+     * Indicates whether this application has declared its user data as fragile, causing the
+     * system to prompt the user on whether to keep the user data on uninstall.
+     */
+    @DataClass.Generated.Member
+    public boolean isUserDataFragile() {
+        return mUserDataFragile;
+    }
+
+    /**
+     * Indicates whether this application's data will be cleared on a failed restore.
+     */
+    @DataClass.Generated.Member
+    public boolean isClearUserDataOnFailedRestoreAllowed() {
+        return mClearUserDataOnFailedRestoreAllowed;
+    }
+
     @DataClass.Generated(
-            time = 1643132127068L,
+            time = 1693423910860L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/content/pm/parsing/PackageLite.java",
-            inputSignatures =
-                    "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.NonNull java.lang.String mBaseApkPath\nprivate final @android.annotation.Nullable java.lang.String[] mSplitApkPaths\nprivate final @android.annotation.Nullable java.lang.String[] mSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mUsesSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mBaseRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mSplitTypes\nprivate final  int mVersionCodeMajor\nprivate final  int mVersionCode\nprivate final  int mTargetSdk\nprivate final  int mBaseRevisionCode\nprivate final @android.annotation.Nullable int[] mSplitRevisionCodes\nprivate final  int mInstallLocation\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.Nullable boolean[] mIsFeatureSplits\nprivate final  boolean mIsolatedSplits\nprivate final  boolean mSplitRequired\nprivate final  boolean mCoreApp\nprivate final  boolean mDebuggable\nprivate final  boolean mMultiArch\nprivate final  boolean mUse32bitAbi\nprivate final  boolean mExtractNativeLibs\nprivate final  boolean mProfileableByShell\nprivate final  boolean mUseEmbeddedDex\nprivate final  boolean mIsSdkLibrary\npublic  java.util.List<java.lang.String> getAllApkPaths()\npublic  long getLongVersionCode()\nprivate  boolean hasAnyRequiredSplitTypes()\nclass PackageLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
+            inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.NonNull java.lang.String mBaseApkPath\nprivate final @android.annotation.Nullable java.lang.String[] mSplitApkPaths\nprivate final @android.annotation.Nullable java.lang.String[] mSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mUsesSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mBaseRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mSplitTypes\nprivate final  int mVersionCodeMajor\nprivate final  int mVersionCode\nprivate final  int mTargetSdk\nprivate final  int mBaseRevisionCode\nprivate final @android.annotation.Nullable int[] mSplitRevisionCodes\nprivate final  int mInstallLocation\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final @android.annotation.Nullable boolean[] mIsFeatureSplits\nprivate final  boolean mIsolatedSplits\nprivate final  boolean mSplitRequired\nprivate final  boolean mCoreApp\nprivate final  boolean mDebuggable\nprivate final  boolean mMultiArch\nprivate final  boolean mUse32bitAbi\nprivate final  boolean mExtractNativeLibs\nprivate final  boolean mProfileableByShell\nprivate final  boolean mUseEmbeddedDex\nprivate final  boolean mIsSdkLibrary\nprivate final  boolean mClearUserDataAllowed\nprivate final  boolean mBackupAllowed\nprivate final  boolean mDefaultToDeviceProtectedStorage\nprivate final  boolean mRequestLegacyExternalStorage\nprivate final  boolean mUserDataFragile\nprivate final  boolean mClearUserDataOnFailedRestoreAllowed\npublic  java.util.List<java.lang.String> getAllApkPaths()\npublic  long getLongVersionCode()\nprivate  boolean hasAnyRequiredSplitTypes()\nclass PackageLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 76b29e6..5cc3b92 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -27,7 +27,6 @@
 import android.annotation.RawRes;
 import android.annotation.StyleRes;
 import android.annotation.StyleableRes;
-import android.app.ResourcesManager;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ActivityInfo.Config;
@@ -430,49 +429,35 @@
                 if ((configChanges & ActivityInfo.CONFIG_LOCALE) != 0) {
                     if (locales.size() > 1) {
                         String[] availableLocales;
-                        if (ResourcesManager.getInstance().getLocaleList().isEmpty()) {
-                            // The LocaleList has changed. We must query the AssetManager's
-                            // available Locales and figure out the best matching Locale in the new
-                            // LocaleList.
-                            availableLocales = mAssets.getNonSystemLocales();
+                        // The LocaleList has changed. We must query the AssetManager's
+                        // available Locales and figure out the best matching Locale in the new
+                        // LocaleList.
+                        availableLocales = mAssets.getNonSystemLocales();
+                        if (LocaleList.isPseudoLocalesOnly(availableLocales)) {
+                            // No app defined locales, so grab the system locales.
+                            availableLocales = mAssets.getLocales();
                             if (LocaleList.isPseudoLocalesOnly(availableLocales)) {
-                                // No app defined locales, so grab the system locales.
-                                availableLocales = mAssets.getLocales();
-                                if (LocaleList.isPseudoLocalesOnly(availableLocales)) {
-                                    availableLocales = null;
-                                }
+                                availableLocales = null;
                             }
+                        }
 
-                            if (availableLocales != null) {
-                                final Locale bestLocale = locales.getFirstMatchWithEnglishSupported(
-                                        availableLocales);
-                                if (bestLocale != null) {
-                                    selectedLocales = new String[]{
-                                            adjustLanguageTag(bestLocale.toLanguageTag())};
-                                    if (!bestLocale.equals(locales.get(0))) {
-                                        mConfiguration.setLocales(
-                                                new LocaleList(bestLocale, locales));
-                                    }
+                        if (availableLocales != null) {
+                            final Locale bestLocale = locales.getFirstMatchWithEnglishSupported(
+                                    availableLocales);
+                            if (bestLocale != null) {
+                                selectedLocales = new String[]{
+                                        adjustLanguageTag(bestLocale.toLanguageTag())};
+                                if (!bestLocale.equals(locales.get(0))) {
+                                    mConfiguration.setLocales(
+                                            new LocaleList(bestLocale, locales));
                                 }
                             }
-                        } else {
-                            selectedLocales = locales.getIntersection(
-                                    ResourcesManager.getInstance().getLocaleList());
-                            defaultLocale = ResourcesManager.getInstance()
-                                    .getLocaleList().get(0).toLanguageTag();
                         }
                     }
                 }
                 if (selectedLocales == null) {
-                    if (ResourcesManager.getInstance().getLocaleList().isEmpty()) {
-                        selectedLocales = new String[]{
-                                adjustLanguageTag(locales.get(0).toLanguageTag())};
-                    } else {
-                        selectedLocales = new String[locales.size()];
-                        for (int i = 0; i < locales.size(); i++) {
-                            selectedLocales[i] = adjustLanguageTag(locales.get(i).toLanguageTag());
-                        }
-                    }
+                    selectedLocales = new String[]{
+                            adjustLanguageTag(locales.get(0).toLanguageTag())};
                 }
 
                 if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index c0a44b1..f1ae9be 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -890,10 +890,13 @@
             mSystemCallingHideSoftInput = true;
             mCurHideInputToken = hideInputToken;
             mCurStatsToken = statsToken;
-            hideSoftInput(flags, resultReceiver);
-            mCurStatsToken = null;
-            mCurHideInputToken = null;
-            mSystemCallingHideSoftInput = false;
+            try {
+                hideSoftInput(flags, resultReceiver);
+            } finally {
+                mCurStatsToken = null;
+                mCurHideInputToken = null;
+                mSystemCallingHideSoftInput = false;
+            }
         }
 
         /**
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index bcde31a..c6cb604 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1002,6 +1002,24 @@
     public static final String DISALLOW_ADD_CLONE_PROFILE = "no_add_clone_profile";
 
     /**
+     * Specifies if a user is disallowed from creating a private profile.
+     * <p>The default value for an unmanaged user is <code>false</code>.
+     * For users with a device owner set, the default is <code>true</code>.
+     *
+     * <p>Holders of the permission
+     * {@link android.Manifest.permission#MANAGE_DEVICE_POLICY_PROFILES}
+     * can set this restriction using the DevicePolicyManager APIs mentioned below.
+     *
+     * <p>Key for user restrictions.
+     * <p>Type: Boolean
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+     * @see #getUserRestrictions()
+     * @hide
+     */
+    public static final String DISALLOW_ADD_PRIVATE_PROFILE = "no_add_private_profile";
+
+    /**
      * Specifies if a user is disallowed from disabling application verification. The default
      * value is <code>false</code>.
      *
@@ -1895,6 +1913,7 @@
             DISALLOW_ADD_USER,
             DISALLOW_ADD_MANAGED_PROFILE,
             DISALLOW_ADD_CLONE_PROFILE,
+            DISALLOW_ADD_PRIVATE_PROFILE,
             ENSURE_VERIFY_APPS,
             DISALLOW_CONFIG_CELL_BROADCASTS,
             DISALLOW_CONFIG_MOBILE_NETWORKS,
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 522caac..abc0c7a 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5885,15 +5885,6 @@
         public static final String MULTI_AUDIO_FOCUS_ENABLED = "multi_audio_focus_enabled";
 
         /**
-         * Whether desktop mode is enabled or not.
-         * 0 = off
-         * 1 = on
-         * @hide
-         */
-        @Readable
-        public static final String DESKTOP_MODE = "desktop_mode";
-
-        /**
          * The information of locale preference. This records user's preference to avoid
          * unsynchronized and existing locale preference in
          * {@link Locale#getDefault(Locale.Category)}.
@@ -6066,7 +6057,6 @@
             PRIVATE_SETTINGS.add(SHOW_BATTERY_PERCENT);
             PRIVATE_SETTINGS.add(DISPLAY_COLOR_MODE);
             PRIVATE_SETTINGS.add(DISPLAY_COLOR_MODE_VENDOR_HINT);
-            PRIVATE_SETTINGS.add(DESKTOP_MODE);
             PRIVATE_SETTINGS.add(LOCALE_PREFERENCES);
             PRIVATE_SETTINGS.add(TOUCHPAD_POINTER_SPEED);
             PRIVATE_SETTINGS.add(TOUCHPAD_NATURAL_SCROLLING);
@@ -18370,24 +18360,28 @@
              * If hotword detection should be enabled.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String HOTWORD_DETECTION_ENABLED = "hotword_detection_enabled";
 
             /**
              * Whether Smart Replies are enabled within Wear.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String SMART_REPLIES_ENABLED = "smart_replies_enabled";
 
             /**
              * The default vibration pattern.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String DEFAULT_VIBRATION = "default_vibration";
 
             /**
              * If FLP should obtain location data from the paired device.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String OBTAIN_PAIRED_DEVICE_LOCATION =
                     "obtain_paired_device_location";
 
@@ -18395,6 +18389,7 @@
              * The play store availability on companion phone.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String PHONE_PLAY_STORE_AVAILABILITY =
                     "phone_play_store_availability";
 
@@ -18410,6 +18405,7 @@
              * Whether the bug report is enabled.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String BUG_REPORT = "bug_report";
 
             // Possible bug report states
@@ -18422,12 +18418,14 @@
              * The enabled/disabled state of the SmartIlluminate.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String SMART_ILLUMINATE_ENABLED = "smart_illuminate_enabled";
 
             /**
              * Whether automatic time is enabled on the watch.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String CLOCKWORK_AUTO_TIME = "clockwork_auto_time";
 
             // Possible clockwork auto time states
@@ -18445,6 +18443,7 @@
              * Whether automatic time zone is enabled on the watch.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String CLOCKWORK_AUTO_TIME_ZONE = "clockwork_auto_time_zone";
 
             // Possible clockwork auto time zone states
@@ -18461,12 +18460,14 @@
              * Whether 24 hour time format is enabled on the watch.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String CLOCKWORK_24HR_TIME = "clockwork_24hr_time";
 
             /**
              * Whether the auto wifi toggle setting is enabled.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String AUTO_WIFI = "auto_wifi";
 
             // Possible force wifi on states
@@ -18486,6 +18487,7 @@
              * wifi requirement until this time). The time is in millis since epoch.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String ALT_BYPASS_WIFI_REQUIREMENT_TIME_MILLIS =
                     "alt_bypass_wifi_requirement_time_millis";
 
@@ -18493,6 +18495,7 @@
              * Whether the setup was skipped.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String SETUP_SKIPPED = "setup_skipped";
 
             // Possible setup_skipped states
@@ -18507,6 +18510,7 @@
              * The last requested call forwarding action.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String LAST_CALL_FORWARD_ACTION = "last_call_forward_action";
 
             // Possible call forwarding actions
@@ -18519,22 +18523,31 @@
 
             // Stem button settings.
             /** @hide */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String STEM_1_TYPE = "STEM_1_TYPE";
             /** @hide */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String STEM_1_DATA = "STEM_1_DATA";
             /** @hide */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String STEM_1_DEFAULT_DATA = "STEM_1_DEFAULT_DATA";
             /** @hide */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String STEM_2_TYPE = "STEM_2_TYPE";
             /** @hide */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String STEM_2_DATA = "STEM_2_DATA";
             /** @hide */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String STEM_2_DEFAULT_DATA = "STEM_2_DEFAULT_DATA";
             /** @hide */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String STEM_3_TYPE = "STEM_3_TYPE";
             /** @hide */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String STEM_3_DATA = "STEM_3_DATA";
             /** @hide */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String STEM_3_DEFAULT_DATA = "STEM_3_DEFAULT_DATA";
 
             // Stem types
@@ -18549,12 +18562,14 @@
              * If the device should be muted when off body.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String MUTE_WHEN_OFF_BODY_ENABLED = "obtain_mute_when_off_body";
 
             /**
              * Wear OS version string.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String WEAR_OS_VERSION_STRING = "wear_os_version_string";
 
             /**
@@ -18567,24 +18582,28 @@
              * The android wear system version.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String ANDROID_WEAR_VERSION = "android_wear_version";
 
             /**
              * The wear system capabiltiies.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String SYSTEM_CAPABILITIES = "system_capabilities";
 
             /**
              * The android wear system edition.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String SYSTEM_EDITION = "android_wear_system_edition";
 
             /**
              * The Wear platform MR number.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String WEAR_PLATFORM_MR_NUMBER = "wear_platform_mr_number";
 
             /**
@@ -18598,36 +18617,42 @@
              * Whether ambient is currently enabled.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String AMBIENT_ENABLED = "ambient_enabled";
 
             /**
              * Whether ambient tilt to wake is enabled.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String AMBIENT_TILT_TO_WAKE = "ambient_tilt_to_wake";
 
             /**
              * Whether ambient low bit mode is enabled by developer options.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String AMBIENT_LOW_BIT_ENABLED_DEV = "ambient_low_bit_enabled_dev";
 
             /**
              * Whether ambient touch to wake is enabled.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String AMBIENT_TOUCH_TO_WAKE = "ambient_touch_to_wake";
 
             /**
              * Whether ambient tilt to bright is enabled.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String AMBIENT_TILT_TO_BRIGHT = "ambient_tilt_to_bright";
 
             /**
              * Whether touch and hold to edit WF is enabled
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String GESTURE_TOUCH_AND_HOLD_WATCH_FACE_ENABLED =
                     "gesture_touch_and_hold_watchface_enabled";
 
@@ -18641,6 +18666,7 @@
              * Whether bedtime mode is enabled.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String BEDTIME_MODE = "bedtime_mode";
 
             /**
@@ -18652,31 +18678,35 @@
              * Whether the current watchface is decomposable.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String DECOMPOSABLE_WATCHFACE = "current_watchface_decomposable";
 
             /**
              * Whether to force ambient when docked.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String AMBIENT_FORCE_WHEN_DOCKED = "ambient_force_when_docked";
 
             /**
              * Whether the ambient low bit mode is enabled.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String AMBIENT_LOW_BIT_ENABLED = "ambient_low_bit_enabled";
 
             /**
              * The timeout duration in minutes of ambient mode when plugged in.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String AMBIENT_PLUGGED_TIMEOUT_MIN = "ambient_plugged_timeout_min";
 
             /**
              * What OS does paired device has.
              * @hide
              */
-            @Readable
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String PAIRED_DEVICE_OS_TYPE = "paired_device_os_type";
 
             // Possible values of PAIRED_DEVICE_OS_TYPE
@@ -18709,6 +18739,7 @@
              * The user's last setting for hfp client.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String USER_HFP_CLIENT_SETTING = "user_hfp_client_setting";
 
             // Possible hfp client user setting values
@@ -18733,6 +18764,7 @@
              * The companion App name.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String COMPANION_APP_NAME = "wear_companion_app_name";
 
             /**
@@ -18740,18 +18772,21 @@
              * wear. 1 for supporting, 0 for not supporting.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String ENABLE_ALL_LANGUAGES = "enable_all_languages";
 
             /**
              * The Locale (as language tag) the user chose at startup.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String SETUP_LOCALE = "setup_locale";
 
             /**
              * The version of oem setup present.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String OEM_SETUP_VERSION = "oem_setup_version";
 
             /**
@@ -18797,6 +18832,7 @@
              * -{@link BATTERY_SAVER_MODE_CUSTOM}
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String BATTERY_SAVER_MODE = "battery_saver_mode";
 
             /**
@@ -18829,6 +18865,7 @@
              * The maximum ambient mode duration when an activity is allowed to auto resume.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String WEAR_ACTIVITY_AUTO_RESUME_TIMEOUT_MS =
                     "wear_activity_auto_resume_timeout_ms";
 
@@ -18844,6 +18881,7 @@
              * If burn in protection is enabled.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String BURN_IN_PROTECTION_ENABLED = "burn_in_protection";
 
             /**
@@ -18862,6 +18900,7 @@
              *          RIGHT_WRIST_ROTATION_0 = "2", RIGHT_WRIST_ROTATION_180 = "3"
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String WRIST_ORIENTATION_MODE = "wear_wrist_orientation_mode";
 
             /**
@@ -18900,6 +18939,7 @@
              *
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String CLOCKWORK_SYSUI_PACKAGE = "clockwork_sysui_package";
 
             /**
@@ -18929,6 +18969,7 @@
              * Whether the device has Wet Mode/ Touch Lock Mode enabled.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String WET_MODE_ON = "wet_mode_on";
 
             /**
@@ -18947,6 +18988,7 @@
              * Whether charging sounds are enabled.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String CHARGING_SOUNDS_ENABLED = "wear_charging_sounds_enabled";
 
             /**
@@ -18955,6 +18997,7 @@
              *
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String DYNAMIC_COLOR_THEME_ENABLED = "dynamic_color_theme_enabled";
 
             /**
@@ -19046,6 +19089,7 @@
              * The key to indicate the data migration status on device upgrade in Wear Services.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String UPGRADE_DATA_MIGRATION_STATUS =
                     "upgrade_data_migration_status";
 
@@ -19096,17 +19140,20 @@
              * The custom foreground color.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String CUSTOM_COLOR_FOREGROUND = "custom_foreground_color";
 
             /**
              * The custom background color.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String CUSTOM_COLOR_BACKGROUND = "custom_background_color";
 
             /** The status of the phone switching process.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String PHONE_SWITCHING_STATUS = "phone_switching_status";
 
             /**
@@ -19187,6 +19234,7 @@
              * (0 = false, 1 = true)
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String REDUCE_MOTION = "reduce_motion";
 
             /**
@@ -19248,6 +19296,7 @@
              * Controls the launcher ui mode on wearable devices.
              * @hide
              */
+            @Readable(maxTargetSdk = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
             public static final String WEAR_LAUNCHER_UI_MODE = "wear_launcher_ui_mode";
 
             /** Whether Wear Power Anomaly Service is enabled.
diff --git a/core/java/android/service/trust/OWNERS b/core/java/android/service/trust/OWNERS
index 16eb19a..d352525 100644
--- a/core/java/android/service/trust/OWNERS
+++ b/core/java/android/service/trust/OWNERS
@@ -1,3 +1,4 @@
 # Bug component: 36824
 
 jacobhobbie@google.com
+dlm@google.com
diff --git a/core/java/android/view/HandwritingInitiator.java b/core/java/android/view/HandwritingInitiator.java
index 23afb03..a208d1f 100644
--- a/core/java/android/view/HandwritingInitiator.java
+++ b/core/java/android/view/HandwritingInitiator.java
@@ -81,6 +81,8 @@
     private int mConnectionCount = 0;
     private final InputMethodManager mImm;
 
+    private final Rect mTempRect = new Rect();
+
     private final RectF mTempRectF = new RectF();
 
     private final Region mTempRegion = new Region();
@@ -401,8 +403,9 @@
 
             final View cachedHoverTarget = getCachedHoverTarget();
             if (cachedHoverTarget != null) {
-                final Rect handwritingArea = getViewHandwritingArea(cachedHoverTarget);
-                if (isInHandwritingArea(handwritingArea, hoverX, hoverY, cachedHoverTarget,
+                final Rect handwritingArea = mTempRect;
+                if (getViewHandwritingArea(cachedHoverTarget, handwritingArea)
+                        && isInHandwritingArea(handwritingArea, hoverX, hoverY, cachedHoverTarget,
                         /* isHover */ true)
                         && shouldTriggerStylusHandwritingForView(cachedHoverTarget)) {
                     return cachedHoverTarget;
@@ -445,8 +448,9 @@
         // directly return the connectedView.
         final View connectedView = getConnectedView();
         if (connectedView != null) {
-            Rect handwritingArea = getViewHandwritingArea(connectedView);
-            if (isInHandwritingArea(handwritingArea, x, y, connectedView, isHover)
+            Rect handwritingArea = mTempRect;
+            if (getViewHandwritingArea(connectedView, handwritingArea)
+                    && isInHandwritingArea(handwritingArea, x, y, connectedView, isHover)
                     && shouldTriggerStylusHandwritingForView(connectedView)) {
                 return connectedView;
             }
@@ -528,28 +532,30 @@
     /**
      * Return the handwriting area of the given view, represented in the window's coordinate.
      * If the view didn't set any handwriting area, it will return the view's boundary.
-     * It will return null if the view or its handwriting area is not visible.
      *
-     * The handwriting area is clipped to its visible part.
+     * <p> The handwriting area is clipped to its visible part.
      * Notice that the returned rectangle is the view's original handwriting area without the
-     * view's handwriting area extends.
+     * view's handwriting area extends. </p>
+     *
+     * @param view the {@link View} whose handwriting area we want to compute.
+     * @param rect the {@link Rect} to receive the result.
+     *
+     * @return true if the view's handwriting area is still visible, or false if it's clipped and
+     * fully invisible. This method only consider the clip by given view's parents, but not the case
+     * where a view is covered by its sibling view.
      */
-    @Nullable
-    private static Rect getViewHandwritingArea(@NonNull View view) {
+    private static boolean getViewHandwritingArea(@NonNull View view, @NonNull Rect rect) {
         final ViewParent viewParent = view.getParent();
         if (viewParent != null && view.isAttachedToWindow() && view.isAggregatedVisible()) {
             final Rect localHandwritingArea = view.getHandwritingArea();
-            final Rect globalHandwritingArea = new Rect();
             if (localHandwritingArea != null) {
-                globalHandwritingArea.set(localHandwritingArea);
+                rect.set(localHandwritingArea);
             } else {
-                globalHandwritingArea.set(0, 0, view.getWidth(), view.getHeight());
+                rect.set(0, 0, view.getWidth(), view.getHeight());
             }
-            if (viewParent.getChildVisibleRect(view, globalHandwritingArea, null)) {
-                return globalHandwritingArea;
-            }
+            return viewParent.getChildVisibleRect(view, rect, null);
         }
-        return null;
+        return false;
     }
 
     /**
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 62e37a4..b8385c6 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1318,8 +1318,8 @@
      * that have the ignore orientation request display setting enabled by OEMs
      * (enables compatibility mode for fixed orientation on Android 12 (API
      * level 31) or higher; see
-     * <a href="https://developer.android.com/guide/topics/large-screens/large-screen-app-compatibility">
-     * Large screen app compatibility</a>
+     * <a href="https://developer.android.com/guide/topics/large-screens/large-screen-compatibility-mode">
+     * Large screen compatibility mode</a>
      * for more details).
      *
      * <p>To opt out of the user aspect ratio compatibility override, add this property
@@ -1358,8 +1358,8 @@
      * that have the ignore orientation request display setting enabled by OEMs
      * (enables compatibility mode for fixed orientation on Android 12 (API
      * level 31) or higher; see
-     * <a href="https://developer.android.com/guide/topics/large-screens/large-screen-app-compatibility">
-     * Large screen app compatibility</a>
+     * <a href="https://developer.android.com/guide/topics/large-screens/large-screen-compatibility-mode">
+     * Large screen compatibility mode</a>
      * for more details).
      *
      * <p>To opt out of the full-screen option of the user aspect ratio compatibility
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index f99f138..ddb0a8b3 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -2101,7 +2101,7 @@
         if (ims != null && ims.mBatchEditNesting == 0) {
             InputMethodManager imm = getInputMethodManager();
             if (imm != null) {
-                if (imm.isActive(mTextView)) {
+                if (imm.hasActiveInputConnection(mTextView)) {
                     if (ims.mContentChanged || ims.mSelectionModeChanged) {
                         // We are in extract mode and the content has changed
                         // in some way... just report complete new text to the
diff --git a/core/java/android/window/DisplayWindowPolicyController.java b/core/java/android/window/DisplayWindowPolicyController.java
index c270053..2747233a 100644
--- a/core/java/android/window/DisplayWindowPolicyController.java
+++ b/core/java/android/window/DisplayWindowPolicyController.java
@@ -17,8 +17,10 @@
 package android.window;
 
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.view.Display.INVALID_DISPLAY;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.WindowConfiguration;
 import android.content.ComponentName;
@@ -107,18 +109,38 @@
     }
 
     /**
-     * Returns {@code true} if the given activities can be displayed on this virtual display and
-     * the windowing mode is supported.
+     * Returns {@code true} if all of the given activities can be launched on this virtual display
+     * in the configuration defined by the rest of the arguments.
+     *
+     * @see #canContainActivity
      */
-    public abstract boolean canContainActivities(@NonNull List<ActivityInfo> activities,
-            @WindowConfiguration.WindowingMode int windowingMode);
+    public boolean canContainActivities(@NonNull List<ActivityInfo> activities,
+            @WindowConfiguration.WindowingMode int windowingMode) {
+        for (int i = 0; i < activities.size(); i++) {
+            if (!canContainActivity(activities.get(i), windowingMode,
+                    /*launchingFromDisplayId=*/ INVALID_DISPLAY, /*isNewTask=*/ false)) {
+                return false;
+            }
+        }
+        return true;
+    }
 
     /**
-     * Returns {@code true} if the given new task can be launched on this virtual display.
+     * Returns {@code true} if the given activity can be launched on this virtual display in the
+     * configuration defined by the rest of the arguments. If the given intent would be intercepted
+     * by the display owner then this means that the activity cannot be launched.
      */
-    public abstract boolean canActivityBeLaunched(@NonNull ActivityInfo activityInfo, Intent intent,
-            @WindowConfiguration.WindowingMode int windowingMode, int launchingFromDisplayId,
-            boolean isNewTask);
+    public abstract boolean canActivityBeLaunched(@NonNull ActivityInfo activityInfo,
+            @Nullable Intent intent, @WindowConfiguration.WindowingMode int windowingMode,
+            int launchingFromDisplayId, boolean isNewTask);
+
+    /**
+     * Returns {@code true} if the given activity can be launched on this virtual display in the
+     * configuration defined by the rest of the arguments.
+     */
+    protected abstract boolean canContainActivity(@NonNull ActivityInfo activityInfo,
+            @WindowConfiguration.WindowingMode int windowingMode,
+            int launchingFromDisplayId, boolean isNewTask);
 
     /**
      * Called when an Activity window is layouted with the new changes where contains the
diff --git a/core/res/OWNERS b/core/res/OWNERS
index b46902e..0df7c20 100644
--- a/core/res/OWNERS
+++ b/core/res/OWNERS
@@ -52,3 +52,6 @@
 # Telephony
 per-file res/values/config_telephony.xml = file:/platform/frameworks/opt/telephony:/OWNERS
 per-file res/xml/sms_short_codes.xml = file:/platform/frameworks/opt/telephony:/OWNERS
+
+# TV Input Framework
+per-file res/values/config_tv_external_input_logging.xml = file:/services/core/java/com/android/server/tv/OWNERS
diff --git a/core/tests/coretests/res/layout/viewgroup_test.xml b/core/tests/coretests/res/layout/viewgroup_test.xml
index 04f4f52..9b57047 100644
--- a/core/tests/coretests/res/layout/viewgroup_test.xml
+++ b/core/tests/coretests/res/layout/viewgroup_test.xml
@@ -42,8 +42,8 @@
         android:id="@+id/view_translate"
         android:layout_width="20dp"
         android:layout_height="10dp"
-        android:translationX="10dp"
-        android:translationY="20dp"
+        android:translationX="10px"
+        android:translationY="20px"
         android:text="Hello World!"
         android:background="#2F00FF00" />
     <FrameLayout
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index a923479..a41fb64 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -630,7 +630,7 @@
         });
     }
 
-    @FlakyTest(bugId = 295234586)
+    @FlakyTest(bugId = 298331121)
     @Test
     public void testHandleConfigurationChanged_DoesntOverrideActivityConfig() {
         final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
@@ -836,8 +836,10 @@
     }
 
     private static ClientTransaction newRelaunchResumeTransaction(Activity activity) {
+        final Configuration currentConfig = activity.getResources().getConfiguration();
         final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(null,
-                null, 0, new MergedConfiguration(), false /* preserveWindow */);
+                null, 0, new MergedConfiguration(currentConfig, currentConfig),
+                false /* preserveWindow */);
         final ResumeActivityItem resumeStateRequest =
                 ResumeActivityItem.obtain(true /* isForward */,
                         false /* shouldSendCompatFakeFocus*/);
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
index 55eabb0..c3d8f9a 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/WindowExtensionsImpl.java
@@ -16,12 +16,14 @@
 
 package androidx.window.extensions;
 
+import android.app.ActivityTaskManager;
 import android.app.ActivityThread;
 import android.app.Application;
 import android.content.Context;
 import android.window.TaskFragmentOrganizer;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.window.common.DeviceStateManagerFoldingFeatureProducer;
 import androidx.window.common.RawFoldingFeatureProducer;
 import androidx.window.extensions.area.WindowAreaComponent;
@@ -111,9 +113,13 @@
      * {@link WindowExtensions#getWindowLayoutComponent()}.
      * @return {@link ActivityEmbeddingComponent} OEM implementation.
      */
-    @NonNull
+    @Nullable
     public ActivityEmbeddingComponent getActivityEmbeddingComponent() {
         if (mSplitController == null) {
+            if (!ActivityTaskManager.supportsMultiWindow(getApplication())) {
+                // Disable AE for device that doesn't support multi window.
+                return null;
+            }
             synchronized (mLock) {
                 if (mSplitController == null) {
                     mSplitController = new SplitController(
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
index ccf9552..e03e1ec 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
@@ -319,13 +319,17 @@
             return features;
         }
 
+        // We will transform the feature bounds to the Activity window, so using the rotation
+        // from the same source (WindowConfiguration) to make sure they are synchronized.
+        final int rotation = windowConfiguration.getDisplayRotation();
+
         for (CommonFoldingFeature baseFeature : storedFeatures) {
             Integer state = convertToExtensionState(baseFeature.getState());
             if (state == null) {
                 continue;
             }
             Rect featureRect = baseFeature.getRect();
-            rotateRectToDisplayRotation(displayId, featureRect);
+            rotateRectToDisplayRotation(displayId, rotation, featureRect);
             transformToWindowSpaceRect(windowConfiguration, featureRect);
 
             if (isZero(featureRect)) {
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java
index 5bfb0ebd..15a329bd 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/sidecar/SampleSidecarImpl.java
@@ -120,10 +120,12 @@
         }
 
         List<SidecarDisplayFeature> features = new ArrayList<>();
+        final int rotation = activity.getResources().getConfiguration().windowConfiguration
+                .getDisplayRotation();
         for (CommonFoldingFeature baseFeature : mStoredFeatures) {
             SidecarDisplayFeature feature = new SidecarDisplayFeature();
             Rect featureRect = baseFeature.getRect();
-            rotateRectToDisplayRotation(displayId, featureRect);
+            rotateRectToDisplayRotation(displayId, rotation, featureRect);
             transformToWindowSpaceRect(activity, featureRect);
             feature.setRect(featureRect);
             feature.setType(baseFeature.getType());
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/util/ExtensionHelper.java b/libs/WindowManager/Jetpack/src/androidx/window/util/ExtensionHelper.java
index 9e2611f..57f8308 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/util/ExtensionHelper.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/util/ExtensionHelper.java
@@ -16,8 +16,6 @@
 
 package androidx.window.util;
 
-import static android.view.Surface.ROTATION_0;
-import static android.view.Surface.ROTATION_180;
 import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
 
@@ -25,8 +23,8 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.hardware.display.DisplayManagerGlobal;
+import android.util.RotationUtils;
 import android.view.DisplayInfo;
-import android.view.Surface;
 import android.view.WindowManager;
 
 import androidx.annotation.NonNull;
@@ -45,10 +43,9 @@
      * Rotates the input rectangle specified in default display orientation to the current display
      * rotation.
      */
-    public static void rotateRectToDisplayRotation(int displayId, Rect inOutRect) {
+    public static void rotateRectToDisplayRotation(int displayId, int rotation, Rect inOutRect) {
         DisplayManagerGlobal dmGlobal = DisplayManagerGlobal.getInstance();
         DisplayInfo displayInfo = dmGlobal.getDisplayInfo(displayId);
-        int rotation = displayInfo.rotation;
 
         boolean isSideRotation = rotation == ROTATION_90 || rotation == ROTATION_270;
         int displayWidth = isSideRotation ? displayInfo.logicalHeight : displayInfo.logicalWidth;
@@ -56,35 +53,7 @@
 
         inOutRect.intersect(0, 0, displayWidth, displayHeight);
 
-        rotateBounds(inOutRect, displayWidth, displayHeight, rotation);
-    }
-
-    /**
-     * Rotates the input rectangle within parent bounds for a given delta.
-     */
-    private static void rotateBounds(Rect inOutRect, int parentWidth, int parentHeight,
-            @Surface.Rotation int delta) {
-        int origLeft = inOutRect.left;
-        switch (delta) {
-            case ROTATION_0:
-                return;
-            case ROTATION_90:
-                inOutRect.left = inOutRect.top;
-                inOutRect.top = parentWidth - inOutRect.right;
-                inOutRect.right = inOutRect.bottom;
-                inOutRect.bottom = parentWidth - origLeft;
-                return;
-            case ROTATION_180:
-                inOutRect.left = parentWidth - inOutRect.right;
-                inOutRect.right = parentWidth - origLeft;
-                return;
-            case ROTATION_270:
-                inOutRect.left = parentHeight - inOutRect.bottom;
-                inOutRect.bottom = inOutRect.right;
-                inOutRect.right = parentHeight - inOutRect.top;
-                inOutRect.top = origLeft;
-                return;
-        }
+        RotationUtils.rotateBounds(inOutRect, displayWidth, displayHeight, rotation);
     }
 
     /** Transforms rectangle from absolute coordinate space to the window coordinate space. */
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java
index d189ae2..45564cb 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/WindowExtensionsTest.java
@@ -16,8 +16,11 @@
 
 package androidx.window.extensions;
 
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
 import static com.google.common.truth.Truth.assertThat;
 
+import android.app.ActivityTaskManager;
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -52,7 +55,11 @@
 
     @Test
     public void testGetActivityEmbeddingComponent() {
-        assertThat(mExtensions.getActivityEmbeddingComponent()).isNotNull();
+        if (ActivityTaskManager.supportsMultiWindow(getInstrumentation().getContext())) {
+            assertThat(mExtensions.getActivityEmbeddingComponent()).isNotNull();
+        } else {
+            assertThat(mExtensions.getActivityEmbeddingComponent()).isNull();
+        }
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 1c2cee5..998cd5d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -72,7 +72,6 @@
 import com.android.wm.shell.compatui.CompatUIController;
 import com.android.wm.shell.compatui.CompatUIShellCommandHandler;
 import com.android.wm.shell.desktopmode.DesktopMode;
-import com.android.wm.shell.desktopmode.DesktopModeController;
 import com.android.wm.shell.desktopmode.DesktopModeStatus;
 import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
 import com.android.wm.shell.desktopmode.DesktopTasksController;
@@ -109,13 +108,13 @@
 import com.android.wm.shell.unfold.UnfoldTransitionHandler;
 import com.android.wm.shell.windowdecor.WindowDecorViewModel;
 
+import java.util.Optional;
+
 import dagger.BindsOptionalOf;
 import dagger.Lazy;
 import dagger.Module;
 import dagger.Provides;
 
-import java.util.Optional;
-
 /**
  * Provides basic dependencies from {@link com.android.wm.shell}, these dependencies are only
  * accessible from components within the WM subcomponent (can be explicitly exposed to the
@@ -800,30 +799,10 @@
     @WMSingleton
     @Provides
     static Optional<DesktopMode> provideDesktopMode(
-            Optional<DesktopModeController> desktopModeController,
             Optional<DesktopTasksController> desktopTasksController) {
-        if (DesktopModeStatus.isProto2Enabled()) {
-            return desktopTasksController.map(DesktopTasksController::asDesktopMode);
-        }
-        return desktopModeController.map(DesktopModeController::asDesktopMode);
+        return desktopTasksController.map(DesktopTasksController::asDesktopMode);
     }
 
-    @BindsOptionalOf
-    @DynamicOverride
-    abstract DesktopModeController optionalDesktopModeController();
-
-    @WMSingleton
-    @Provides
-    static Optional<DesktopModeController> provideDesktopModeController(
-            @DynamicOverride Optional<Lazy<DesktopModeController>> desktopModeController) {
-        // Use optional-of-lazy for the dependency that this provider relies on.
-        // Lazy ensures that this provider will not be the cause the dependency is created
-        // when it will not be returned due to the condition below.
-        if (DesktopModeStatus.isProto1Enabled()) {
-            return desktopModeController.map(Lazy::get);
-        }
-        return Optional.empty();
-    }
 
     @BindsOptionalOf
     @DynamicOverride
@@ -836,7 +815,7 @@
         // Use optional-of-lazy for the dependency that this provider relies on.
         // Lazy ensures that this provider will not be the cause the dependency is created
         // when it will not be returned due to the condition below.
-        if (DesktopModeStatus.isProto2Enabled()) {
+        if (DesktopModeStatus.isEnabled()) {
             return desktopTasksController.map(Lazy::get);
         }
         return Optional.empty();
@@ -853,7 +832,7 @@
         // Use optional-of-lazy for the dependency that this provider relies on.
         // Lazy ensures that this provider will not be the cause the dependency is created
         // when it will not be returned due to the condition below.
-        if (DesktopModeStatus.isAnyEnabled()) {
+        if (DesktopModeStatus.isEnabled()) {
             return desktopModeTaskRepository.map(Lazy::get);
         }
         return Optional.empty();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index c641e87..e9f3e1a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -54,7 +54,6 @@
 import com.android.wm.shell.common.annotations.ShellMainThread;
 import com.android.wm.shell.dagger.back.ShellBackAnimationModule;
 import com.android.wm.shell.dagger.pip.PipModule;
-import com.android.wm.shell.desktopmode.DesktopModeController;
 import com.android.wm.shell.desktopmode.DesktopModeStatus;
 import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
 import com.android.wm.shell.desktopmode.DesktopTasksController;
@@ -197,10 +196,9 @@
             ShellController shellController,
             SyncTransactionQueue syncQueue,
             Transitions transitions,
-            Optional<DesktopModeController> desktopModeController,
             Optional<DesktopTasksController> desktopTasksController,
             RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) {
-        if (DesktopModeStatus.isAnyEnabled()) {
+        if (DesktopModeStatus.isEnabled()) {
             return new DesktopModeWindowDecorViewModel(
                     context,
                     mainHandler,
@@ -211,7 +209,6 @@
                     shellController,
                     syncQueue,
                     transitions,
-                    desktopModeController,
                     desktopTasksController,
                     rootTaskDisplayAreaOrganizer);
         }
@@ -353,13 +350,12 @@
             @Nullable PipTransitionController pipTransitionController,
             Optional<RecentsTransitionHandler> recentsTransitionHandler,
             KeyguardTransitionHandler keyguardTransitionHandler,
-            Optional<DesktopModeController> desktopModeController,
             Optional<DesktopTasksController> desktopTasksController,
             Optional<UnfoldTransitionHandler> unfoldHandler,
             Transitions transitions) {
         return new DefaultMixedHandler(shellInit, transitions, splitScreenOptional,
                 pipTransitionController, recentsTransitionHandler,
-                keyguardTransitionHandler, desktopModeController, desktopTasksController,
+                keyguardTransitionHandler, desktopTasksController,
                 unfoldHandler);
     }
 
@@ -471,24 +467,6 @@
     @WMSingleton
     @Provides
     @DynamicOverride
-    static DesktopModeController provideDesktopModeController(Context context,
-            ShellInit shellInit,
-            ShellController shellController,
-            ShellTaskOrganizer shellTaskOrganizer,
-            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
-            Transitions transitions,
-            @DynamicOverride DesktopModeTaskRepository desktopModeTaskRepository,
-            @ShellMainThread Handler mainHandler,
-            @ShellMainThread ShellExecutor mainExecutor
-    ) {
-        return new DesktopModeController(context, shellInit, shellController, shellTaskOrganizer,
-                rootTaskDisplayAreaOrganizer, transitions, desktopModeTaskRepository, mainHandler,
-                mainExecutor);
-    }
-
-    @WMSingleton
-    @Provides
-    @DynamicOverride
     static DesktopTasksController provideDesktopTasksController(
             Context context,
             ShellInit shellInit,
@@ -553,8 +531,7 @@
     @ShellCreateTriggerOverride
     @Provides
     static Object provideIndependentShellComponentsToCreate(
-            DefaultMixedHandler defaultMixedHandler,
-            Optional<DesktopModeController> desktopModeController) {
+            DefaultMixedHandler defaultMixedHandler) {
         return new Object();
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
deleted file mode 100644
index 5b24d7a..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
+++ /dev/null
@@ -1,557 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.desktopmode;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.view.WindowManager.TRANSIT_CHANGE;
-import static android.view.WindowManager.TRANSIT_NONE;
-import static android.view.WindowManager.TRANSIT_OPEN;
-import static android.view.WindowManager.TRANSIT_TO_FRONT;
-
-import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
-import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE;
-import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_DESKTOP_MODE;
-
-import android.app.ActivityManager.RunningTaskInfo;
-import android.app.WindowConfiguration;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.database.ContentObserver;
-import android.graphics.Region;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.util.ArraySet;
-import android.view.SurfaceControl;
-import android.view.WindowManager;
-import android.window.DisplayAreaInfo;
-import android.window.TransitionInfo;
-import android.window.TransitionRequestInfo;
-import android.window.WindowContainerTransaction;
-
-import androidx.annotation.BinderThread;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.protolog.common.ProtoLog;
-import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.common.ExternalInterfaceBinder;
-import com.android.wm.shell.common.RemoteCallable;
-import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.common.annotations.ExternalThread;
-import com.android.wm.shell.common.annotations.ShellMainThread;
-import com.android.wm.shell.sysui.ShellController;
-import com.android.wm.shell.sysui.ShellInit;
-import com.android.wm.shell.transition.Transitions;
-
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.List;
-import java.util.concurrent.Executor;
-import java.util.function.Consumer;
-
-/**
- * Handles windowing changes when desktop mode system setting changes
- */
-public class DesktopModeController implements RemoteCallable<DesktopModeController>,
-        Transitions.TransitionHandler {
-
-    private final Context mContext;
-    private final ShellController mShellController;
-    private final ShellTaskOrganizer mShellTaskOrganizer;
-    private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
-    private final Transitions mTransitions;
-    private final DesktopModeTaskRepository mDesktopModeTaskRepository;
-    private final ShellExecutor mMainExecutor;
-    private final DesktopModeImpl mDesktopModeImpl = new DesktopModeImpl();
-    private final SettingsObserver mSettingsObserver;
-
-    public DesktopModeController(Context context,
-            ShellInit shellInit,
-            ShellController shellController,
-            ShellTaskOrganizer shellTaskOrganizer,
-            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
-            Transitions transitions,
-            DesktopModeTaskRepository desktopModeTaskRepository,
-            @ShellMainThread Handler mainHandler,
-            @ShellMainThread ShellExecutor mainExecutor) {
-        mContext = context;
-        mShellController = shellController;
-        mShellTaskOrganizer = shellTaskOrganizer;
-        mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer;
-        mTransitions = transitions;
-        mDesktopModeTaskRepository = desktopModeTaskRepository;
-        mMainExecutor = mainExecutor;
-        mSettingsObserver = new SettingsObserver(mContext, mainHandler);
-        if (DesktopModeStatus.isProto1Enabled()) {
-            shellInit.addInitCallback(this::onInit, this);
-        }
-    }
-
-    private void onInit() {
-        ProtoLog.d(WM_SHELL_DESKTOP_MODE, "Initialize DesktopModeController");
-        mShellController.addExternalInterface(KEY_EXTRA_SHELL_DESKTOP_MODE,
-                this::createExternalInterface, this);
-        mSettingsObserver.observe();
-        if (DesktopModeStatus.isActive(mContext)) {
-            updateDesktopModeActive(true);
-        }
-        mTransitions.addHandler(this);
-    }
-
-    @Override
-    public Context getContext() {
-        return mContext;
-    }
-
-    @Override
-    public ShellExecutor getRemoteCallExecutor() {
-        return mMainExecutor;
-    }
-
-    /**
-     * Get connection interface between sysui and shell
-     */
-    public DesktopMode asDesktopMode() {
-        return mDesktopModeImpl;
-    }
-
-    /**
-     * Creates a new instance of the external interface to pass to another process.
-     */
-    private ExternalInterfaceBinder createExternalInterface() {
-        return new IDesktopModeImpl(this);
-    }
-
-    /**
-     * Adds a listener to find out about changes in the visibility of freeform tasks.
-     *
-     * @param listener the listener to add.
-     * @param callbackExecutor the executor to call the listener on.
-     */
-    public void addVisibleTasksListener(DesktopModeTaskRepository.VisibleTasksListener listener,
-            Executor callbackExecutor) {
-        mDesktopModeTaskRepository.addVisibleTasksListener(listener, callbackExecutor);
-    }
-
-    /**
-     * Adds a listener to track changes to corners of desktop mode tasks.
-     * @param listener the listener to add.
-     * @param callbackExecutor the executor to call the listener on.
-     */
-    public void addTaskCornerListener(Consumer<Region> listener,
-            Executor callbackExecutor) {
-        mDesktopModeTaskRepository.setTaskCornerListener(listener, callbackExecutor);
-    }
-
-    @VisibleForTesting
-    void updateDesktopModeActive(boolean active) {
-        ProtoLog.d(WM_SHELL_DESKTOP_MODE, "updateDesktopModeActive: active=%s", active);
-
-        int displayId = mContext.getDisplayId();
-
-        ArrayList<RunningTaskInfo> runningTasks = mShellTaskOrganizer.getRunningTasks(displayId);
-
-        WindowContainerTransaction wct = new WindowContainerTransaction();
-        // Reset freeform windowing mode that is set per task level so tasks inherit it
-        clearFreeformForStandardTasks(runningTasks, wct);
-        if (active) {
-            moveHomeBehindVisibleTasks(runningTasks, wct);
-            setDisplayAreaWindowingMode(displayId, WINDOWING_MODE_FREEFORM, wct);
-        } else {
-            clearBoundsForStandardTasks(runningTasks, wct);
-            setDisplayAreaWindowingMode(displayId, WINDOWING_MODE_FULLSCREEN, wct);
-        }
-        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
-            mTransitions.startTransition(TRANSIT_CHANGE, wct, null);
-        } else {
-            mRootTaskDisplayAreaOrganizer.applyTransaction(wct);
-        }
-    }
-
-    private WindowContainerTransaction clearBoundsForStandardTasks(
-            ArrayList<RunningTaskInfo> runningTasks, WindowContainerTransaction wct) {
-        ProtoLog.v(WM_SHELL_DESKTOP_MODE, "prepareClearBoundsForTasks");
-        for (RunningTaskInfo taskInfo : runningTasks) {
-            if (taskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD) {
-                ProtoLog.v(WM_SHELL_DESKTOP_MODE, "clearing bounds for token=%s taskInfo=%s",
-                        taskInfo.token, taskInfo);
-                wct.setBounds(taskInfo.token, null);
-            }
-        }
-        return wct;
-    }
-
-    private void clearFreeformForStandardTasks(ArrayList<RunningTaskInfo> runningTasks,
-            WindowContainerTransaction wct) {
-        ProtoLog.v(WM_SHELL_DESKTOP_MODE, "prepareClearFreeformForTasks");
-        for (RunningTaskInfo taskInfo : runningTasks) {
-            if (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM
-                    && taskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD) {
-                ProtoLog.v(WM_SHELL_DESKTOP_MODE,
-                        "clearing windowing mode for token=%s taskInfo=%s", taskInfo.token,
-                        taskInfo);
-                wct.setWindowingMode(taskInfo.token, WINDOWING_MODE_UNDEFINED);
-            }
-        }
-    }
-
-    private void moveHomeBehindVisibleTasks(ArrayList<RunningTaskInfo> runningTasks,
-            WindowContainerTransaction wct) {
-        ProtoLog.v(WM_SHELL_DESKTOP_MODE, "moveHomeBehindVisibleTasks");
-        RunningTaskInfo homeTask = null;
-        ArrayList<RunningTaskInfo> visibleTasks = new ArrayList<>();
-        for (RunningTaskInfo taskInfo : runningTasks) {
-            if (taskInfo.getActivityType() == ACTIVITY_TYPE_HOME) {
-                homeTask = taskInfo;
-            } else if (taskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD
-                    && taskInfo.isVisible()) {
-                visibleTasks.add(taskInfo);
-            }
-        }
-        if (homeTask == null) {
-            ProtoLog.w(WM_SHELL_DESKTOP_MODE, "moveHomeBehindVisibleTasks: home task not found");
-        } else {
-            ProtoLog.v(WM_SHELL_DESKTOP_MODE, "moveHomeBehindVisibleTasks: visible tasks %d",
-                    visibleTasks.size());
-            wct.reorder(homeTask.getToken(), true /* onTop */);
-            for (RunningTaskInfo task : visibleTasks) {
-                wct.reorder(task.getToken(), true /* onTop */);
-            }
-        }
-    }
-
-    private void setDisplayAreaWindowingMode(int displayId,
-            @WindowConfiguration.WindowingMode int windowingMode, WindowContainerTransaction wct) {
-        DisplayAreaInfo displayAreaInfo = mRootTaskDisplayAreaOrganizer.getDisplayAreaInfo(
-                displayId);
-        if (displayAreaInfo == null) {
-            ProtoLog.e(WM_SHELL_DESKTOP_MODE,
-                    "unable to update windowing mode for display %d display not found", displayId);
-            return;
-        }
-
-        ProtoLog.v(WM_SHELL_DESKTOP_MODE,
-                "setWindowingMode: displayId=%d current wmMode=%d new wmMode=%d", displayId,
-                displayAreaInfo.configuration.windowConfiguration.getWindowingMode(),
-                windowingMode);
-
-        wct.setWindowingMode(displayAreaInfo.token, windowingMode);
-    }
-
-    /**
-     * Show apps on desktop
-     */
-    void showDesktopApps(int displayId) {
-        // Bring apps to front, ignoring their visibility status to always ensure they are on top.
-        WindowContainerTransaction wct = new WindowContainerTransaction();
-        bringDesktopAppsToFront(displayId, wct);
-
-        if (!wct.isEmpty()) {
-            if (Transitions.ENABLE_SHELL_TRANSITIONS) {
-                // TODO(b/268662477): add animation for the transition
-                mTransitions.startTransition(TRANSIT_NONE, wct, null /* handler */);
-            } else {
-                mShellTaskOrganizer.applyTransaction(wct);
-            }
-        }
-    }
-
-    /** Get number of tasks that are marked as visible */
-    int getVisibleTaskCount(int displayId) {
-        return mDesktopModeTaskRepository.getVisibleTaskCount(displayId);
-    }
-
-    private void bringDesktopAppsToFront(int displayId, WindowContainerTransaction wct) {
-        final ArraySet<Integer> activeTasks = mDesktopModeTaskRepository.getActiveTasks(displayId);
-        ProtoLog.d(WM_SHELL_DESKTOP_MODE, "bringDesktopAppsToFront: tasks=%s", activeTasks.size());
-
-        final List<RunningTaskInfo> taskInfos = new ArrayList<>();
-        for (Integer taskId : activeTasks) {
-            RunningTaskInfo taskInfo = mShellTaskOrganizer.getRunningTaskInfo(taskId);
-            if (taskInfo != null) {
-                taskInfos.add(taskInfo);
-            }
-        }
-
-        if (taskInfos.isEmpty()) {
-            return;
-        }
-
-        moveHomeTaskToFront(wct);
-
-        ProtoLog.d(WM_SHELL_DESKTOP_MODE,
-                "bringDesktopAppsToFront: reordering all active tasks to the front");
-        final List<Integer> allTasksInZOrder =
-                mDesktopModeTaskRepository.getFreeformTasksInZOrder();
-        // Sort by z-order, bottom to top, so that the top-most task is reordered to the top last
-        // in the WCT.
-        taskInfos.sort(Comparator.comparingInt(task -> -allTasksInZOrder.indexOf(task.taskId)));
-        for (RunningTaskInfo task : taskInfos) {
-            wct.reorder(task.token, true);
-        }
-    }
-
-    private void moveHomeTaskToFront(WindowContainerTransaction wct) {
-        for (RunningTaskInfo task : mShellTaskOrganizer.getRunningTasks(mContext.getDisplayId())) {
-            if (task.getActivityType() == ACTIVITY_TYPE_HOME) {
-                wct.reorder(task.token, true /* onTop */);
-                return;
-            }
-        }
-    }
-
-    /**
-     * Update corner rects stored for a specific task
-     * @param taskId task to update
-     * @param taskCorners task's new corner handles
-     */
-    public void onTaskCornersChanged(int taskId, Region taskCorners) {
-        mDesktopModeTaskRepository.updateTaskCorners(taskId, taskCorners);
-    }
-
-    /**
-     * Remove corners saved for a task. Likely used due to task closure.
-     * @param taskId task to remove
-     */
-    public void removeCornersForTask(int taskId) {
-        mDesktopModeTaskRepository.removeTaskCorners(taskId);
-    }
-
-    /**
-     * Moves a specifc task to the front.
-     * @param taskInfo the task to show in front.
-     */
-    public void moveTaskToFront(RunningTaskInfo taskInfo) {
-        WindowContainerTransaction wct = new WindowContainerTransaction();
-        wct.reorder(taskInfo.token, true /* onTop */);
-        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
-            mTransitions.startTransition(TRANSIT_TO_FRONT, wct, null);
-        } else {
-            mShellTaskOrganizer.applyTransaction(wct);
-        }
-    }
-
-    /**
-     * Turn desktop mode on or off
-     * @param active the desired state for desktop mode setting
-     */
-    public void setDesktopModeActive(boolean active) {
-        int value = active ? 1 : 0;
-        Settings.System.putInt(mContext.getContentResolver(), Settings.System.DESKTOP_MODE, value);
-    }
-
-    /**
-     * Returns the windowing mode of the display area with the specified displayId.
-     * @param displayId
-     * @return
-     */
-    public int getDisplayAreaWindowingMode(int displayId) {
-        return mRootTaskDisplayAreaOrganizer.getDisplayAreaInfo(displayId)
-                .configuration.windowConfiguration.getWindowingMode();
-    }
-
-    @Override
-    public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
-            @NonNull SurfaceControl.Transaction startTransaction,
-            @NonNull SurfaceControl.Transaction finishTransaction,
-            @NonNull Transitions.TransitionFinishCallback finishCallback) {
-        // This handler should never be the sole handler, so should not animate anything.
-        return false;
-    }
-
-    @Nullable
-    @Override
-    public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
-            @NonNull TransitionRequestInfo request) {
-        RunningTaskInfo triggerTask = request.getTriggerTask();
-        // Only do anything if we are in desktop mode and opening/moving-to-front a task/app in
-        // freeform
-        if (!DesktopModeStatus.isActive(mContext)) {
-            ProtoLog.d(WM_SHELL_DESKTOP_MODE,
-                    "skip shell transition request: desktop mode not active");
-            return null;
-        }
-        if (request.getType() != TRANSIT_OPEN && request.getType() != TRANSIT_TO_FRONT) {
-            ProtoLog.d(WM_SHELL_DESKTOP_MODE,
-                    "skip shell transition request: unsupported type %s",
-                    WindowManager.transitTypeToString(request.getType()));
-            return null;
-        }
-        if (triggerTask == null || triggerTask.getWindowingMode() != WINDOWING_MODE_FREEFORM) {
-            ProtoLog.d(WM_SHELL_DESKTOP_MODE, "skip shell transition request: not freeform task");
-            return null;
-        }
-        ProtoLog.d(WM_SHELL_DESKTOP_MODE, "handle shell transition request: %s", request);
-
-        WindowContainerTransaction wct = new WindowContainerTransaction();
-        bringDesktopAppsToFront(triggerTask.displayId, wct);
-        wct.reorder(triggerTask.token, true /* onTop */);
-
-        return wct;
-    }
-
-    /**
-     * Applies the proper surface states (rounded corners) to tasks when desktop mode is active.
-     * This is intended to be used when desktop mode is part of another animation but isn't, itself,
-     * animating.
-     */
-    public void syncSurfaceState(@NonNull TransitionInfo info,
-            SurfaceControl.Transaction finishTransaction) {
-        // Add rounded corners to freeform windows
-        final TypedArray ta = mContext.obtainStyledAttributes(
-                new int[]{android.R.attr.dialogCornerRadius});
-        final int cornerRadius = ta.getDimensionPixelSize(0, 0);
-        ta.recycle();
-        for (TransitionInfo.Change change: info.getChanges()) {
-            if (change.getTaskInfo().getWindowingMode() == WINDOWING_MODE_FREEFORM) {
-                finishTransaction.setCornerRadius(change.getLeash(), cornerRadius);
-            }
-        }
-    }
-
-    /**
-     * A {@link ContentObserver} for listening to changes to {@link Settings.System#DESKTOP_MODE}
-     */
-    private final class SettingsObserver extends ContentObserver {
-
-        private final Uri mDesktopModeSetting = Settings.System.getUriFor(
-                Settings.System.DESKTOP_MODE);
-
-        private final Context mContext;
-
-        SettingsObserver(Context context, Handler handler) {
-            super(handler);
-            mContext = context;
-        }
-
-        public void observe() {
-            // TODO(b/242867463): listen for setting change for all users
-            mContext.getContentResolver().registerContentObserver(mDesktopModeSetting,
-                    false /* notifyForDescendants */, this /* observer */, UserHandle.USER_CURRENT);
-        }
-
-        @Override
-        public void onChange(boolean selfChange, @Nullable Uri uri) {
-            if (mDesktopModeSetting.equals(uri)) {
-                ProtoLog.d(WM_SHELL_DESKTOP_MODE, "Received update for desktop mode setting");
-                desktopModeSettingChanged();
-            }
-        }
-
-        private void desktopModeSettingChanged() {
-            boolean enabled = DesktopModeStatus.isActive(mContext);
-            updateDesktopModeActive(enabled);
-        }
-    }
-
-    /**
-     * The interface for calls from outside the shell, within the host process.
-     */
-    @ExternalThread
-    private final class DesktopModeImpl implements DesktopMode {
-
-        @Override
-        public void addVisibleTasksListener(
-                DesktopModeTaskRepository.VisibleTasksListener listener,
-                Executor callbackExecutor) {
-            mMainExecutor.execute(() -> {
-                DesktopModeController.this.addVisibleTasksListener(listener, callbackExecutor);
-            });
-        }
-
-        @Override
-        public void addDesktopGestureExclusionRegionListener(Consumer<Region> listener,
-                Executor callbackExecutor) {
-            mMainExecutor.execute(() -> {
-                DesktopModeController.this.addTaskCornerListener(listener, callbackExecutor);
-            });
-        }
-    }
-
-    /**
-     * The interface for calls from outside the host process.
-     */
-    @BinderThread
-    private static class IDesktopModeImpl extends IDesktopMode.Stub
-            implements ExternalInterfaceBinder {
-
-        private DesktopModeController mController;
-
-        IDesktopModeImpl(DesktopModeController controller) {
-            mController = controller;
-        }
-
-        /**
-         * Invalidates this instance, preventing future calls from updating the controller.
-         */
-        @Override
-        public void invalidate() {
-            mController = null;
-        }
-
-        @Override
-        public void showDesktopApps(int displayId) {
-            executeRemoteCallWithTaskPermission(mController, "showDesktopApps",
-                    controller -> controller.showDesktopApps(displayId));
-        }
-
-        @Override
-        public void showDesktopApp(int taskId) throws RemoteException {
-            // TODO
-        }
-
-        @Override
-        public int getVisibleTaskCount(int displayId) throws RemoteException {
-            int[] result = new int[1];
-            executeRemoteCallWithTaskPermission(mController, "getVisibleTaskCount",
-                    controller -> result[0] = controller.getVisibleTaskCount(displayId),
-                    true /* blocking */
-            );
-            return result[0];
-        }
-
-        @Override
-        public void onDesktopSplitSelectAnimComplete(RunningTaskInfo taskInfo) {
-
-        }
-
-        @Override
-        public void stashDesktopApps(int displayId) throws RemoteException {
-            // Stashing of desktop apps not needed. Apps always launch on desktop
-        }
-
-        @Override
-        public void hideStashedDesktopApps(int displayId) throws RemoteException {
-            // Stashing of desktop apps not needed. Apps always launch on desktop
-        }
-
-        @Override
-        public void setTaskListener(IDesktopTaskListener listener) throws RemoteException {
-            // TODO(b/261234402): move visibility from sysui state to listener
-        }
-    }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java
index 517f9f2..7783113 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java
@@ -16,14 +16,7 @@
 
 package com.android.wm.shell.desktopmode;
 
-import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE;
-
-import android.content.Context;
 import android.os.SystemProperties;
-import android.os.UserHandle;
-import android.provider.Settings;
-
-import com.android.internal.protolog.common.ProtoLog;
 
 /**
  * Constants for desktop mode feature
@@ -31,13 +24,7 @@
 public class DesktopModeStatus {
 
     /**
-     * Flag to indicate whether desktop mode is available on the device
-     */
-    private static final boolean IS_SUPPORTED = SystemProperties.getBoolean(
-            "persist.wm.debug.desktop_mode", false);
-
-    /**
-     * Flag to indicate whether desktop mode proto 2 is available on the device
+     * Flag to indicate whether desktop mode proto is available on the device
      */
     private static final boolean IS_PROTO2_ENABLED = SystemProperties.getBoolean(
             "persist.wm.debug.desktop_mode_2", false);
@@ -64,28 +51,13 @@
             "persist.wm.debug.desktop_stashing", false);
 
     /**
-     * Return {@code true} if desktop mode support is enabled
-     */
-    public static boolean isProto1Enabled() {
-        return IS_SUPPORTED;
-    }
-
-    /**
      * Return {@code true} is desktop windowing proto 2 is enabled
      */
-    public static boolean isProto2Enabled() {
+    public static boolean isEnabled() {
         return IS_PROTO2_ENABLED;
     }
 
     /**
-     * Return {@code true} if proto 1 or 2 is enabled.
-     * Can be used to guard logic that is common for both prototypes.
-     */
-    public static boolean isAnyEnabled() {
-        return isProto1Enabled() || isProto2Enabled();
-    }
-
-    /**
      * Return {@code true} if veiled resizing is active. If false, fluid resizing is used.
      */
     public static boolean isVeiledResizeEnabled() {
@@ -99,26 +71,4 @@
     public static boolean isStashingEnabled() {
         return IS_STASHING_ENABLED;
     }
-    /**
-     * Check if desktop mode is active
-     *
-     * @return {@code true} if active
-     */
-    public static boolean isActive(Context context) {
-        if (!isAnyEnabled()) {
-            return false;
-        }
-        if (isProto2Enabled()) {
-            // Desktop mode is always active in prototype 2
-            return true;
-        }
-        try {
-            int result = Settings.System.getIntForUser(context.getContentResolver(),
-                    Settings.System.DESKTOP_MODE, UserHandle.USER_CURRENT);
-            return result != 0;
-        } catch (Exception e) {
-            ProtoLog.e(WM_SHELL_DESKTOP_MODE, "Failed to read DESKTOP_MODE setting %s", e);
-            return false;
-        }
-    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 236dec0..b918c83 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -122,7 +122,7 @@
 
     init {
         desktopMode = DesktopModeImpl()
-        if (DesktopModeStatus.isProto2Enabled()) {
+        if (DesktopModeStatus.isEnabled()) {
             shellInit.addInitCallback({ onInit() }, this)
         }
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
index 22541bbd..a80241e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
@@ -68,7 +68,7 @@
 
     private void onInit() {
         mShellTaskOrganizer.addListenerForType(this, TASK_LISTENER_TYPE_FREEFORM);
-        if (DesktopModeStatus.isAnyEnabled()) {
+        if (DesktopModeStatus.isEnabled()) {
             mShellTaskOrganizer.addFocusListener(this);
         }
     }
@@ -90,7 +90,7 @@
             t.apply();
         }
 
-        if (DesktopModeStatus.isAnyEnabled()) {
+        if (DesktopModeStatus.isEnabled()) {
             mDesktopModeTaskRepository.ifPresent(repository -> {
                 repository.addOrMoveFreeformTaskToTop(taskInfo.taskId);
                 if (taskInfo.isVisible) {
@@ -111,7 +111,7 @@
                 taskInfo.taskId);
         mTasks.remove(taskInfo.taskId);
 
-        if (DesktopModeStatus.isAnyEnabled()) {
+        if (DesktopModeStatus.isEnabled()) {
             mDesktopModeTaskRepository.ifPresent(repository -> {
                 repository.removeFreeformTask(taskInfo.taskId);
                 if (repository.removeActiveTask(taskInfo.taskId)) {
@@ -135,7 +135,7 @@
                 taskInfo.taskId);
         mWindowDecorationViewModel.onTaskInfoChanged(taskInfo);
         state.mTaskInfo = taskInfo;
-        if (DesktopModeStatus.isAnyEnabled()) {
+        if (DesktopModeStatus.isEnabled()) {
             mDesktopModeTaskRepository.ifPresent(repository -> {
                 if (taskInfo.isVisible) {
                     if (repository.addActiveTask(taskInfo.displayId, taskInfo.taskId)) {
@@ -154,7 +154,7 @@
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG,
                 "Freeform Task Focus Changed: #%d focused=%b",
                 taskInfo.taskId, taskInfo.isFocused);
-        if (DesktopModeStatus.isAnyEnabled() && taskInfo.isFocused) {
+        if (DesktopModeStatus.isEnabled() && taskInfo.isFocused) {
             mDesktopModeTaskRepository.ifPresent(repository -> {
                 repository.addOrMoveFreeformTaskToTop(taskInfo.taskId);
             });
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
index e3922d6..018d674 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransition.java
@@ -1059,7 +1059,21 @@
     private void resetPrevPip(@NonNull TransitionInfo.Change prevPipTaskChange,
             @NonNull SurfaceControl.Transaction startTransaction) {
         final SurfaceControl leash = prevPipTaskChange.getLeash();
-        startTransaction.remove(leash);
+        final Rect bounds = prevPipTaskChange.getEndAbsBounds();
+        final Point offset = prevPipTaskChange.getEndRelOffset();
+        bounds.offset(-offset.x, -offset.y);
+
+        startTransaction.setWindowCrop(leash, null);
+        startTransaction.setMatrix(leash, 1, 0, 0, 1);
+        startTransaction.setCornerRadius(leash, 0);
+        startTransaction.setPosition(leash, bounds.left, bounds.top);
+
+        if (mHasFadeOut && prevPipTaskChange.getTaskInfo().isVisible()) {
+            if (mPipAnimationController.getCurrentAnimator() != null) {
+                mPipAnimationController.getCurrentAnimator().cancel();
+            }
+            startTransaction.setAlpha(leash, 1);
+        }
 
         mHasFadeOut = false;
         mCurrentPipTaskToken = null;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index ac142e9..94e1b33 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -340,7 +340,7 @@
                 continue;
             }
 
-            if (DesktopModeStatus.isProto2Enabled() && mDesktopModeTaskRepository.isPresent()
+            if (DesktopModeStatus.isEnabled() && mDesktopModeTaskRepository.isPresent()
                     && mDesktopModeTaskRepository.get().isActiveTask(taskInfo.taskId)) {
                 // Freeform tasks will be added as a separate entry
                 freeformTasks.add(taskInfo);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index 986560b..87ceaa4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -43,7 +43,6 @@
 
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.common.split.SplitScreenUtils;
-import com.android.wm.shell.desktopmode.DesktopModeController;
 import com.android.wm.shell.desktopmode.DesktopModeStatus;
 import com.android.wm.shell.desktopmode.DesktopTasksController;
 import com.android.wm.shell.keyguard.KeyguardTransitionHandler;
@@ -71,7 +70,6 @@
     private RecentsTransitionHandler mRecentsHandler;
     private StageCoordinator mSplitHandler;
     private final KeyguardTransitionHandler mKeyguardHandler;
-    private DesktopModeController mDesktopModeController;
     private DesktopTasksController mDesktopTasksController;
     private UnfoldTransitionHandler mUnfoldHandler;
 
@@ -141,7 +139,6 @@
             @Nullable PipTransitionController pipTransitionController,
             Optional<RecentsTransitionHandler> recentsHandlerOptional,
             KeyguardTransitionHandler keyguardHandler,
-            Optional<DesktopModeController> desktopModeControllerOptional,
             Optional<DesktopTasksController> desktopTasksControllerOptional,
             Optional<UnfoldTransitionHandler> unfoldHandler) {
         mPlayer = player;
@@ -161,7 +158,6 @@
                 if (mRecentsHandler != null) {
                     mRecentsHandler.addMixer(this);
                 }
-                mDesktopModeController = desktopModeControllerOptional.orElse(null);
                 mDesktopTasksController = desktopTasksControllerOptional.orElse(null);
                 mUnfoldHandler = unfoldHandler.orElse(null);
             }, this);
@@ -244,7 +240,7 @@
     @Override
     public Transitions.TransitionHandler handleRecentsRequest(WindowContainerTransaction outWCT) {
         if (mRecentsHandler != null && (mSplitHandler.isSplitScreenVisible()
-                || DesktopModeStatus.isActive(mPlayer.getContext()))) {
+                || DesktopModeStatus.isEnabled())) {
             return this;
         }
         return null;
@@ -259,7 +255,7 @@
                     MixedTransition.TYPE_RECENTS_DURING_SPLIT, transition);
             mixed.mLeftoversHandler = mRecentsHandler;
             mActiveTransitions.add(mixed);
-        } else if (DesktopModeStatus.isActive(mPlayer.getContext())) {
+        } else if (DesktopModeStatus.isEnabled()) {
             ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Got a recents request while "
                     + "desktop mode is active, so treat it as Mixed.");
             final MixedTransition mixed = new MixedTransition(
@@ -666,11 +662,6 @@
         if (!consumed) {
             return false;
         }
-        //Sync desktop mode state (proto 1)
-        if (mDesktopModeController != null) {
-            mDesktopModeController.syncSurfaceState(info, finishTransaction);
-            return true;
-        }
         //Sync desktop mode state (proto 2)
         if (mDesktopTasksController != null) {
             mDesktopTasksController.syncSurfaceState(info, finishTransaction);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 92b44d4..abd2ad4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -69,7 +69,6 @@
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.desktopmode.DesktopModeController;
 import com.android.wm.shell.desktopmode.DesktopModeStatus;
 import com.android.wm.shell.desktopmode.DesktopTasksController;
 import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition;
@@ -102,7 +101,6 @@
     private final Choreographer mMainChoreographer;
     private final DisplayController mDisplayController;
     private final SyncTransactionQueue mSyncQueue;
-    private final Optional<DesktopModeController> mDesktopModeController;
     private final Optional<DesktopTasksController> mDesktopTasksController;
     private boolean mTransitionDragActive;
 
@@ -135,7 +133,6 @@
             ShellController shellController,
             SyncTransactionQueue syncQueue,
             Transitions transitions,
-            Optional<DesktopModeController> desktopModeController,
             Optional<DesktopTasksController> desktopTasksController,
             RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer
     ) {
@@ -149,7 +146,6 @@
                 shellController,
                 syncQueue,
                 transitions,
-                desktopModeController,
                 desktopTasksController,
                 new DesktopModeWindowDecoration.Factory(),
                 new InputMonitorFactory(),
@@ -169,7 +165,6 @@
             ShellController shellController,
             SyncTransactionQueue syncQueue,
             Transitions transitions,
-            Optional<DesktopModeController> desktopModeController,
             Optional<DesktopTasksController> desktopTasksController,
             DesktopModeWindowDecoration.Factory desktopModeWindowDecorFactory,
             InputMonitorFactory inputMonitorFactory,
@@ -185,7 +180,6 @@
         mDisplayController = displayController;
         mSyncQueue = syncQueue;
         mTransitions = transitions;
-        mDesktopModeController = desktopModeController;
         mDesktopTasksController = desktopTasksController;
 
         mDesktopModeWindowDecorFactory = desktopModeWindowDecorFactory;
@@ -214,9 +208,8 @@
             public void onTaskStageChanged(int taskId, int stage, boolean visible) {
                 if (visible) {
                     DesktopModeWindowDecoration decor = mWindowDecorByTaskId.get(taskId);
-                    if (decor != null && DesktopModeStatus.isActive(mContext)
+                    if (decor != null && DesktopModeStatus.isEnabled()
                             && decor.mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
-                        mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(false));
                         mDesktopTasksController.ifPresent(c -> c.moveToSplit(decor.mTaskInfo));
                     }
                 }
@@ -376,7 +369,6 @@
                     decoration.closeHandleMenu();
                 }
             } else if (id == R.id.desktop_button) {
-                mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(true));
                 if (mDesktopTasksController.isPresent()) {
                     final WindowContainerTransaction wct = new WindowContainerTransaction();
                     // App sometimes draws before the insets from WindowDecoration#relayout have
@@ -387,7 +379,6 @@
                 }
                 decoration.closeHandleMenu();
             } else if (id == R.id.fullscreen_button) {
-                mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(false));
                 mDesktopTasksController.ifPresent(c -> c.moveToFullscreen(mTaskId));
                 decoration.closeHandleMenu();
             } else if (id == R.id.split_screen_button) {
@@ -465,7 +456,6 @@
         private void moveTaskToFront(RunningTaskInfo taskInfo) {
             if (!taskInfo.isFocused) {
                 mDesktopTasksController.ifPresent(c -> c.moveTaskToFront(taskInfo));
-                mDesktopModeController.ifPresent(c -> c.moveTaskToFront(taskInfo));
             }
         }
 
@@ -476,15 +466,10 @@
         @Override
         public boolean handleMotionEvent(@Nullable View v, MotionEvent e) {
             final RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
-            if (DesktopModeStatus.isProto2Enabled()
+            if (DesktopModeStatus.isEnabled()
                     && taskInfo.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
                 return false;
             }
-            if (DesktopModeStatus.isProto1Enabled() && mDesktopModeController.isPresent()
-                    && mDesktopModeController.get().getDisplayAreaWindowingMode(taskInfo.displayId)
-                    == WINDOWING_MODE_FULLSCREEN) {
-                return false;
-            }
             if (mGestureDetector.onTouchEvent(e)) {
                 return true;
             }
@@ -634,7 +619,7 @@
      */
     private void handleReceivedMotionEvent(MotionEvent ev, InputMonitor inputMonitor) {
         final DesktopModeWindowDecoration relevantDecor = getRelevantWindowDecor(ev);
-        if (DesktopModeStatus.isProto2Enabled()) {
+        if (DesktopModeStatus.isEnabled()) {
             if (relevantDecor == null
                     || relevantDecor.mTaskInfo.getWindowingMode() != WINDOWING_MODE_FREEFORM
                     || mTransitionDragActive) {
@@ -643,14 +628,10 @@
         }
         handleEventOutsideFocusedCaption(ev, relevantDecor);
         // Prevent status bar from reacting to a caption drag.
-        if (DesktopModeStatus.isProto2Enabled()) {
+        if (DesktopModeStatus.isEnabled()) {
             if (mTransitionDragActive) {
                 inputMonitor.pilferPointers();
             }
-        } else if (DesktopModeStatus.isProto1Enabled()) {
-            if (mTransitionDragActive && !DesktopModeStatus.isActive(mContext)) {
-                inputMonitor.pilferPointers();
-            }
         }
     }
 
@@ -683,7 +664,7 @@
                     mDragToDesktopAnimationStartBounds.set(
                             relevantDecor.mTaskInfo.configuration.windowConfiguration.getBounds());
                     boolean dragFromStatusBarAllowed = false;
-                    if (DesktopModeStatus.isProto2Enabled()) {
+                    if (DesktopModeStatus.isEnabled()) {
                         // In proto2 any full screen or multi-window task can be dragged to
                         // freeform.
                         final int windowingMode = relevantDecor.mTaskInfo.getWindowingMode();
@@ -708,10 +689,8 @@
                     final int statusBarHeight = getStatusBarHeight(
                             relevantDecor.mTaskInfo.displayId);
                     if (ev.getY() > 2 * statusBarHeight) {
-                        if (DesktopModeStatus.isProto2Enabled()) {
+                        if (DesktopModeStatus.isEnabled()) {
                             animateToDesktop(relevantDecor, ev);
-                        } else if (DesktopModeStatus.isProto1Enabled()) {
-                            mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(true));
                         }
                         mMoveToDesktopAnimator = null;
                         return;
@@ -902,7 +881,7 @@
                 && taskInfo.isFocused) {
             return false;
         }
-        return DesktopModeStatus.isProto2Enabled()
+        return DesktopModeStatus.isEnabled()
                 && taskInfo.getWindowingMode() != WINDOWING_MODE_PINNED
                 && taskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD
                 && !taskInfo.configuration.windowConfiguration.isAlwaysOnTop()
@@ -984,13 +963,11 @@
 
         @Override
         public void onTaskCornersChanged(int taskId, Region corner) {
-            mDesktopModeController.ifPresent(d -> d.onTaskCornersChanged(taskId, corner));
             mDesktopTasksController.ifPresent(d -> d.onTaskCornersChanged(taskId, corner));
         }
 
         @Override
         public void onTaskCornersRemoved(int taskId) {
-            mDesktopModeController.ifPresent(d -> d.removeCornersForTask(taskId));
             mDesktopTasksController.ifPresent(d -> d.removeCornersForTask(taskId));
         }
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index a75dce2..3e21c8c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -428,7 +428,7 @@
                 .setOnTouchListener(mOnCaptionTouchListener)
                 .setLayoutId(mRelayoutParams.mLayoutResId)
                 .setCaptionPosition(mRelayoutParams.mCaptionX, mRelayoutParams.mCaptionY)
-                .setWindowingButtonsVisible(DesktopModeStatus.isProto2Enabled())
+                .setWindowingButtonsVisible(DesktopModeStatus.isEnabled())
                 .build();
         mHandleMenu.show();
     }
@@ -549,9 +549,6 @@
     }
 
     private int getDesktopModeWindowDecorLayoutId(int windowingMode) {
-        if (DesktopModeStatus.isProto1Enabled()) {
-            return R.layout.desktop_mode_app_controls_window_decor;
-        }
         return windowingMode == WINDOWING_MODE_FREEFORM
                 ? R.layout.desktop_mode_app_controls_window_decor
                 : R.layout.desktop_mode_focused_window_decor;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java
index ac4a597..ca7cbfd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.java
@@ -236,7 +236,7 @@
             t.setPosition(mAppInfoPill.mWindowSurface,
                     mAppInfoPillPosition.x, mAppInfoPillPosition.y);
             // Only show windowing buttons in proto2. Proto1 uses a system-level mode only.
-            final boolean shouldShowWindowingPill = DesktopModeStatus.isProto2Enabled();
+            final boolean shouldShowWindowingPill = DesktopModeStatus.isEnabled();
             if (shouldShowWindowingPill) {
                 t.setPosition(mWindowingPill.mWindowSurface,
                         mWindowingPillPosition.x, mWindowingPillPosition.y);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
deleted file mode 100644
index 605a762..0000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java
+++ /dev/null
@@ -1,531 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.desktopmode;
-
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOW_CONFIG_BOUNDS;
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.WindowManager.TRANSIT_CHANGE;
-import static android.view.WindowManager.TRANSIT_CLOSE;
-import static android.view.WindowManager.TRANSIT_NONE;
-import static android.view.WindowManager.TRANSIT_OPEN;
-import static android.view.WindowManager.TRANSIT_TO_FRONT;
-import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
-import static com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask;
-import static com.android.wm.shell.desktopmode.DesktopTestHelpers.createFullscreenTask;
-import static com.android.wm.shell.desktopmode.DesktopTestHelpers.createHomeTask;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
-
-import android.app.ActivityManager.RunningTaskInfo;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.IBinder;
-import android.testing.AndroidTestingRunner;
-import android.window.DisplayAreaInfo;
-import android.window.TransitionRequestInfo;
-import android.window.WindowContainerTransaction;
-import android.window.WindowContainerTransaction.Change;
-import android.window.WindowContainerTransaction.HierarchyOp;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.dx.mockito.inline.extended.StaticMockitoSession;
-import com.android.wm.shell.MockToken;
-import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
-import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.ShellTestCase;
-import com.android.wm.shell.TestShellExecutor;
-import com.android.wm.shell.common.ShellExecutor;
-import com.android.wm.shell.sysui.ShellController;
-import com.android.wm.shell.sysui.ShellInit;
-import com.android.wm.shell.transition.Transitions;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-public class DesktopModeControllerTest extends ShellTestCase {
-
-    private static final int SECOND_DISPLAY = 2;
-
-    @Mock
-    private ShellController mShellController;
-    @Mock
-    private ShellTaskOrganizer mShellTaskOrganizer;
-    @Mock
-    private RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
-    @Mock
-    private ShellExecutor mTestExecutor;
-    @Mock
-    private Handler mMockHandler;
-    @Mock
-    private Transitions mTransitions;
-    private DesktopModeController mController;
-    private DesktopModeTaskRepository mDesktopModeTaskRepository;
-    private ShellInit mShellInit;
-    private StaticMockitoSession mMockitoSession;
-
-    @Before
-    public void setUp() {
-        mMockitoSession = mockitoSession().mockStatic(DesktopModeStatus.class).startMocking();
-        when(DesktopModeStatus.isProto1Enabled()).thenReturn(true);
-        when(DesktopModeStatus.isActive(any())).thenReturn(true);
-
-        mShellInit = Mockito.spy(new ShellInit(mTestExecutor));
-
-        mDesktopModeTaskRepository = new DesktopModeTaskRepository();
-
-        mController = createController();
-
-        when(mShellTaskOrganizer.getRunningTasks(anyInt())).thenReturn(new ArrayList<>());
-
-        mShellInit.init();
-        clearInvocations(mShellTaskOrganizer);
-        clearInvocations(mRootTaskDisplayAreaOrganizer);
-        clearInvocations(mTransitions);
-    }
-
-    @After
-    public void tearDown() {
-        mMockitoSession.finishMocking();
-    }
-
-    @Test
-    public void instantiate_addInitCallback() {
-        verify(mShellInit).addInitCallback(any(), any());
-    }
-
-    @Test
-    public void instantiate_flagOff_doNotAddInitCallback() {
-        when(DesktopModeStatus.isProto1Enabled()).thenReturn(false);
-        clearInvocations(mShellInit);
-
-        createController();
-
-        verify(mShellInit, never()).addInitCallback(any(), any());
-    }
-
-    @Test
-    public void testDesktopModeEnabled_rootTdaSetToFreeform() {
-        DisplayAreaInfo displayAreaInfo = createMockDisplayArea();
-
-        mController.updateDesktopModeActive(true);
-        WindowContainerTransaction wct = getDesktopModeSwitchTransaction();
-
-        // 1 change: Root TDA windowing mode
-        assertThat(wct.getChanges().size()).isEqualTo(1);
-        // Verify WCT has a change for setting windowing mode to freeform
-        Change change = wct.getChanges().get(displayAreaInfo.token.asBinder());
-        assertThat(change).isNotNull();
-        assertThat(change.getWindowingMode()).isEqualTo(WINDOWING_MODE_FREEFORM);
-    }
-
-    @Test
-    public void testDesktopModeDisabled_rootTdaSetToFullscreen() {
-        DisplayAreaInfo displayAreaInfo = createMockDisplayArea();
-
-        mController.updateDesktopModeActive(false);
-        WindowContainerTransaction wct = getDesktopModeSwitchTransaction();
-
-        // 1 change: Root TDA windowing mode
-        assertThat(wct.getChanges().size()).isEqualTo(1);
-        // Verify WCT has a change for setting windowing mode to fullscreen
-        Change change = wct.getChanges().get(displayAreaInfo.token.asBinder());
-        assertThat(change).isNotNull();
-        assertThat(change.getWindowingMode()).isEqualTo(WINDOWING_MODE_FULLSCREEN);
-    }
-
-    @Test
-    public void testDesktopModeEnabled_windowingModeCleared() {
-        createMockDisplayArea();
-        RunningTaskInfo freeformTask = createFreeformTask();
-        RunningTaskInfo fullscreenTask = createFullscreenTask();
-        RunningTaskInfo homeTask = createHomeTask();
-        when(mShellTaskOrganizer.getRunningTasks(anyInt())).thenReturn(new ArrayList<>(
-                Arrays.asList(freeformTask, fullscreenTask, homeTask)));
-
-        mController.updateDesktopModeActive(true);
-        WindowContainerTransaction wct = getDesktopModeSwitchTransaction();
-
-        // 2 changes: Root TDA windowing mode and 1 task
-        assertThat(wct.getChanges().size()).isEqualTo(2);
-        // No changes for tasks that are not standard or freeform
-        assertThat(wct.getChanges().get(fullscreenTask.token.asBinder())).isNull();
-        assertThat(wct.getChanges().get(homeTask.token.asBinder())).isNull();
-        // Standard freeform task has windowing mode cleared
-        Change change = wct.getChanges().get(freeformTask.token.asBinder());
-        assertThat(change).isNotNull();
-        assertThat(change.getWindowingMode()).isEqualTo(WINDOWING_MODE_UNDEFINED);
-    }
-
-    @Test
-    public void testDesktopModeDisabled_windowingModeAndBoundsCleared() {
-        createMockDisplayArea();
-        RunningTaskInfo freeformTask = createFreeformTask();
-        RunningTaskInfo fullscreenTask = createFullscreenTask();
-        RunningTaskInfo homeTask = createHomeTask();
-        when(mShellTaskOrganizer.getRunningTasks(anyInt())).thenReturn(new ArrayList<>(
-                Arrays.asList(freeformTask, fullscreenTask, homeTask)));
-
-        mController.updateDesktopModeActive(false);
-        WindowContainerTransaction wct = getDesktopModeSwitchTransaction();
-
-        // 3 changes: Root TDA windowing mode and 2 tasks
-        assertThat(wct.getChanges().size()).isEqualTo(3);
-        // No changes to home task
-        assertThat(wct.getChanges().get(homeTask.token.asBinder())).isNull();
-        // Standard tasks have bounds cleared
-        assertThatBoundsCleared(wct.getChanges().get(freeformTask.token.asBinder()));
-        assertThatBoundsCleared(wct.getChanges().get(fullscreenTask.token.asBinder()));
-        // Freeform standard tasks have windowing mode cleared
-        assertThat(wct.getChanges().get(
-                freeformTask.token.asBinder()).getWindowingMode()).isEqualTo(
-                WINDOWING_MODE_UNDEFINED);
-    }
-
-    @Test
-    public void testDesktopModeEnabled_homeTaskBehindVisibleTask() {
-        createMockDisplayArea();
-        RunningTaskInfo fullscreenTask1 = createFullscreenTask();
-        fullscreenTask1.isVisible = true;
-        RunningTaskInfo fullscreenTask2 = createFullscreenTask();
-        fullscreenTask2.isVisible = false;
-        RunningTaskInfo homeTask = createHomeTask();
-        when(mShellTaskOrganizer.getRunningTasks(anyInt())).thenReturn(new ArrayList<>(
-                Arrays.asList(fullscreenTask1, fullscreenTask2, homeTask)));
-
-        mController.updateDesktopModeActive(true);
-        WindowContainerTransaction wct = getDesktopModeSwitchTransaction();
-
-        // Check that there are hierarchy changes for home task and visible task
-        assertThat(wct.getHierarchyOps()).hasSize(2);
-        // First show home task
-        HierarchyOp op1 = wct.getHierarchyOps().get(0);
-        assertThat(op1.getType()).isEqualTo(HIERARCHY_OP_TYPE_REORDER);
-        assertThat(op1.getContainer()).isEqualTo(homeTask.token.asBinder());
-
-        // Then visible task on top of it
-        HierarchyOp op2 = wct.getHierarchyOps().get(1);
-        assertThat(op2.getType()).isEqualTo(HIERARCHY_OP_TYPE_REORDER);
-        assertThat(op2.getContainer()).isEqualTo(fullscreenTask1.token.asBinder());
-    }
-
-    @Test
-    public void testShowDesktopApps_allAppsInvisible_bringsToFront() {
-        // Set up two active tasks on desktop, task2 is on top of task1.
-        RunningTaskInfo freeformTask1 = createFreeformTask();
-        mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, freeformTask1.taskId);
-        mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(freeformTask1.taskId);
-        mDesktopModeTaskRepository.updateVisibleFreeformTasks(
-                DEFAULT_DISPLAY, freeformTask1.taskId, false /* visible */);
-        RunningTaskInfo freeformTask2 = createFreeformTask();
-        mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, freeformTask2.taskId);
-        mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(freeformTask2.taskId);
-        mDesktopModeTaskRepository.updateVisibleFreeformTasks(
-                DEFAULT_DISPLAY, freeformTask2.taskId, false /* visible */);
-        when(mShellTaskOrganizer.getRunningTaskInfo(freeformTask1.taskId)).thenReturn(
-                freeformTask1);
-        when(mShellTaskOrganizer.getRunningTaskInfo(freeformTask2.taskId)).thenReturn(
-                freeformTask2);
-
-        // Run show desktop apps logic
-        mController.showDesktopApps(DEFAULT_DISPLAY);
-
-        final WindowContainerTransaction wct = getBringAppsToFrontTransaction();
-        // Check wct has reorder calls
-        assertThat(wct.getHierarchyOps()).hasSize(2);
-
-        // Task 1 appeared first, must be first reorder to top.
-        HierarchyOp op1 = wct.getHierarchyOps().get(0);
-        assertThat(op1.getType()).isEqualTo(HIERARCHY_OP_TYPE_REORDER);
-        assertThat(op1.getContainer()).isEqualTo(freeformTask1.token.asBinder());
-
-        // Task 2 appeared last, must be last reorder to top.
-        HierarchyOp op2 = wct.getHierarchyOps().get(1);
-        assertThat(op2.getType()).isEqualTo(HIERARCHY_OP_TYPE_REORDER);
-        assertThat(op2.getContainer()).isEqualTo(freeformTask2.token.asBinder());
-    }
-
-    @Test
-    public void testShowDesktopApps_appsAlreadyVisible_bringsToFront() {
-        final RunningTaskInfo task1 = createFreeformTask();
-        mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, task1.taskId);
-        mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task1.taskId);
-        mDesktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY, task1.taskId,
-                true /* visible */);
-        when(mShellTaskOrganizer.getRunningTaskInfo(task1.taskId)).thenReturn(task1);
-        final RunningTaskInfo task2 = createFreeformTask();
-        mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, task2.taskId);
-        mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task2.taskId);
-        mDesktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY, task2.taskId,
-                true /* visible */);
-        when(mShellTaskOrganizer.getRunningTaskInfo(task2.taskId)).thenReturn(task2);
-
-        mController.showDesktopApps(DEFAULT_DISPLAY);
-
-        final WindowContainerTransaction wct = getBringAppsToFrontTransaction();
-        // Check wct has reorder calls
-        assertThat(wct.getHierarchyOps()).hasSize(2);
-        // Task 1 appeared first, must be first reorder to top.
-        HierarchyOp op1 = wct.getHierarchyOps().get(0);
-        assertThat(op1.getType()).isEqualTo(HIERARCHY_OP_TYPE_REORDER);
-        assertThat(op1.getContainer()).isEqualTo(task1.token.asBinder());
-
-        // Task 2 appeared last, must be last reorder to top.
-        HierarchyOp op2 = wct.getHierarchyOps().get(1);
-        assertThat(op2.getType()).isEqualTo(HIERARCHY_OP_TYPE_REORDER);
-        assertThat(op2.getContainer()).isEqualTo(task2.token.asBinder());
-    }
-
-    @Test
-    public void testShowDesktopApps_someAppsInvisible_reordersAll() {
-        final RunningTaskInfo task1 = createFreeformTask();
-        mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, task1.taskId);
-        mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task1.taskId);
-        mDesktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY, task1.taskId,
-                false /* visible */);
-        when(mShellTaskOrganizer.getRunningTaskInfo(task1.taskId)).thenReturn(task1);
-        final RunningTaskInfo task2 = createFreeformTask();
-        mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, task2.taskId);
-        mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task2.taskId);
-        mDesktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY, task2.taskId,
-                true /* visible */);
-        when(mShellTaskOrganizer.getRunningTaskInfo(task2.taskId)).thenReturn(task2);
-
-        mController.showDesktopApps(DEFAULT_DISPLAY);
-
-        final WindowContainerTransaction wct = getBringAppsToFrontTransaction();
-        // Both tasks should be reordered to top, even if one was already visible.
-        assertThat(wct.getHierarchyOps()).hasSize(2);
-        final HierarchyOp op1 = wct.getHierarchyOps().get(0);
-        assertThat(op1.getType()).isEqualTo(HIERARCHY_OP_TYPE_REORDER);
-        assertThat(op1.getContainer()).isEqualTo(task1.token.asBinder());
-        final HierarchyOp op2 = wct.getHierarchyOps().get(1);
-        assertThat(op2.getType()).isEqualTo(HIERARCHY_OP_TYPE_REORDER);
-        assertThat(op2.getContainer()).isEqualTo(task2.token.asBinder());
-    }
-
-    @Test
-    public void testShowDesktopApps_twoDisplays_bringsToFrontOnlyOneDisplay() {
-        RunningTaskInfo taskDefaultDisplay = createFreeformTask(DEFAULT_DISPLAY);
-        mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, taskDefaultDisplay.taskId);
-        mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(taskDefaultDisplay.taskId);
-        mDesktopModeTaskRepository.updateVisibleFreeformTasks(
-                DEFAULT_DISPLAY, taskDefaultDisplay.taskId, false /* visible */);
-        when(mShellTaskOrganizer.getRunningTaskInfo(taskDefaultDisplay.taskId)).thenReturn(
-                taskDefaultDisplay);
-
-        RunningTaskInfo taskSecondDisplay = createFreeformTask(SECOND_DISPLAY);
-        mDesktopModeTaskRepository.addActiveTask(SECOND_DISPLAY, taskSecondDisplay.taskId);
-        mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(taskSecondDisplay.taskId);
-        mDesktopModeTaskRepository.updateVisibleFreeformTasks(
-                SECOND_DISPLAY, taskSecondDisplay.taskId, false /* visible */);
-        when(mShellTaskOrganizer.getRunningTaskInfo(taskSecondDisplay.taskId)).thenReturn(
-                taskSecondDisplay);
-
-        mController.showDesktopApps(DEFAULT_DISPLAY);
-
-        WindowContainerTransaction wct = getBringAppsToFrontTransaction();
-        assertThat(wct.getHierarchyOps()).hasSize(1);
-        HierarchyOp op = wct.getHierarchyOps().get(0);
-        assertThat(op.getContainer()).isEqualTo(taskDefaultDisplay.token.asBinder());
-    }
-
-    @Test
-    public void testGetVisibleTaskCount_noTasks_returnsZero() {
-        assertThat(mController.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(0);
-    }
-
-    @Test
-    public void testGetVisibleTaskCount_twoTasks_bothVisible_returnsTwo() {
-        RunningTaskInfo task1 = createFreeformTask();
-        mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, task1.taskId);
-        mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task1.taskId);
-        mDesktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY, task1.taskId,
-                true /* visible */);
-
-        RunningTaskInfo task2 = createFreeformTask();
-        mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, task2.taskId);
-        mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task2.taskId);
-        mDesktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY, task2.taskId,
-                true /* visible */);
-
-        assertThat(mController.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(2);
-    }
-
-    @Test
-    public void testGetVisibleTaskCount_twoTasks_oneVisible_returnsOne() {
-        RunningTaskInfo task1 = createFreeformTask();
-        mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, task1.taskId);
-        mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task1.taskId);
-        mDesktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY, task1.taskId,
-                true /* visible */);
-
-        RunningTaskInfo task2 = createFreeformTask();
-        mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, task2.taskId);
-        mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task2.taskId);
-        mDesktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY, task2.taskId,
-                false /* visible */);
-
-        assertThat(mController.getVisibleTaskCount(DEFAULT_DISPLAY)).isEqualTo(1);
-    }
-
-    @Test
-    public void testGetVisibleTaskCount_twoTasksVisibleOnDifferentDisplays_returnsOne() {
-        RunningTaskInfo taskDefaultDisplay = createFreeformTask();
-        mDesktopModeTaskRepository.addActiveTask(DEFAULT_DISPLAY, taskDefaultDisplay.taskId);
-        mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(taskDefaultDisplay.taskId);
-        mDesktopModeTaskRepository.updateVisibleFreeformTasks(DEFAULT_DISPLAY,
-                taskDefaultDisplay.taskId,
-                true /* visible */);
-
-        RunningTaskInfo taskSecondDisplay = createFreeformTask();
-        mDesktopModeTaskRepository.addActiveTask(SECOND_DISPLAY, taskSecondDisplay.taskId);
-        mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(taskSecondDisplay.taskId);
-        mDesktopModeTaskRepository.updateVisibleFreeformTasks(SECOND_DISPLAY,
-                taskSecondDisplay.taskId,
-                true /* visible */);
-
-        assertThat(mController.getVisibleTaskCount(SECOND_DISPLAY)).isEqualTo(1);
-    }
-
-    @Test
-    public void testHandleTransitionRequest_desktopModeNotActive_returnsNull() {
-        when(DesktopModeStatus.isActive(any())).thenReturn(false);
-        WindowContainerTransaction wct = mController.handleRequest(
-                new Binder(),
-                new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, null /* remote */));
-        assertThat(wct).isNull();
-    }
-
-    @Test
-    public void testHandleTransitionRequest_unsupportedTransit_returnsNull() {
-        WindowContainerTransaction wct = mController.handleRequest(
-                new Binder(),
-                new TransitionRequestInfo(TRANSIT_CLOSE, null /* trigger */, null /* remote */));
-        assertThat(wct).isNull();
-    }
-
-    @Test
-    public void testHandleTransitionRequest_notFreeform_returnsNull() {
-        RunningTaskInfo trigger = new RunningTaskInfo();
-        trigger.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
-        WindowContainerTransaction wct = mController.handleRequest(
-                new Binder(),
-                new TransitionRequestInfo(TRANSIT_TO_FRONT, trigger, null /* remote */));
-        assertThat(wct).isNull();
-    }
-
-    @Test
-    public void testHandleTransitionRequest_taskOpen_returnsWct() {
-        RunningTaskInfo trigger = new RunningTaskInfo();
-        trigger.token = new MockToken().token();
-        trigger.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
-        WindowContainerTransaction wct = mController.handleRequest(
-                mock(IBinder.class),
-                new TransitionRequestInfo(TRANSIT_OPEN, trigger, null /* remote */));
-        assertThat(wct).isNotNull();
-    }
-
-    @Test
-    public void testHandleTransitionRequest_taskToFront_returnsWct() {
-        RunningTaskInfo trigger = new RunningTaskInfo();
-        trigger.token = new MockToken().token();
-        trigger.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
-        WindowContainerTransaction wct = mController.handleRequest(
-                mock(IBinder.class),
-                new TransitionRequestInfo(TRANSIT_TO_FRONT, trigger, null /* remote */));
-        assertThat(wct).isNotNull();
-    }
-
-    @Test
-    public void testHandleTransitionRequest_taskOpen_doesNotStartAnotherTransition() {
-        RunningTaskInfo trigger = new RunningTaskInfo();
-        trigger.token = new MockToken().token();
-        trigger.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
-        mController.handleRequest(
-                mock(IBinder.class),
-                new TransitionRequestInfo(TRANSIT_OPEN, trigger, null /* remote */));
-        verifyZeroInteractions(mTransitions);
-    }
-
-    private DesktopModeController createController() {
-        return new DesktopModeController(mContext, mShellInit, mShellController,
-                mShellTaskOrganizer, mRootTaskDisplayAreaOrganizer, mTransitions,
-                mDesktopModeTaskRepository, mMockHandler, new TestShellExecutor());
-    }
-
-    private DisplayAreaInfo createMockDisplayArea() {
-        DisplayAreaInfo displayAreaInfo = new DisplayAreaInfo(new MockToken().token(),
-                mContext.getDisplayId(), 0);
-        when(mRootTaskDisplayAreaOrganizer.getDisplayAreaInfo(mContext.getDisplayId()))
-                .thenReturn(displayAreaInfo);
-        return displayAreaInfo;
-    }
-
-    private WindowContainerTransaction getDesktopModeSwitchTransaction() {
-        ArgumentCaptor<WindowContainerTransaction> arg = ArgumentCaptor.forClass(
-                WindowContainerTransaction.class);
-        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
-            verify(mTransitions).startTransition(eq(TRANSIT_CHANGE), arg.capture(), any());
-        } else {
-            verify(mRootTaskDisplayAreaOrganizer).applyTransaction(arg.capture());
-        }
-        return arg.getValue();
-    }
-
-    private WindowContainerTransaction getBringAppsToFrontTransaction() {
-        final ArgumentCaptor<WindowContainerTransaction> arg = ArgumentCaptor.forClass(
-                WindowContainerTransaction.class);
-        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
-            verify(mTransitions).startTransition(eq(TRANSIT_NONE), arg.capture(), any());
-        } else {
-            verify(mShellTaskOrganizer).applyTransaction(arg.capture());
-        }
-        return arg.getValue();
-    }
-
-    private void assertThatBoundsCleared(Change change) {
-        assertThat((change.getWindowSetMask() & WINDOW_CONFIG_BOUNDS) != 0).isTrue();
-        assertThat(change.getConfiguration().windowConfiguration.getBounds().isEmpty()).isTrue();
-    }
-
-}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index 5d87cf8..be4a287 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -107,7 +107,7 @@
     @Before
     fun setUp() {
         mockitoSession = mockitoSession().mockStatic(DesktopModeStatus::class.java).startMocking()
-        whenever(DesktopModeStatus.isProto2Enabled()).thenReturn(true)
+        whenever(DesktopModeStatus.isEnabled()).thenReturn(true)
 
         shellInit = Mockito.spy(ShellInit(testExecutor))
         desktopModeTaskRepository = DesktopModeTaskRepository()
@@ -154,7 +154,7 @@
 
     @Test
     fun instantiate_flagOff_doNotAddInitCallback() {
-        whenever(DesktopModeStatus.isProto2Enabled()).thenReturn(false)
+        whenever(DesktopModeStatus.isEnabled()).thenReturn(false)
         clearInvocations(shellInit)
 
         createController()
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
index 9e9e1ca..40ce785 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
@@ -257,7 +257,7 @@
     public void testGetRecentTasks_hasActiveDesktopTasks_proto2Enabled_groupFreeformTasks() {
         StaticMockitoSession mockitoSession = mockitoSession().mockStatic(
                 DesktopModeStatus.class).startMocking();
-        when(DesktopModeStatus.isProto2Enabled()).thenReturn(true);
+        when(DesktopModeStatus.isEnabled()).thenReturn(true);
 
         ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
         ActivityManager.RecentTaskInfo t2 = makeTaskInfo(2);
@@ -297,7 +297,7 @@
     public void testGetRecentTasks_hasActiveDesktopTasks_proto2Disabled_doNotGroupFreeformTasks() {
         StaticMockitoSession mockitoSession = mockitoSession().mockStatic(
                 DesktopModeStatus.class).startMocking();
-        when(DesktopModeStatus.isProto2Enabled()).thenReturn(false);
+        when(DesktopModeStatus.isEnabled()).thenReturn(false);
 
         ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
         ActivityManager.RecentTaskInfo t2 = makeTaskInfo(2);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java
index 7f0465a..d8afe68 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.java
@@ -55,7 +55,6 @@
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.SyncTransactionQueue;
-import com.android.wm.shell.desktopmode.DesktopModeController;
 import com.android.wm.shell.desktopmode.DesktopTasksController;
 import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
@@ -88,7 +87,6 @@
     @Mock private DisplayController mDisplayController;
     @Mock private DisplayLayout mDisplayLayout;
     @Mock private SyncTransactionQueue mSyncQueue;
-    @Mock private DesktopModeController mDesktopModeController;
     @Mock private DesktopTasksController mDesktopTasksController;
     @Mock private InputMonitor mInputMonitor;
     @Mock private InputManager mInputManager;
@@ -121,7 +119,6 @@
                         mShellController,
                         mSyncQueue,
                         mTransitions,
-                        Optional.of(mDesktopModeController),
                         Optional.of(mDesktopTasksController),
                         mDesktopModeWindowDecorFactory,
                         mMockInputMonitorFactory,
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index 0eb657a..fd3e5a2 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -709,11 +709,9 @@
     /**
      * Returns the Mean Sea Level altitude of this location in meters.
      *
-     * @throws IllegalStateException if {@link #hasMslAltitude()} is false.
+     * <p>This is only valid if {@link #hasMslAltitude()} is true.
      */
     public @FloatRange double getMslAltitudeMeters() {
-        Preconditions.checkState(hasMslAltitude(),
-                "The Mean Sea Level altitude of this location is not set.");
         return mMslAltitudeMeters;
     }
 
@@ -744,11 +742,9 @@
      * percentile confidence level. This means that there is 68% chance that the true Mean Sea Level
      * altitude of this location falls within {@link #getMslAltitudeMeters()} +/- this uncertainty.
      *
-     * @throws IllegalStateException if {@link #hasMslAltitudeAccuracy()} is false.
+     * <p>This is only valid if {@link #hasMslAltitudeAccuracy()} is true.
      */
     public @FloatRange(from = 0.0) float getMslAltitudeAccuracyMeters() {
-        Preconditions.checkState(hasMslAltitudeAccuracy(),
-                "The Mean Sea Level altitude accuracy of this location is not set.");
         return mMslAltitudeAccuracyMeters;
     }
 
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 0acce03..ec24ab7 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -954,9 +954,6 @@
     <!-- UI debug setting: enable freeform window support summary [CHAR LIMIT=150] -->
     <string name="enable_freeform_support_summary">Enable support for experimental freeform windows.</string>
 
-    <!-- UI debug setting: enable desktop mode [CHAR LIMIT=25] -->
-    <string name="desktop_mode">Desktop mode</string>
-
     <!-- Local (desktop) backup password menu title [CHAR LIMIT=25] -->
     <string name="local_backup_password_title">Desktop backup password</string>
     <!-- Summary text of the "local backup password" setting when the user has not supplied a password -->
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 92f65d6..c0f6231 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -98,7 +98,6 @@
                     Settings.System.VOLUME_VOICE, // deprecated since API 2?
                     Settings.System.WHEN_TO_MAKE_WIFI_CALLS, // bug?
                     Settings.System.WINDOW_ORIENTATION_LISTENER_LOG, // used for debugging only
-                    Settings.System.DESKTOP_MODE, // developer setting for internal prototyping
                     Settings.System.MIN_REFRESH_RATE, // depends on hardware capabilities
                     Settings.System.PEAK_REFRESH_RATE, // depends on hardware capabilities
                     Settings.System.SCREEN_BRIGHTNESS_FLOAT,
diff --git a/packages/SystemUI/animation/Android.bp b/packages/SystemUI/animation/Android.bp
index 8eb012d..6f53b42 100644
--- a/packages/SystemUI/animation/Android.bp
+++ b/packages/SystemUI/animation/Android.bp
@@ -68,5 +68,6 @@
     kotlincflags: ["-Xjvm-default=all"],
 
     // sdk_version must be specified, otherwise it compiles against private APIs.
+    min_sdk_version: "33",
     sdk_version: "current",
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
index b3b44cb..463253b 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
@@ -102,17 +102,19 @@
     longPressViewModel: KeyguardLongPressViewModel,
     modifier: Modifier = Modifier,
 ) {
-    var settingsMenu: View? = null
+    fun findSettingsMenu(): View {
+        return viewProvider().requireViewById(R.id.keyguard_settings_button)
+    }
 
     Box(
         modifier = modifier,
     ) {
         LongPressSurface(
             viewModel = longPressViewModel,
-            isSettingsMenuVisible = { settingsMenu?.isVisible == true },
+            isSettingsMenuVisible = { findSettingsMenu().isVisible },
             settingsMenuBounds = {
                 val bounds = android.graphics.Rect()
-                settingsMenu?.getHitRect(bounds)
+                findSettingsMenu().getHitRect(bounds)
                 bounds.toComposeRect()
             },
             modifier = Modifier.fillMaxSize(),
@@ -124,12 +126,8 @@
                 // Remove the KeyguardRootView from any parent it might already have in legacy code
                 // just in case (a view can't have two parents).
                 (keyguardRootView.parent as? ViewGroup)?.removeView(keyguardRootView)
-                settingsMenu = keyguardRootView.requireViewById(R.id.keyguard_settings_button)
                 keyguardRootView
             },
-            update = { keyguardRootView ->
-                keyguardRootView.requireViewById<View>(R.id.lock_icon_view)
-            },
             modifier = Modifier.fillMaxSize(),
         )
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java b/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java
index 56c0953..5f33ef9 100644
--- a/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java
+++ b/packages/SystemUI/src/com/android/keyguard/PinShapeNonHintingView.java
@@ -61,7 +61,7 @@
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         super.onLayout(changed, l, t, r, b);
-        if (getChildCount() > 0) {
+        if (getChildCount() > 2) {
             View firstChild = getChildAt(0);
             boolean isVisible = firstChild.getLocalVisibleRect(mFirstChildVisibleRect);
             boolean clipped = mFirstChildVisibleRect.left > 0
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerScope.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerScope.java
index 8dbe5e0..d59f51f 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerScope.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerScope.java
@@ -24,7 +24,7 @@
 import javax.inject.Scope;
 
 /**
- * Scope annotation for singleton items within the CentralSurfacesComponent.
+ * Scope annotation for singleton items within the {@link KeyguardBouncerComponent}.
  */
 @Documented
 @Retention(RUNTIME)
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewScope.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewScope.java
index f498ef3..394d63171 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewScope.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewScope.java
@@ -24,7 +24,7 @@
 import javax.inject.Scope;
 
 /**
- * Scope annotation for singleton items within the CentralSurfacesComponent.
+ * Scope annotation for singleton items within the {@link KeyguardStatusBarViewComponent}.
  */
 @Documented
 @Retention(RUNTIME)
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewScope.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewScope.java
index aeae8e3..6c2c9f2 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewScope.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewScope.java
@@ -24,7 +24,7 @@
 import javax.inject.Scope;
 
 /**
- * Scope annotation for singleton items within the CentralSurfacesComponent.
+ * Scope annotation for singleton items within the {@link KeyguardStatusViewComponent}.
  */
 @Documented
 @Retention(RUNTIME)
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
index 3562477..968c10e 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/ReferenceSystemUIModule.java
@@ -57,6 +57,7 @@
 import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragmentStartableModule;
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
 import com.android.systemui.statusbar.policy.AospPolicyModule;
 import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -95,6 +96,7 @@
 @Module(includes = {
         AospPolicyModule.class,
         BatterySaverModule.class,
+        CollapsedStatusBarFragmentStartableModule.class,
         GestureModule.class,
         MediaModule.class,
         MultiUserUtilsModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index ade7684..96ec654 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -109,7 +109,6 @@
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.phone.LetterboxModule;
 import com.android.systemui.statusbar.phone.NotificationIconAreaControllerModule;
-import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
 import com.android.systemui.statusbar.pipeline.dagger.StatusBarPipelineModule;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -219,7 +218,6 @@
             WalletModule.class
         },
         subcomponents = {
-            CentralSurfacesComponent.class,
             ComplicationComponent.class,
             NavigationBarComponent.class,
             NotificationRowComponent.class,
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 907e106..0fb1b48 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -210,7 +210,8 @@
 
     /** Inflate and bind views upon emitting a blueprint value . */
     // TODO(b/297365780): Tracking Bug
-    @JvmField val LAZY_INFLATE_KEYGUARD = unreleasedFlag("lazy_inflate_keyguard")
+    @JvmField
+    val LAZY_INFLATE_KEYGUARD = unreleasedFlag("lazy_inflate_keyguard", teamfood = true)
 
     /** Enables UI updates for AI wallpapers in the wallpaper picker. */
     // TODO(b/267722622): Tracking Bug
@@ -500,11 +501,6 @@
 
     @Keep
     @JvmField
-    val WM_DESKTOP_WINDOWING =
-        sysPropBooleanFlag("persist.wm.debug.desktop_mode", default = false)
-
-    @Keep
-    @JvmField
     val WM_CAPTION_ON_SHELL =
         sysPropBooleanFlag("persist.wm.debug.caption_on_shell", default = true)
 
@@ -772,7 +768,7 @@
 
     /** Enable the share wifi button in Quick Settings internet dialog. */
     @JvmField
-    val SHARE_WIFI_QS_BUTTON = unreleasedFlag("share_wifi_qs_button")
+    val SHARE_WIFI_QS_BUTTON = unreleasedFlag("share_wifi_qs_button", teamfood = true)
 
     /** Enable haptic slider component in the brightness slider */
     @JvmField
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
index 2814732..8b0b0ae 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt
@@ -78,6 +78,22 @@
                     }
 
                     if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
+                        launch { viewModel.alpha.collect { alpha -> view.alpha = alpha } }
+                    }
+
+                    if (featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
+                        launch {
+                            viewModel.translationY.collect {
+                                val statusView =
+                                    view.requireViewById<View>(R.id.keyguard_status_view)
+                                statusView.translationY = it
+                            }
+                        }
+                    }
+                }
+
+                repeatOnLifecycle(Lifecycle.State.STARTED) {
+                    if (featureFlags.isEnabled(Flags.MIGRATE_SPLIT_KEYGUARD_BOTTOM_AREA)) {
                         launch {
                             viewModel.keyguardRootViewVisibilityState.collect { visibilityState ->
                                 view.animate().cancel()
@@ -111,18 +127,6 @@
                                 }
                             }
                         }
-
-                        launch { viewModel.alpha.collect { alpha -> view.alpha = alpha } }
-                    }
-
-                    if (featureFlags.isEnabled(Flags.MIGRATE_KEYGUARD_STATUS_VIEW)) {
-                        launch {
-                            viewModel.translationY.collect {
-                                val statusView =
-                                    view.requireViewById<View>(R.id.keyguard_status_view)
-                                statusView.translationY = it
-                            }
-                        }
                     }
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandler.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandler.kt
index bbb61b4..ec0c40e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandler.kt
@@ -26,6 +26,7 @@
 import androidx.core.view.GestureDetectorCompat
 import androidx.dynamicanimation.animation.FloatPropertyCompat
 import androidx.dynamicanimation.animation.SpringForce
+import com.android.internal.annotations.VisibleForTesting
 import com.android.settingslib.Utils
 import com.android.systemui.Gefingerpoken
 import com.android.systemui.R
@@ -146,7 +147,8 @@
         }
 
     /** The touch listener for the scroll view */
-    private val touchListener =
+    @VisibleForTesting
+    val touchListener =
         object : Gefingerpoken {
             override fun onTouchEvent(motionEvent: MotionEvent?) = onTouch(motionEvent!!)
             override fun onInterceptTouchEvent(ev: MotionEvent?) = onInterceptTouch(ev!!)
@@ -279,15 +281,14 @@
         } else if (isUp || motionEvent.action == MotionEvent.ACTION_CANCEL) {
             // It's an up and the fling didn't take it above
             val relativePos = scrollView.relativeScrollX % playerWidthPlusPadding
-            val scrollXAmount: Int
-            if (relativePos > playerWidthPlusPadding / 2) {
-                scrollXAmount = playerWidthPlusPadding - relativePos
-            } else {
-                scrollXAmount = -1 * relativePos
-            }
+            val scrollXAmount: Int =
+                if (isRtl xor (relativePos > playerWidthPlusPadding / 2)) {
+                    playerWidthPlusPadding - relativePos
+                } else {
+                    -1 * relativePos
+                }
             if (scrollXAmount != 0) {
-                val dx = if (isRtl) -scrollXAmount else scrollXAmount
-                val newScrollX = scrollView.relativeScrollX + dx
+                val newScrollX = scrollView.relativeScrollX + scrollXAmount
                 // Delay the scrolling since scrollView calls springback which cancels
                 // the animation again..
                 mainExecutor.execute { scrollView.smoothScrollTo(newScrollX, scrollView.scrollY) }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt
index 2ad71e7..80274bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializer.kt
@@ -27,6 +27,7 @@
 import com.android.systemui.statusbar.window.StatusBarWindowController
 import java.lang.IllegalStateException
 import javax.inject.Inject
+import javax.inject.Provider
 
 /**
  * Responsible for creating the status bar window and initializing the root components of that
@@ -35,6 +36,7 @@
 @SysUISingleton
 class StatusBarInitializer @Inject constructor(
     private val windowController: StatusBarWindowController,
+    private val collapsedStatusBarFragmentProvider: Provider<CollapsedStatusBarFragment>,
     private val creationListeners: Set<@JvmSuppressWildcards OnStatusBarViewInitializedListener>,
 ) {
 
@@ -43,11 +45,9 @@
     /**
      * Creates the status bar window and root views, and initializes the component.
      *
-     * TODO(b/277762009): Inject StatusBarFragmentCreator and make this class a CoreStartable.
+     * TODO(b/277764509): Initialize the status bar via [CoreStartable#start].
      */
-    fun initializeStatusBar(
-        statusBarFragmentCreator: () -> CollapsedStatusBarFragment,
-    ) {
+    fun initializeStatusBar() {
         windowController.fragmentHostManager.addTagListener(
                 CollapsedStatusBarFragment.TAG,
                 object : FragmentHostManager.FragmentListener {
@@ -67,11 +67,14 @@
                     override fun onFragmentViewDestroyed(tag: String?, fragment: Fragment?) {
                         // nop
                     }
-                }).fragmentManager
+                }
+        ).fragmentManager
                 .beginTransaction()
-                .replace(R.id.status_bar_container,
-                        statusBarFragmentCreator.invoke(),
-                        CollapsedStatusBarFragment.TAG)
+                .replace(
+                    R.id.status_bar_container,
+                    collapsedStatusBarFragmentProvider.get(),
+                    CollapsedStatusBarFragment.TAG
+                )
                 .commit()
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
index 5c2f9a8..62a0d13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
@@ -39,10 +39,7 @@
 
     override fun attach(pipeline: NotifPipeline) {
         pipeline.addOnAfterRenderListListener(::onAfterRenderList)
-        // TODO(b/282865576): This has an issue where it makes changes to some groups without
-        // notifying listeners. To be fixed in QPR, but for now let's comment it out to avoid the
-        // group expansion bug.
-        // groupExpansionManagerImpl.attach(pipeline)
+        groupExpansionManagerImpl.attach(pipeline)
     }
 
     fun onAfterRenderList(entries: List<ListEntry>, controller: NotifStackController) =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java
index 46af03a..eb31bd3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java
@@ -67,18 +67,29 @@
      * Cleanup entries from mExpandedGroups that no longer exist in the pipeline.
      */
     private final OnBeforeRenderListListener mNotifTracker = (entries) -> {
+        if (mExpandedGroups.isEmpty()) {
+            return; // nothing to do
+        }
+
         final Set<NotificationEntry> renderingSummaries = new HashSet<>();
         for (ListEntry entry : entries) {
             if (entry instanceof GroupEntry) {
                 renderingSummaries.add(entry.getRepresentativeEntry());
             }
         }
-        mExpandedGroups.removeIf(expandedGroup -> !renderingSummaries.contains(expandedGroup));
+
+        // If a group is in mExpandedGroups but not in the pipeline entries, collapse it.
+        final var groupsToRemove = setDifference(mExpandedGroups, renderingSummaries);
+        for (NotificationEntry entry : groupsToRemove) {
+            setGroupExpanded(entry, false);
+        }
     };
 
     public void attach(NotifPipeline pipeline) {
-        mDumpManager.registerDumpable(this);
-        pipeline.addOnBeforeRenderListListener(mNotifTracker);
+        if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE)) {
+            mDumpManager.registerDumpable(this);
+            pipeline.addOnBeforeRenderListListener(mNotifTracker);
+        }
     }
 
     @Override
@@ -134,4 +145,27 @@
             listener.onGroupExpansionChange(entry.getRow(), expanded);
         }
     }
+
+    /**
+     * Utility method to compute the difference between two sets of NotificationEntry. Unfortunately
+     * {@code Sets.difference} from Guava is not available in this codebase.
+     */
+    @NonNull
+    private Set<NotificationEntry> setDifference(Set<NotificationEntry> set1,
+            Set<NotificationEntry> set2) {
+        if (set1 == null || set1.isEmpty()) {
+            return new HashSet<>();
+        }
+        if (set2 == null || set2.isEmpty()) {
+            return new HashSet<>(set1);
+        }
+
+        final Set<NotificationEntry> difference = new HashSet<>();
+        for (NotificationEntry e : set1) {
+            if (!set2.contains(e)) {
+                difference.add(e);
+            }
+        }
+        return difference;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManager.java
index b9c8f72..c33e8ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManager.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.notification.collection.render;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 
 import com.android.systemui.statusbar.notification.collection.ListEntry;
@@ -31,13 +32,14 @@
      * @return whether a given notification is a top level entry or is the summary in a group which
      * has children
      */
-    boolean isGroupSummary(NotificationEntry entry);
+    boolean isGroupSummary(@NonNull NotificationEntry entry);
 
     /**
      * Get the summary of a specified status bar notification. For an isolated notification this
      * returns itself.
      */
-    NotificationEntry getGroupSummary(NotificationEntry entry);
+    @Nullable
+    NotificationEntry getGroupSummary(@NonNull NotificationEntry entry);
 
     /**
      * Similar to {@link #getGroupSummary(NotificationEntry)} but doesn't get the visual summary
@@ -46,19 +48,20 @@
      * TODO: remove this when migrating to the new pipeline, this is taken care of in the
      * dismissal logic built into NotifCollection
      */
-    default NotificationEntry getLogicalGroupSummary(NotificationEntry entry) {
+    @Nullable
+    default NotificationEntry getLogicalGroupSummary(@NonNull NotificationEntry entry) {
         return getGroupSummary(entry);
     }
 
     /**
      * @return whether a given notification is a child in a group
      */
-    boolean isChildInGroup(NotificationEntry entry);
+    boolean isChildInGroup(@NonNull NotificationEntry entry);
 
     /**
      * Whether this is the only child in a group
      */
-    boolean isOnlyChildInGroup(NotificationEntry entry);
+    boolean isOnlyChildInGroup(@NonNull NotificationEntry entry);
 
     /**
      * Get the children that are in the summary's group, not including those isolated.
@@ -67,5 +70,5 @@
      * @return list of the children
      */
     @Nullable
-    List<NotificationEntry> getChildren(ListEntry summary);
+    List<NotificationEntry> getChildren(@NonNull ListEntry summary);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java
index e784ec6..a6b855f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java
@@ -18,40 +18,65 @@
 
 import static com.android.systemui.statusbar.notification.collection.GroupEntry.ROOT_ENTRY;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.statusbar.notification.collection.GroupEntry;
 import com.android.systemui.statusbar.notification.collection.ListEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
 import java.util.List;
 
+import javax.inject.Inject;
+
 /**
  * ShadeListBuilder groups notifications from system server. This manager translates
  * ShadeListBuilder's method of grouping to be used within SystemUI.
  */
+@SysUISingleton
 public class GroupMembershipManagerImpl implements GroupMembershipManager {
-    @Override
-    public boolean isGroupSummary(NotificationEntry entry) {
-        return getGroupSummary(entry) == entry;
+    FeatureFlags mFeatureFlags;
+
+    @Inject
+    public GroupMembershipManagerImpl(FeatureFlags featureFlags) {
+        mFeatureFlags = featureFlags;
     }
 
     @Override
-    public NotificationEntry getGroupSummary(NotificationEntry entry) {
-        if (isEntryTopLevel(entry) || entry.getParent() == null) {
-            return null;
+    public boolean isGroupSummary(@NonNull NotificationEntry entry) {
+        return getGroupSummary(entry) == entry;
+    }
+
+    @Nullable
+    @Override
+    public NotificationEntry getGroupSummary(@NonNull NotificationEntry entry) {
+        if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE)) {
+            if (!isChildInGroup(entry)) {
+                return entry.getRepresentativeEntry();
+            }
+        } else {
+            if (isEntryTopLevel(entry) || entry.getParent() == null) {
+                return null;
+            }
         }
 
         return entry.getParent().getRepresentativeEntry();
     }
 
     @Override
-    public boolean isChildInGroup(NotificationEntry entry) {
-        return !isEntryTopLevel(entry);
+    public boolean isChildInGroup(@NonNull NotificationEntry entry) {
+        if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE)) {
+            return !isEntryTopLevel(entry) && entry.getParent() != null;
+        } else {
+            return !isEntryTopLevel(entry);
+        }
     }
 
     @Override
-    public boolean isOnlyChildInGroup(NotificationEntry entry) {
+    public boolean isOnlyChildInGroup(@NonNull NotificationEntry entry) {
         if (entry.getParent() == null) {
             return false;
         }
@@ -61,20 +86,24 @@
 
     @Nullable
     @Override
-    public List<NotificationEntry> getChildren(ListEntry entry) {
+    public List<NotificationEntry> getChildren(@NonNull ListEntry entry) {
         if (entry instanceof GroupEntry) {
             return ((GroupEntry) entry).getChildren();
         }
 
-        if (isGroupSummary(entry.getRepresentativeEntry())) {
+        NotificationEntry representativeEntry = entry.getRepresentativeEntry();
+        if (representativeEntry != null && isGroupSummary(representativeEntry)) {
             // maybe we were actually passed the summary
-            return entry.getRepresentativeEntry().getParent().getChildren();
+            GroupEntry parent = representativeEntry.getParent();
+            if (parent != null) {
+                return parent.getChildren();
+            }
         }
 
         return null;
     }
 
-    private boolean isEntryTopLevel(NotificationEntry entry) {
+    private boolean isEntryTopLevel(@NonNull NotificationEntry entry) {
         return entry.getParent() == ROOT_ENTRY;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index 09be41b..5664a2a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -167,11 +167,8 @@
     }
 
     /** Provides an instance of {@link GroupMembershipManager} */
-    @SysUISingleton
-    @Provides
-    static GroupMembershipManager provideGroupMembershipManager() {
-        return new GroupMembershipManagerImpl();
-    }
+    @Binds
+    GroupMembershipManager provideGroupMembershipManager(GroupMembershipManagerImpl impl);
 
     /** Provides an instance of {@link GroupExpansionManager} */
     @Binds
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index d2034d7..8d2a63e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -276,14 +276,16 @@
         }
     }
 
-    @GuardedBy("mDozingLock")
     public void startNotificationLogging() {
         if (!mLogging) {
             mLogging = true;
             if (DEBUG) {
                 Log.i(TAG, "startNotificationLogging");
             }
-            boolean lockscreen = mLockscreen != null && mLockscreen;
+            boolean lockscreen;
+            synchronized (mDozingLock) {
+                lockscreen = mLockscreen != null && mLockscreen;
+            }
             mNotificationPanelLogger.logPanelShown(lockscreen, getVisibleNotifications());
             mListContainer.setChildLocationsChangedListener(this::onChildLocationsChanged);
             // Sometimes, the transition from lockscreenOrShadeVisible=false ->
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
index 0ff1a95..67c0c94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -44,7 +44,6 @@
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 import com.android.systemui.qs.QSPanelController;
 import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
-import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.util.Compile;
 
@@ -183,8 +182,6 @@
         return contextForUser.getPackageManager();
     }
 
-    void start();
-
     boolean updateIsKeyguard();
 
     boolean updateIsKeyguard(boolean forceStateChange);
@@ -200,8 +197,6 @@
 
     void onKeyguardViewManagerStatesUpdated();
 
-    NotificationPresenter getPresenter();
-
     /**
      * Used to dispatch initial touch events before crossing the threshold to pull down the
      * notification shade. After that, since the launcher window is set to slippery, input
@@ -220,8 +215,6 @@
     /** */
     boolean getCommandQueuePanelsEnabled();
 
-    BiometricUnlockController getBiometricUnlockController();
-
     void showWirelessChargingAnimation(int batteryLevel);
 
     void checkBarModes();
@@ -230,9 +223,6 @@
 
     void setInteracting(int barWindow, boolean interacting);
 
-    @Override
-    void dump(PrintWriter pwOriginal, String[] args);
-
     /** @deprecated Use {@link DisplayMetricsRepository} instead. */
     @Deprecated
     float getDisplayWidth();
@@ -281,8 +271,6 @@
 
     void setBouncerShowing(boolean bouncerShowing);
 
-    int getWakefulnessState();
-
     boolean isScreenFullyOff();
 
     void showScreenPinningRequest(int taskId, boolean allowCancel);
@@ -323,8 +311,6 @@
 
     boolean isBouncerShowingOverDream();
 
-    boolean isKeyguardSecure();
-
     void updateNotificationPanelTouchState();
 
     int getRotation();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt
index 37038a3..98ba6d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesEmptyImpl.kt
@@ -23,9 +23,7 @@
 import com.android.systemui.navigationbar.NavigationBarView
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction
 import com.android.systemui.qs.QSPanelController
-import com.android.systemui.statusbar.NotificationPresenter
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
-import java.io.PrintWriter
 
 /**
  * Empty implementation of [CentralSurfaces] for variants only need to override portions of the
@@ -41,15 +39,12 @@
     override fun getKeyguardMessageArea(): AuthKeyguardMessageArea? = null
     override fun isLaunchingActivityOverLockscreen() = false
     override fun onKeyguardViewManagerStatesUpdated() {}
-    override fun getPresenter(): NotificationPresenter? = null
     override fun onInputFocusTransfer(start: Boolean, cancel: Boolean, velocity: Float) {}
     override fun getCommandQueuePanelsEnabled() = false
-    override fun getBiometricUnlockController(): BiometricUnlockController? = null
     override fun showWirelessChargingAnimation(batteryLevel: Int) {}
     override fun checkBarModes() {}
     override fun updateBubblesVisibility() {}
     override fun setInteracting(barWindow: Int, interacting: Boolean) {}
-    override fun dump(pwOriginal: PrintWriter, args: Array<String>) {}
     override fun getDisplayWidth() = 0f
     override fun getDisplayHeight() = 0f
     override fun showKeyguard() {}
@@ -77,7 +72,6 @@
     override fun showPinningEnterExitToast(entering: Boolean) {}
     override fun showPinningEscapeToast() {}
     override fun setBouncerShowing(bouncerShowing: Boolean) {}
-    override fun getWakefulnessState() = 0
     override fun isScreenFullyOff() = false
     override fun showScreenPinningRequest(taskId: Int, allowCancel: Boolean) {}
     override fun getEmergencyActionIntent(): Intent? = null
@@ -95,7 +89,6 @@
     override fun isBouncerShowing() = false
     override fun isBouncerShowingScrimmed() = false
     override fun isBouncerShowingOverDream() = false
-    override fun isKeyguardSecure() = false
     override fun updateNotificationPanelTouchState() {}
     override fun getRotation() = 0
     override fun setBarStateForTest(state: Int) {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 8cdf7d8..0277a36 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -222,9 +222,7 @@
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
-import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
 import com.android.systemui.statusbar.phone.dagger.StatusBarPhoneModule;
-import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
 import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.BrightnessMirrorController;
@@ -454,7 +452,6 @@
             mNotificationShadeWindowViewControllerLazy;
     private final DozeParameters mDozeParameters;
     private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
-    private final CentralSurfacesComponent.Factory mCentralSurfacesComponentFactory;
     private final PluginManager mPluginManager;
     private final ShadeController mShadeController;
     private final WindowRootViewVisibilityInteractor mWindowRootViewVisibilityInteractor;
@@ -500,8 +497,6 @@
     private final Provider<FingerprintManager> mFingerprintManager;
     private final ActivityStarter mActivityStarter;
 
-    private CentralSurfacesComponent mCentralSurfacesComponent;
-
     /** @see android.view.WindowInsetsController#setSystemBarsAppearance(int, int) */
     private @Appearance int mAppearance;
 
@@ -702,7 +697,6 @@
             DozeScrimController dozeScrimController,
             VolumeComponent volumeComponent,
             CommandQueue commandQueue,
-            CentralSurfacesComponent.Factory centralSurfacesComponentFactory,
             Lazy<CentralSurfacesCommandQueueCallbacks> commandQueueCallbacksLazy,
             PluginManager pluginManager,
             ShadeController shadeController,
@@ -813,7 +807,6 @@
         mNotificationShadeDepthControllerLazy = notificationShadeDepthControllerLazy;
         mVolumeComponent = volumeComponent;
         mCommandQueue = commandQueue;
-        mCentralSurfacesComponentFactory = centralSurfacesComponentFactory;
         mCommandQueueCallbacksLazy = commandQueueCallbacksLazy;
         mPluginManager = pluginManager;
         mShadeController = shadeController;
@@ -1193,10 +1186,15 @@
         updateResources();
         updateTheme();
 
-        inflateStatusBarWindow();
+        setUpShade();
         getNotificationShadeWindowView().setOnTouchListener(getStatusBarWindowTouchListener());
         mWallpaperController.setRootView(getNotificationShadeWindowView());
 
+        mDemoModeController.addCallback(mDemoModeCallback);
+
+        mCommandQueueCallbacks = mCommandQueueCallbacksLazy.get();
+        mCommandQueue.addCallback(mCommandQueueCallbacks);
+
         // TODO: Deal with the ugliness that comes from having some of the status bar broken out
         // into fragments, but the rest here, it leaves some awkward lifecycle and whatnot.
         if (!mFeatureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) {
@@ -1227,8 +1225,7 @@
                     setBouncerShowingForStatusBarComponents(mBouncerShowing);
                     checkBarModes();
                 });
-        mStatusBarInitializer.initializeStatusBar(
-                mCentralSurfacesComponent::createCollapsedStatusBarFragment);
+        mStatusBarInitializer.initializeStatusBar();
 
         mStatusBarTouchableRegionManager.setup(this, getNotificationShadeWindowView());
 
@@ -1551,15 +1548,7 @@
         };
     }
 
-    private void inflateStatusBarWindow() {
-        if (mCentralSurfacesComponent != null) {
-            Log.e(TAG, "CentralSurfacesComponent being recreated; this is unexpected.");
-        }
-        mCentralSurfacesComponent = mCentralSurfacesComponentFactory.create();
-        mFragmentService.addFragmentInstantiationProvider(
-                CollapsedStatusBarFragment.class,
-                mCentralSurfacesComponent::createCollapsedStatusBarFragment);
-
+    private void setUpShade() {
         // Ideally, NotificationShadeWindowController could automatically fetch the window root view
         // in #attach or a CoreStartable.start method or something similar. But for now, to avoid
         // regressions, we'll continue standing up the root view in CentralSurfaces.
@@ -1568,12 +1557,6 @@
         mShadeController.setNotificationShadeWindowViewController(
                 getNotificationShadeWindowViewController());
         mBackActionInteractor.setup(mQsController, mShadeSurface);
-
-        // Listen for demo mode changes
-        mDemoModeController.addCallback(mDemoModeCallback);
-
-        mCommandQueueCallbacks = mCommandQueueCallbacksLazy.get();
-        mCommandQueue.addCallback(mCommandQueueCallbacks);
     }
 
     protected NotificationShadeWindowViewController getNotificationShadeWindowViewController() {
@@ -1666,11 +1649,6 @@
         logStateToEventlog();
     }
 
-    @Override
-    public NotificationPresenter getPresenter() {
-        return mPresenter;
-    }
-
     @VisibleForTesting
     @Override
     public void setBarStateForTest(int state) {
@@ -1745,11 +1723,6 @@
     }
 
     @Override
-    public BiometricUnlockController getBiometricUnlockController() {
-        return mBiometricUnlockController;
-    }
-
-    @Override
     public void showTransientUnchecked() {
         if (!mTransientShown) {
             mTransientShown = true;
@@ -2503,7 +2476,7 @@
                 mStatusBarKeyguardViewManager.reset(true);
             } else if (mState == StatusBarState.KEYGUARD
                     && !mStatusBarKeyguardViewManager.primaryBouncerIsOrWillBeShowing()
-                    && isKeyguardSecure()) {
+                    && mStatusBarKeyguardViewManager.isSecure()) {
                 mStatusBarKeyguardViewManager.showBouncer(true /* scrimmed */);
             }
         }
@@ -2842,11 +2815,6 @@
         }
     };
 
-    @Override
-    public int getWakefulnessState() {
-        return mWakefulnessLifecycle.getWakefulness();
-    }
-
     /**
      * @return true if the screen is currently fully off, i.e. has finished turning off and has
      * since not started turning on.
@@ -2912,7 +2880,7 @@
         if (mDevicePolicyManager.getCameraDisabled(null,
                 mLockscreenUserManager.getCurrentUserId())) {
             return false;
-        } else if (isKeyguardShowing() && isKeyguardSecure()) {
+        } else if (isKeyguardShowing() && mStatusBarKeyguardViewManager.isSecure()) {
             // Check if the admin has disabled the camera specifically for the keyguard
             return (mDevicePolicyManager.getKeyguardDisabledFeatures(null,
                     mLockscreenUserManager.getCurrentUserId())
@@ -3215,11 +3183,6 @@
         return mBouncerShowingOverDream;
     }
 
-    @Override
-    public boolean isKeyguardSecure() {
-        return mStatusBarKeyguardViewManager.isSecure();
-    }
-
     // End Extra BaseStatusBarMethods.
 
     boolean isTransientShown() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index b0f8276..40432ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -1480,7 +1480,7 @@
 
     public void setScrimBehindChangeRunnable(Runnable changeRunnable) {
         // TODO: remove this. This is necessary because of an order-of-operations limitation.
-        // The fix is to move more of these class into @CentralSurfacesScope
+        // The fix is to move more of these class into @SysUISingleton.
         if (mScrimBehind == null) {
             mScrimBehindChangeRunnable = changeRunnable;
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
index 37f032b..2c15e27 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
@@ -125,6 +125,7 @@
 
     // FrameCallback used to delay starting the light reveal animation until the next frame
     private val startLightRevealCallback = TraceUtils.namedRunnable("startLightReveal") {
+        lightRevealAnimationPlaying = true
         lightRevealAnimator.start()
     }
 
@@ -268,7 +269,6 @@
             decidedToAnimateGoingToSleep = true
 
             shouldAnimateInKeyguard = true
-            lightRevealAnimationPlaying = true
 
             // Start the animation on the next frame. startAnimation() is called after
             // PhoneWindowManager makes a binder call to System UI on
@@ -283,7 +283,8 @@
                 // dispatched, a race condition could make it possible for this callback to be run
                 // as the device is waking up. That results in the AOD UI being shown while we wake
                 // up, with unpredictable consequences.
-                if (!powerManager.isInteractive(Display.DEFAULT_DISPLAY)) {
+                if (!powerManager.isInteractive(Display.DEFAULT_DISPLAY) &&
+                        shouldAnimateInKeyguard) {
                     aodUiAnimationPlaying = true
 
                     // Show AOD. That'll cause the KeyguardVisibilityHelper to call
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java
deleted file mode 100644
index 1a04b91..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/CentralSurfacesComponent.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone.dagger;
-
-import static com.android.systemui.statusbar.phone.dagger.StatusBarViewModule.STATUS_BAR_FRAGMENT;
-
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
-import com.android.systemui.shade.ShadeHeaderController;
-import com.android.systemui.statusbar.phone.CentralSurfacesImpl;
-import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
-
-import dagger.Subcomponent;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-
-import javax.inject.Named;
-import javax.inject.Scope;
-
-/**
- * Dagger subcomponent for classes (semi-)related to the status bar. The component is created once
- * inside {@link CentralSurfacesImpl} and never re-created.
- *
- * TODO(b/197137564): This should likely be re-factored a bit. It includes classes that aren't
- * directly related to status bar functionality, like multiple notification classes. And, the fact
- * that it has many getter methods indicates that we need to access many of these classes from
- * outside the component. Should more items be moved *into* this component to avoid so many getters?
- */
-@Subcomponent(modules = {
-        StatusBarViewModule.class,
-})
-@CentralSurfacesComponent.CentralSurfacesScope
-public interface CentralSurfacesComponent {
-    /**
-     * Builder for {@link CentralSurfacesComponent}.
-     */
-    @Subcomponent.Factory
-    interface Factory {
-        CentralSurfacesComponent create();
-    }
-
-    /**
-     * Scope annotation for singleton items within the CentralSurfacesComponent.
-     */
-    @Documented
-    @Retention(RUNTIME)
-    @Scope
-    @interface CentralSurfacesScope {}
-
-    /**
-     * Creates a {@link ShadeHeaderController}.
-     */
-    ShadeHeaderController getLargeScreenShadeHeaderController();
-
-    /**
-     * Creates a new {@link CollapsedStatusBarFragment} each time it's called. See
-     * {@link StatusBarViewModule#createCollapsedStatusBarFragment}.
-     */
-    @Named(STATUS_BAR_FRAGMENT)
-    CollapsedStatusBarFragment createCollapsedStatusBarFragment();
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
deleted file mode 100644
index ebdde78..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarViewModule.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone.dagger;
-
-import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.shade.ShadeExpansionStateManager;
-import com.android.systemui.shade.ShadeViewController;
-import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.OperatorNameViewController;
-import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
-import com.android.systemui.statusbar.phone.NotificationIconAreaController;
-import com.android.systemui.statusbar.phone.StatusBarHideIconsForBouncerManager;
-import com.android.systemui.statusbar.phone.StatusBarIconController;
-import com.android.systemui.statusbar.phone.StatusBarLocationPublisher;
-import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
-import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragmentLogger;
-import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent;
-import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
-import com.android.systemui.statusbar.pipeline.shared.ui.binder.CollapsedStatusBarViewBinder;
-import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.CollapsedStatusBarViewModel;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.statusbar.window.StatusBarWindowStateController;
-import com.android.systemui.util.CarrierConfigTracker;
-import com.android.systemui.util.settings.SecureSettings;
-
-import dagger.Module;
-import dagger.Provides;
-
-import java.util.concurrent.Executor;
-
-import javax.inject.Named;
-
-/**
- * A module for {@link CentralSurfacesComponent.CentralSurfacesScope} components.
- *
- * @deprecated CentralSurfacesScope will be removed shortly (b/277762009). Classes should be
- *   annotated with @SysUISingleton instead.
- */
-@Module(subcomponents = StatusBarFragmentComponent.class)
-@Deprecated
-public abstract class StatusBarViewModule {
-
-    public static final String STATUS_BAR_FRAGMENT = "status_bar_fragment";
-
-    /**
-     * Creates a new {@link CollapsedStatusBarFragment}.
-     *
-     * **IMPORTANT**: This method intentionally does not have
-     * {@link CentralSurfacesComponent.CentralSurfacesScope}, which means a new fragment *will* be
-     * created each time this method is called. This is intentional because we need fragments to
-     * re-created in certain lifecycle scenarios.
-     *
-     * This provider is {@link Named} such that it does not conflict with the provider inside of
-     * {@link StatusBarFragmentComponent}.
-     */
-    @Provides
-    @Named(STATUS_BAR_FRAGMENT)
-    public static CollapsedStatusBarFragment createCollapsedStatusBarFragment(
-            StatusBarFragmentComponent.Factory statusBarFragmentComponentFactory,
-            OngoingCallController ongoingCallController,
-            SystemStatusAnimationScheduler animationScheduler,
-            StatusBarLocationPublisher locationPublisher,
-            NotificationIconAreaController notificationIconAreaController,
-            ShadeExpansionStateManager shadeExpansionStateManager,
-            FeatureFlags featureFlags,
-            StatusBarIconController statusBarIconController,
-            StatusBarIconController.DarkIconManager.Factory darkIconManagerFactory,
-            CollapsedStatusBarViewModel collapsedStatusBarViewModel,
-            CollapsedStatusBarViewBinder collapsedStatusBarViewBinder,
-            StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager,
-            KeyguardStateController keyguardStateController,
-            ShadeViewController shadeViewController,
-            StatusBarStateController statusBarStateController,
-            CommandQueue commandQueue,
-            CarrierConfigTracker carrierConfigTracker,
-            CollapsedStatusBarFragmentLogger collapsedStatusBarFragmentLogger,
-            OperatorNameViewController.Factory operatorNameViewControllerFactory,
-            SecureSettings secureSettings,
-            @Main Executor mainExecutor,
-            DumpManager dumpManager,
-            StatusBarWindowStateController statusBarWindowStateController,
-            KeyguardUpdateMonitor keyguardUpdateMonitor
-    ) {
-        return new CollapsedStatusBarFragment(statusBarFragmentComponentFactory,
-                ongoingCallController,
-                animationScheduler,
-                locationPublisher,
-                notificationIconAreaController,
-                shadeExpansionStateManager,
-                featureFlags,
-                statusBarIconController,
-                darkIconManagerFactory,
-                collapsedStatusBarViewModel,
-                collapsedStatusBarViewBinder,
-                statusBarHideIconsForBouncerManager,
-                keyguardStateController,
-                shadeViewController,
-                statusBarStateController,
-                commandQueue,
-                carrierConfigTracker,
-                collapsedStatusBarFragmentLogger,
-                operatorNameViewControllerFactory,
-                secureSettings,
-                mainExecutor,
-                dumpManager,
-                statusBarWindowStateController,
-                keyguardUpdateMonitor);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index 2efdf8a..66f0f59 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -29,7 +29,6 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewStub;
 import android.widget.LinearLayout;
 
 import androidx.annotation.VisibleForTesting;
@@ -85,6 +84,8 @@
 import java.util.Set;
 import java.util.concurrent.Executor;
 
+import javax.inject.Inject;
+
 /**
  * Contains the collapsed status bar and handles hiding/showing based on disable flags
  * and keyguard state. Also manages lifecycle to make sure the views it contains are being
@@ -203,7 +204,7 @@
         mTransitionFromLockscreenToDreamStarted = false;
     };
 
-    @SuppressLint("ValidFragment")
+    @Inject
     public CollapsedStatusBarFragment(
             StatusBarFragmentComponent.Factory statusBarFragmentComponentFactory,
             OngoingCallController ongoingCallController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentStartable.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentStartable.kt
new file mode 100644
index 0000000..55af0e3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentStartable.kt
@@ -0,0 +1,58 @@
+/*
+ * 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.statusbar.phone.fragment
+
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.fragments.FragmentService
+import com.android.systemui.qs.QSFragmentStartable
+import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+import javax.inject.Inject
+import javax.inject.Provider
+
+/**
+ * Provides [FragmentService] with a way to automatically inflate [CollapsedStatusBarFragment],
+ * similar to [QSFragmentStartable].
+ */
+@SysUISingleton
+class CollapsedStatusBarFragmentStartable
+@Inject
+constructor(
+    private val fragmentService: FragmentService,
+    private val collapsedstatusBarFragmentProvider: Provider<CollapsedStatusBarFragment>
+) : CoreStartable {
+    override fun start() {
+        fragmentService.addFragmentInstantiationProvider(
+            CollapsedStatusBarFragment::class.java,
+            collapsedstatusBarFragmentProvider,
+        )
+    }
+}
+
+@Module(subcomponents = [StatusBarFragmentComponent::class])
+interface CollapsedStatusBarFragmentStartableModule {
+    @Binds
+    @IntoMap
+    @ClassKey(CollapsedStatusBarFragmentStartable::class)
+    fun bindsCollapsedStatusBarFragmentStartable(
+        startable: CollapsedStatusBarFragmentStartable
+    ): CoreStartable
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandlerTest.kt
new file mode 100644
index 0000000..49f536e
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandlerTest.kt
@@ -0,0 +1,127 @@
+/*
+ * 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.media.controls.ui
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.MotionEvent
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.media.controls.util.MediaUiEventLogger
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.qs.PageIndicator
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.whenever
+import com.android.systemui.util.time.FakeSystemClock
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@RunWith(AndroidTestingRunner::class)
+class MediaCarouselScrollHandlerTest : SysuiTestCase() {
+
+    private val carouselWidth = 1038
+    private val motionEventUp = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0f, 0f, 0)
+
+    @Mock lateinit var mediaCarousel: MediaScrollView
+    @Mock lateinit var pageIndicator: PageIndicator
+    @Mock lateinit var dismissCallback: () -> Unit
+    @Mock lateinit var translationChangedListener: () -> Unit
+    @Mock lateinit var seekBarUpdateListener: (visibleToUser: Boolean) -> Unit
+    @Mock lateinit var closeGuts: (immediate: Boolean) -> Unit
+    @Mock lateinit var falsingManager: FalsingManager
+    @Mock lateinit var logSmartspaceImpression: (Boolean) -> Unit
+    @Mock lateinit var logger: MediaUiEventLogger
+
+    lateinit var executor: FakeExecutor
+    private val clock = FakeSystemClock()
+
+    private lateinit var mediaCarouselScrollHandler: MediaCarouselScrollHandler
+
+    @Before
+    fun setup() {
+        MockitoAnnotations.initMocks(this)
+        executor = FakeExecutor(clock)
+        mediaCarouselScrollHandler =
+            MediaCarouselScrollHandler(
+                mediaCarousel,
+                pageIndicator,
+                executor,
+                dismissCallback,
+                translationChangedListener,
+                seekBarUpdateListener,
+                closeGuts,
+                falsingManager,
+                logSmartspaceImpression,
+                logger
+            )
+        mediaCarouselScrollHandler.playerWidthPlusPadding = carouselWidth
+
+        whenever(mediaCarousel.touchListener).thenReturn(mediaCarouselScrollHandler.touchListener)
+    }
+
+    @Test
+    fun testCarouselScroll_shortScroll() {
+        whenever(mediaCarousel.isLayoutRtl).thenReturn(false)
+        whenever(mediaCarousel.relativeScrollX).thenReturn(300)
+
+        mediaCarousel.touchListener?.onTouchEvent(motionEventUp)
+        executor.runAllReady()
+
+        verify(mediaCarousel).smoothScrollTo(eq(0), anyInt())
+    }
+
+    @Test
+    fun testCarouselScroll_shortScroll_isRTL() {
+        whenever(mediaCarousel.isLayoutRtl).thenReturn(true)
+        whenever(mediaCarousel.relativeScrollX).thenReturn(300)
+
+        mediaCarousel.touchListener?.onTouchEvent(motionEventUp)
+        executor.runAllReady()
+
+        verify(mediaCarousel).smoothScrollTo(eq(carouselWidth), anyInt())
+    }
+
+    @Test
+    fun testCarouselScroll_longScroll() {
+        whenever(mediaCarousel.isLayoutRtl).thenReturn(false)
+        whenever(mediaCarousel.relativeScrollX).thenReturn(600)
+
+        mediaCarousel.touchListener?.onTouchEvent(motionEventUp)
+        executor.runAllReady()
+
+        verify(mediaCarousel).smoothScrollTo(eq(carouselWidth), anyInt())
+    }
+
+    @Test
+    fun testCarouselScroll_longScroll_isRTL() {
+        whenever(mediaCarousel.isLayoutRtl).thenReturn(true)
+        whenever(mediaCarousel.relativeScrollX).thenReturn(600)
+
+        mediaCarousel.touchListener?.onTouchEvent(motionEventUp)
+        executor.runAllReady()
+
+        verify(mediaCarousel).smoothScrollTo(eq(0), anyInt())
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
index 55ea3157..65697b73 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
@@ -24,6 +24,7 @@
 import android.testing.TestableLooper
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FakeFeatureFlagsClassic
 import com.android.systemui.statusbar.notification.collection.GroupEntry
 import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
 import com.android.systemui.statusbar.notification.collection.NotifPipeline
@@ -77,13 +78,18 @@
 
     private lateinit var coordinator: ConversationCoordinator
 
+    private val featureFlags = FakeFeatureFlagsClassic()
+
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
         coordinator = ConversationCoordinator(
             peopleNotificationIdentifier,
             conversationIconManager,
-            HighPriorityProvider(peopleNotificationIdentifier, GroupMembershipManagerImpl()),
+            HighPriorityProvider(
+                peopleNotificationIdentifier,
+                GroupMembershipManagerImpl(featureFlags)
+            ),
             headerController
         )
         whenever(channel.isImportantConversation).thenReturn(true)
@@ -182,7 +188,7 @@
     }
 
     @Test
-    fun testInAlertingPeopleSectionWhenThereIsAnImportantChild(){
+    fun testInAlertingPeopleSectionWhenThereIsAnImportantChild() {
         // GIVEN
         val altChildA = NotificationEntryBuilder().setTag("A")
                 .setImportance(IMPORTANCE_DEFAULT).build()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt
index 4a94dc8..ac2aec6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt
@@ -19,13 +19,23 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
-import com.android.systemui.flags.FakeFeatureFlags
+import com.android.systemui.flags.FakeFeatureFlagsClassic
 import com.android.systemui.flags.Flags
+import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
+import com.android.systemui.statusbar.notification.collection.ListEntry
+import com.android.systemui.statusbar.notification.collection.NotifPipeline
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener
+import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager.OnGroupExpansionChangeListener
+import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.mock
-import org.junit.Assert
+import com.android.systemui.util.mockito.withArgCaptor
+import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Test
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoMoreInteractions
 import org.mockito.Mockito.`when` as whenever
 
 @SmallTest
@@ -34,15 +44,45 @@
 
     private val dumpManager: DumpManager = mock()
     private val groupMembershipManager: GroupMembershipManager = mock()
-    private val featureFlags = FakeFeatureFlags()
+    private val featureFlags = FakeFeatureFlagsClassic()
 
-    private val entry1 = NotificationEntryBuilder().build()
-    private val entry2 = NotificationEntryBuilder().build()
+    private val pipeline: NotifPipeline = mock()
+    private lateinit var beforeRenderListListener: OnBeforeRenderListListener
+
+    private val summary1 = notificationEntry("foo", 1)
+    private val summary2 = notificationEntry("bar", 1)
+    private val entries =
+        listOf<ListEntry>(
+            GroupEntryBuilder()
+                .setSummary(summary1)
+                .setChildren(
+                    listOf(
+                        notificationEntry("foo", 2),
+                        notificationEntry("foo", 3),
+                        notificationEntry("foo", 4)
+                    )
+                )
+                .build(),
+            GroupEntryBuilder()
+                .setSummary(summary2)
+                .setChildren(
+                    listOf(
+                        notificationEntry("bar", 2),
+                        notificationEntry("bar", 3),
+                        notificationEntry("bar", 4)
+                    )
+                )
+                .build(),
+            notificationEntry("baz", 1)
+        )
+
+    private fun notificationEntry(pkg: String, id: Int) =
+        NotificationEntryBuilder().setPkg(pkg).setId(id).build().apply { row = mock() }
 
     @Before
     fun setUp() {
-        whenever(groupMembershipManager.getGroupSummary(entry1)).thenReturn(entry1)
-        whenever(groupMembershipManager.getGroupSummary(entry2)).thenReturn(entry2)
+        whenever(groupMembershipManager.getGroupSummary(summary1)).thenReturn(summary1)
+        whenever(groupMembershipManager.getGroupSummary(summary2)).thenReturn(summary2)
 
         gem = GroupExpansionManagerImpl(dumpManager, groupMembershipManager, featureFlags)
     }
@@ -54,16 +94,16 @@
         var listenerCalledCount = 0
         gem.registerGroupExpansionChangeListener { _, _ -> listenerCalledCount++ }
 
-        gem.setGroupExpanded(entry1, false)
-        Assert.assertEquals(0, listenerCalledCount)
-        gem.setGroupExpanded(entry1, true)
-        Assert.assertEquals(1, listenerCalledCount)
-        gem.setGroupExpanded(entry2, true)
-        Assert.assertEquals(2, listenerCalledCount)
-        gem.setGroupExpanded(entry1, true)
-        Assert.assertEquals(2, listenerCalledCount)
-        gem.setGroupExpanded(entry2, false)
-        Assert.assertEquals(3, listenerCalledCount)
+        gem.setGroupExpanded(summary1, false)
+        assertThat(listenerCalledCount).isEqualTo(0)
+        gem.setGroupExpanded(summary1, true)
+        assertThat(listenerCalledCount).isEqualTo(1)
+        gem.setGroupExpanded(summary2, true)
+        assertThat(listenerCalledCount).isEqualTo(2)
+        gem.setGroupExpanded(summary1, true)
+        assertThat(listenerCalledCount).isEqualTo(2)
+        gem.setGroupExpanded(summary2, false)
+        assertThat(listenerCalledCount).isEqualTo(3)
     }
 
     @Test
@@ -73,15 +113,39 @@
         var listenerCalledCount = 0
         gem.registerGroupExpansionChangeListener { _, _ -> listenerCalledCount++ }
 
-        gem.setGroupExpanded(entry1, false)
-        Assert.assertEquals(1, listenerCalledCount)
-        gem.setGroupExpanded(entry1, true)
-        Assert.assertEquals(2, listenerCalledCount)
-        gem.setGroupExpanded(entry2, true)
-        Assert.assertEquals(3, listenerCalledCount)
-        gem.setGroupExpanded(entry1, true)
-        Assert.assertEquals(4, listenerCalledCount)
-        gem.setGroupExpanded(entry2, false)
-        Assert.assertEquals(5, listenerCalledCount)
+        gem.setGroupExpanded(summary1, false)
+        assertThat(listenerCalledCount).isEqualTo(1)
+        gem.setGroupExpanded(summary1, true)
+        assertThat(listenerCalledCount).isEqualTo(2)
+        gem.setGroupExpanded(summary2, true)
+        assertThat(listenerCalledCount).isEqualTo(3)
+        gem.setGroupExpanded(summary1, true)
+        assertThat(listenerCalledCount).isEqualTo(4)
+        gem.setGroupExpanded(summary2, false)
+        assertThat(listenerCalledCount).isEqualTo(5)
+    }
+
+    @Test
+    fun testSyncWithPipeline() {
+        featureFlags.set(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE, true)
+        gem.attach(pipeline)
+        beforeRenderListListener = withArgCaptor {
+            verify(pipeline).addOnBeforeRenderListListener(capture())
+        }
+
+        val listener: OnGroupExpansionChangeListener = mock()
+        gem.registerGroupExpansionChangeListener(listener)
+
+        beforeRenderListListener.onBeforeRenderList(entries)
+        verify(listener, never()).onGroupExpansionChange(any(), any())
+
+        // Expand one of the groups.
+        gem.setGroupExpanded(summary1, true)
+        verify(listener).onGroupExpansionChange(summary1.row, true)
+
+        // Empty the pipeline list and verify that the group is no longer expanded.
+        beforeRenderListListener.onBeforeRenderList(emptyList())
+        verify(listener).onGroupExpansionChange(summary1.row, false)
+        verifyNoMoreInteractions(listener)
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerTest.kt
new file mode 100644
index 0000000..37ec0e0
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerTest.kt
@@ -0,0 +1,106 @@
+/*
+ * 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.statusbar.notification.collection.render
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FakeFeatureFlagsClassic
+import com.android.systemui.flags.Flags
+import com.android.systemui.statusbar.notification.collection.GroupEntry
+import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+
+@SmallTest
+class GroupMembershipManagerTest : SysuiTestCase() {
+    private lateinit var gmm: GroupMembershipManagerImpl
+
+    private val featureFlags = FakeFeatureFlagsClassic()
+
+    @Before
+    fun setUp() {
+        gmm = GroupMembershipManagerImpl(featureFlags)
+    }
+
+    @Test
+    fun testIsChildInGroup_topLevel() {
+        featureFlags.set(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE, false)
+        val topLevelEntry = NotificationEntryBuilder().setParent(GroupEntry.ROOT_ENTRY).build()
+        assertThat(gmm.isChildInGroup(topLevelEntry)).isFalse()
+    }
+
+    @Test
+    fun testIsChildInGroup_noParent_old() {
+        featureFlags.set(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE, false)
+        val noParentEntry = NotificationEntryBuilder().setParent(null).build()
+        assertThat(gmm.isChildInGroup(noParentEntry)).isTrue()
+    }
+
+    @Test
+    fun testIsChildInGroup_noParent_new() {
+        featureFlags.set(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE, true)
+        val noParentEntry = NotificationEntryBuilder().setParent(null).build()
+        assertThat(gmm.isChildInGroup(noParentEntry)).isFalse()
+    }
+
+    @Test
+    fun testIsChildInGroup_child() {
+        featureFlags.set(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE, false)
+        val childEntry = NotificationEntryBuilder().build()
+        assertThat(gmm.isChildInGroup(childEntry)).isTrue()
+    }
+
+    @Test
+    fun testIsGroupSummary() {
+        featureFlags.set(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE, true)
+        val entry = NotificationEntryBuilder().setGroupSummary(mContext, true).build()
+        assertThat(gmm.isGroupSummary(entry)).isTrue()
+    }
+
+    @Test
+    fun testGetGroupSummary() {
+        featureFlags.set(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE, true)
+
+        val summary =
+            NotificationEntryBuilder()
+                .setGroup(mContext, "group")
+                .setGroupSummary(mContext, true)
+                .build()
+        val groupEntry =
+            GroupEntryBuilder().setParent(GroupEntry.ROOT_ENTRY).setSummary(summary).build()
+        val entry =
+            NotificationEntryBuilder().setGroup(mContext, "group").setParent(groupEntry).build()
+
+        assertThat(gmm.getGroupSummary(entry)).isEqualTo(summary)
+    }
+
+    @Test
+    fun testGetGroupSummary_isSummary_old() {
+        featureFlags.set(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE, false)
+        val entry = NotificationEntryBuilder().setGroupSummary(mContext, true).build()
+        assertThat(gmm.getGroupSummary(entry)).isNull()
+    }
+
+    @Test
+    fun testGetGroupSummary_isSummary_new() {
+        featureFlags.set(Flags.NOTIFICATION_GROUP_EXPANSION_CHANGE, true)
+        val entry = NotificationEntryBuilder().setGroupSummary(mContext, true).build()
+        assertThat(gmm.getGroupSummary(entry)).isEqualTo(entry)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 5a1450f..4e3690f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -162,7 +162,7 @@
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
-import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
+import com.android.systemui.statusbar.phone.fragment.CollapsedStatusBarFragment;
 import com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -195,6 +195,8 @@
 import java.io.PrintWriter;
 import java.util.Optional;
 
+import javax.inject.Provider;
+
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper(setAsMainLooper = true)
@@ -259,6 +261,7 @@
     @Mock private DynamicPrivacyController mDynamicPrivacyController;
     @Mock private AutoHideController mAutoHideController;
     @Mock private StatusBarWindowController mStatusBarWindowController;
+    @Mock private Provider<CollapsedStatusBarFragment> mCollapsedStatusBarFragmentProvider;
     @Mock private StatusBarWindowStateController mStatusBarWindowStateController;
     @Mock private UserSwitcherController mUserSwitcherController;
     @Mock private Bubbles mBubbles;
@@ -277,8 +280,6 @@
     @Mock private ViewMediatorCallback mKeyguardVieMediatorCallback;
     @Mock private VolumeComponent mVolumeComponent;
     @Mock private CommandQueue mCommandQueue;
-    @Mock private CentralSurfacesComponent.Factory mStatusBarComponentFactory;
-    @Mock private CentralSurfacesComponent mCentralSurfacesComponent;
     @Mock private CentralSurfacesCommandQueueCallbacks mCentralSurfacesCommandQueueCallbacks;
     @Mock private PluginManager mPluginManager;
     @Mock private ViewMediatorCallback mViewMediatorCallback;
@@ -405,7 +406,6 @@
         when(mNotificationShadeWindowViewControllerLazy.get())
                 .thenReturn(mNotificationShadeWindowViewController);
 
-        when(mStatusBarComponentFactory.create()).thenReturn(mCentralSurfacesComponent);
         doAnswer(invocation -> {
             ((Runnable) invocation.getArgument(0)).run();
             return null;
@@ -443,7 +443,10 @@
                 mock(FragmentService.class),
                 mLightBarController,
                 mAutoHideController,
-                new StatusBarInitializer(mStatusBarWindowController, emptySet()),
+                new StatusBarInitializer(
+                        mStatusBarWindowController,
+                        mCollapsedStatusBarFragmentProvider,
+                        emptySet()),
                 mStatusBarWindowController,
                 mStatusBarWindowStateController,
                 mKeyguardUpdateMonitor,
@@ -504,7 +507,6 @@
                 mDozeScrimController,
                 mVolumeComponent,
                 mCommandQueue,
-                mStatusBarComponentFactory,
                 () -> mCentralSurfacesCommandQueueCallbacks,
                 mPluginManager,
                 mShadeController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
index e76f26d..e6f8c48 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationControllerTest.kt
@@ -134,6 +134,22 @@
         verify(shadeViewController, times(1)).showAodUi()
     }
 
+    @Test
+    fun testAodUiShowNotInvokedIfWakingUp() {
+        `when`(dozeParameters.canControlUnlockedScreenOff()).thenReturn(true)
+        `when`(powerManager.isInteractive).thenReturn(false)
+
+        val callbackCaptor = ArgumentCaptor.forClass(Runnable::class.java)
+        controller.startAnimation()
+        controller.onStartedWakingUp()
+
+        verify(handler).postDelayed(callbackCaptor.capture(), anyLong())
+
+        callbackCaptor.value.run()
+
+        verify(shadeViewController, never()).showAodUi()
+    }
+
     /**
      * The AOD UI is shown during the screen off animation, after a delay to allow the light reveal
      * animation to start. If the device is woken up during the screen off, we should *never* do
diff --git a/services/companion/java/com/android/server/companion/virtual/Android.bp b/services/companion/java/com/android/server/companion/virtual/Android.bp
index 6526c78..7a7d376 100644
--- a/services/companion/java/com/android/server/companion/virtual/Android.bp
+++ b/services/companion/java/com/android/server/companion/virtual/Android.bp
@@ -1,6 +1,9 @@
 java_aconfig_library {
     name: "virtualdevice_flags_lib",
     aconfig_declarations: "virtualdevice_flags",
+    static_libs: [
+        "android.companion.virtual.flags-aconfig-java",
+    ],
 }
 
 aconfig_declarations {
diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
index 34033e2..cf6092e 100644
--- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
+++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
@@ -17,6 +17,7 @@
 package com.android.server.companion.virtual;
 
 import static android.content.pm.ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES;
+import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
 
@@ -46,7 +47,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.BlockedAppStreamingActivity;
 
-import java.util.List;
 import java.util.Set;
 
 
@@ -219,28 +219,37 @@
     }
 
     @Override
-    public boolean canContainActivities(@NonNull List<ActivityInfo> activities,
-            @WindowConfiguration.WindowingMode int windowingMode) {
-        if (!isWindowingModeSupported(windowingMode)) {
+    public boolean canActivityBeLaunched(@NonNull ActivityInfo activityInfo,
+            @Nullable Intent intent, @WindowConfiguration.WindowingMode int windowingMode,
+            int launchingFromDisplayId, boolean isNewTask) {
+        if (!canContainActivity(activityInfo, windowingMode, launchingFromDisplayId, isNewTask)) {
+            mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
             return false;
         }
-        // Can't display all the activities if any of them don't want to be displayed.
-        final int activityCount = activities.size();
-        for (int i = 0; i < activityCount; i++) {
-            final ActivityInfo aInfo = activities.get(i);
-            if (!canContainActivity(aInfo, /* windowFlags= */ 0, /* systemWindowFlags= */ 0)) {
-                mActivityBlockedCallback.onActivityBlocked(mDisplayId, aInfo);
-                return false;
-            }
+        if (mIntentListenerCallback != null && intent != null
+                && mIntentListenerCallback.shouldInterceptIntent(intent)) {
+            Slog.d(TAG, "Virtual device intercepting intent");
+            return false;
         }
         return true;
     }
 
     @Override
-    public boolean canActivityBeLaunched(ActivityInfo activityInfo,
-            Intent intent, @WindowConfiguration.WindowingMode int windowingMode,
-            int launchingFromDisplayId, boolean isNewTask) {
+    public boolean canContainActivity(@NonNull ActivityInfo activityInfo,
+            @WindowConfiguration.WindowingMode int windowingMode, int launchingFromDisplayId,
+            boolean isNewTask) {
         if (!isWindowingModeSupported(windowingMode)) {
+            Slog.d(TAG, "Virtual device doesn't support windowing mode " + windowingMode);
+            return false;
+        }
+        if ((activityInfo.flags & FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES) == 0) {
+            Slog.d(TAG, "Virtual device requires android:canDisplayOnRemoteDevices=true");
+            return false;
+        }
+        final UserHandle activityUser =
+                UserHandle.getUserHandleForUid(activityInfo.applicationInfo.uid);
+        if (!mAllowedUsers.contains(activityUser)) {
+            Slog.d(TAG, "Virtual device launch disallowed from user " + activityUser);
             return false;
         }
 
@@ -249,40 +258,36 @@
             // The error dialog alerting users that streaming is blocked is always allowed.
             return true;
         }
-
-        if (!canContainActivity(activityInfo, /* windowFlags= */  0, /* systemWindowFlags= */ 0)) {
-            mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
+        if (!activityMatchesDisplayCategory(activityInfo)) {
+            Slog.d(TAG, "The activity's required display category '"
+                    + activityInfo.requiredDisplayCategory
+                    + "' not found on virtual display with the following categories: "
+                    + mDisplayCategories);
             return false;
         }
-
-        if (launchingFromDisplayId == Display.DEFAULT_DISPLAY) {
-            return true;
-        }
-        if (isNewTask && !mBlockedCrossTaskNavigations.isEmpty()
-                && mBlockedCrossTaskNavigations.contains(activityComponent)) {
-            Slog.d(TAG, "Virtual device blocking cross task navigation of " + activityComponent);
-            mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
+        if ((mDefaultActivityPolicy == VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_ALLOWED
+                && mBlockedActivities.contains(activityComponent))
+                || (mDefaultActivityPolicy == VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_BLOCKED
+                && !mAllowedActivities.contains(activityComponent))) {
+            Slog.d(TAG, "Virtual device launch disallowed by policy: " + activityComponent);
             return false;
         }
-        if (isNewTask && !mAllowedCrossTaskNavigations.isEmpty()
-                && !mAllowedCrossTaskNavigations.contains(activityComponent)) {
-            Slog.d(TAG, "Virtual device not allowing cross task navigation of "
-                    + activityComponent);
-            mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
-            return false;
-        }
-
-        if (mIntentListenerCallback != null && intent != null
-                && mIntentListenerCallback.shouldInterceptIntent(intent)) {
-            Slog.d(TAG, "Virtual device has intercepted intent");
-            return false;
+        if (isNewTask && launchingFromDisplayId != DEFAULT_DISPLAY) {
+            if ((!mBlockedCrossTaskNavigations.isEmpty()
+                    && mBlockedCrossTaskNavigations.contains(activityComponent))
+                    || ((!mAllowedCrossTaskNavigations.isEmpty()
+                    && !mAllowedCrossTaskNavigations.contains(activityComponent)))) {
+                Slog.d(TAG, "Virtual device cross task navigation disallowed by policy: "
+                        + activityComponent);
+                return false;
+            }
         }
 
         return true;
     }
 
-
     @Override
+    @SuppressWarnings("AndroidFrameworkRequiresPermission")
     public boolean keepActivityOnWindowFlagsChanged(ActivityInfo activityInfo, int windowFlags,
             int systemWindowFlags) {
         // The callback is fired only when windowFlags are changed. To let VirtualDevice owner
@@ -293,10 +298,17 @@
                     activityInfo.applicationInfo.uid));
         }
 
-        if (!canContainActivity(activityInfo, windowFlags, systemWindowFlags)) {
-            mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
-            return false;
+        if (!CompatChanges.isChangeEnabled(ALLOW_SECURE_ACTIVITY_DISPLAY_ON_REMOTE_DEVICE,
+                activityInfo.packageName,
+                UserHandle.getUserHandleForUid(activityInfo.applicationInfo.uid))) {
+            // TODO(b/201712607): Add checks for the apps that use SurfaceView#setSecure.
+            if ((windowFlags & FLAG_SECURE) != 0
+                    || (systemWindowFlags & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) {
+                mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
+                return false;
+            }
         }
+
         return true;
     }
 
@@ -368,53 +380,6 @@
 
     }
 
-    private boolean canContainActivity(ActivityInfo activityInfo, int windowFlags,
-            int systemWindowFlags) {
-        if ((activityInfo.flags & FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES) == 0) {
-            return false;
-        }
-        ComponentName activityComponent = activityInfo.getComponentName();
-        if (BLOCKED_APP_STREAMING_COMPONENT.equals(activityComponent)) {
-            // The error dialog alerting users that streaming is blocked is always allowed. Need to
-            // run before the clauses below to ensure error dialog always shows up.
-            return true;
-        }
-        if (!activityMatchesDisplayCategory(activityInfo)) {
-            Slog.d(TAG, String.format(
-                    "The activity's required display category: %s is not found on virtual display"
-                            + " with the following categories: %s",
-                    activityInfo.requiredDisplayCategory, mDisplayCategories.toString()));
-            return false;
-        }
-        final UserHandle activityUser =
-                UserHandle.getUserHandleForUid(activityInfo.applicationInfo.uid);
-        if (!mAllowedUsers.contains(activityUser)) {
-            Slog.d(TAG, "Virtual device activity not allowed from user " + activityUser);
-            return false;
-        }
-        if (mDefaultActivityPolicy == VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_ALLOWED
-                && mBlockedActivities.contains(activityComponent)) {
-            Slog.d(TAG, "Virtual device blocking launch of " + activityComponent);
-            return false;
-        }
-        if (mDefaultActivityPolicy == VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_BLOCKED
-                && !mAllowedActivities.contains(activityComponent)) {
-            Slog.d(TAG, activityComponent + " is not in the allowed list.");
-            return false;
-        }
-        if (!CompatChanges.isChangeEnabled(ALLOW_SECURE_ACTIVITY_DISPLAY_ON_REMOTE_DEVICE,
-                activityInfo.packageName, activityUser)) {
-            // TODO(b/201712607): Add checks for the apps that use SurfaceView#setSecure.
-            if ((windowFlags & FLAG_SECURE) != 0) {
-                return false;
-            }
-            if ((systemWindowFlags & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) {
-                return false;
-            }
-        }
-        return true;
-    }
-
     @VisibleForTesting
     int getRunningAppsChangedListenersSizeForTesting() {
         synchronized (mGenericWindowPolicyControllerLock) {
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
index 7429fbe..a135878 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -34,6 +34,7 @@
 import android.companion.virtual.VirtualDevice;
 import android.companion.virtual.VirtualDeviceManager;
 import android.companion.virtual.VirtualDeviceParams;
+import android.companion.virtual.flags.Flags;
 import android.companion.virtual.sensor.VirtualSensor;
 import android.content.AttributionSource;
 import android.content.Context;
@@ -323,6 +324,15 @@
                 @NonNull IVirtualDeviceSoundEffectListener soundEffectListener) {
             createVirtualDevice_enforcePermission();
             attributionSource.enforceCallingUid();
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                if (Flags.moreLogs()) {
+                    Slog.i(TAG, "Creating VirtualDevice");
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+
             final int callingUid = getCallingUid();
             final String packageName = attributionSource.getPackageName();
             if (!PermissionUtils.validateCallingPackageName(getContext(), packageName)) {
diff --git a/services/companion/java/com/android/server/companion/virtual/flags.aconfig b/services/companion/java/com/android/server/companion/virtual/flags.aconfig
index 4fe4c87..6297e91 100644
--- a/services/companion/java/com/android/server/companion/virtual/flags.aconfig
+++ b/services/companion/java/com/android/server/companion/virtual/flags.aconfig
@@ -1,3 +1,5 @@
+# OLD PACKAGE, DO NOT USE: Prefer `flags.aconfig` in core/java/android/companion/virtual
+# (or other custom files) to define your flags
 package: "com.android.server.companion.virtual"
 
 flag {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index bf9cdbe..0d265a0 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3852,15 +3852,16 @@
 
     @Override
     public void forceStopPackage(final String packageName, int userId) {
-        forceStopPackage(packageName, userId, /*flags=*/ 0);
+        forceStopPackage(packageName, userId, /*flags=*/ 0, null);
     }
 
     @Override
     public void forceStopPackageEvenWhenStopping(final String packageName, int userId) {
-        forceStopPackage(packageName, userId, ActivityManager.FLAG_OR_STOPPED);
+        forceStopPackage(packageName, userId, ActivityManager.FLAG_OR_STOPPED, null);
     }
 
-    private void forceStopPackage(final String packageName, int userId, int userRunningFlags) {
+    private void forceStopPackage(final String packageName, int userId, int userRunningFlags,
+            String reason) {
         if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
                 != PackageManager.PERMISSION_GRANTED) {
             String msg = "Permission Denial: forceStopPackage() from pid="
@@ -3905,7 +3906,8 @@
                                 + packageName + ": " + e);
                     }
                     if (mUserController.isUserRunning(user, userRunningFlags)) {
-                        forceStopPackageLocked(packageName, pkgUid, "from pid " + callingPid);
+                        forceStopPackageLocked(packageName, pkgUid,
+                                reason == null ? ("from pid " + callingPid) : reason);
                         finishForceStopPackageLocked(packageName, pkgUid);
                     }
                 }
@@ -5444,6 +5446,19 @@
                 intent = new Intent(Intent.ACTION_MAIN);
             }
             try {
+                if (allowlistToken != null) {
+                    final int callingUid = Binder.getCallingUid();
+                    final String packageName;
+                    final long token = Binder.clearCallingIdentity();
+                    try {
+                        packageName = AppGlobals.getPackageManager().getNameForUid(callingUid);
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                    Slog.wtf(TAG, "Send a non-null allowlistToken to a non-PI target."
+                            + " Calling package: " + packageName + "; intent: " + intent
+                            + "; options: " + options);
+                }
                 target.send(code, intent, resolvedType, allowlistToken, null,
                         requiredPermission, options);
             } catch (RemoteException e) {
@@ -14898,8 +14913,8 @@
                                     Intent.EXTRA_QUARANTINED, false);
                             if (suspended && quarantined && packageNames != null) {
                                 for (int i = 0; i < packageNames.length; i++) {
-                                    forceStopPackageLocked(packageNames[i], -1, false, true, true,
-                                            false, false, userId, "suspended");
+                                    forceStopPackage(packageNames[i], userId,
+                                            ActivityManager.FLAG_OR_STOPPED, "quarantined");
                                 }
                             }
 
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index ff35b19..bfccd58 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -3066,7 +3066,8 @@
          * <p>This variable controls the retry delay, and is reset when the VPN pass network
          * validation.
          */
-        private int mValidationFailRetryCount = 0;
+        @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+        int mValidationFailRetryCount = 0;
 
         /**
          * The number of attempts since the last successful connection.
@@ -3897,6 +3898,18 @@
                 // Skip other invalid status if the scheduled recovery exists.
                 if (mScheduledHandleDataStallFuture != null) return;
 
+                // Trigger network validation on the underlying network to possibly cause system
+                // switch default network or try recover if the current default network is broken.
+                //
+                // For the same underlying network, the first validation result should clarify if
+                // it's caused by broken underlying network. So only perform underlying network
+                // re-evaluation after first validation failure to prevent extra network resource
+                // costs on sending probes.
+                if (mValidationFailRetryCount == 0) {
+                    mConnectivityManager.reportNetworkConnectivity(
+                            mActiveNetwork, false /* hasConnectivity */);
+                }
+
                 if (mValidationFailRetryCount < MAX_MOBIKE_RECOVERY_ATTEMPT) {
                     Log.d(TAG, "Validation failed");
 
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index c0c60a4..e3dafa4 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -282,6 +282,8 @@
  *      <screenBrightnessRampFastIncrease>0.02</screenBrightnessRampFastIncrease>
  *      <screenBrightnessRampSlowDecrease>0.03</screenBrightnessRampSlowDecrease>
  *      <screenBrightnessRampSlowIncrease>0.04</screenBrightnessRampSlowIncrease>
+ *      <screenBrightnessRampSlowDecreaseIdle>0.05</screenBrightnessRampSlowDecreaseIdle>
+ *      <screenBrightnessRampSlowIncreaseIdle>0.06</screenBrightnessRampSlowIncreaseIdle>
  *
  *      <screenBrightnessRampIncreaseMaxMillis>2000</screenBrightnessRampIncreaseMaxMillis>
  *      <screenBrightnessRampDecreaseMaxMillis>3000</screenBrightnessRampDecreaseMaxMillis>
@@ -597,6 +599,8 @@
     private float mBrightnessRampFastIncrease = Float.NaN;
     private float mBrightnessRampSlowDecrease = Float.NaN;
     private float mBrightnessRampSlowIncrease = Float.NaN;
+    private float mBrightnessRampSlowDecreaseIdle = Float.NaN;
+    private float mBrightnessRampSlowIncreaseIdle = Float.NaN;
     private long mBrightnessRampDecreaseMaxMillis = 0;
     private long mBrightnessRampIncreaseMaxMillis = 0;
     private int mAmbientHorizonLong = AMBIENT_LIGHT_LONG_HORIZON_MILLIS;
@@ -1039,6 +1043,14 @@
         return mBrightnessRampSlowIncrease;
     }
 
+    public float getBrightnessRampSlowDecreaseIdle() {
+        return mBrightnessRampSlowDecreaseIdle;
+    }
+
+    public float getBrightnessRampSlowIncreaseIdle() {
+        return mBrightnessRampSlowIncreaseIdle;
+    }
+
     public long getBrightnessRampDecreaseMaxMillis() {
         return mBrightnessRampDecreaseMaxMillis;
     }
@@ -1654,6 +1666,8 @@
                 + ", mBrightnessRampFastIncrease=" + mBrightnessRampFastIncrease
                 + ", mBrightnessRampSlowDecrease=" + mBrightnessRampSlowDecrease
                 + ", mBrightnessRampSlowIncrease=" + mBrightnessRampSlowIncrease
+                + ", mBrightnessRampSlowDecreaseIdle=" + mBrightnessRampSlowDecreaseIdle
+                + ", mBrightnessRampSlowIncreaseIdle=" + mBrightnessRampSlowIncreaseIdle
                 + ", mBrightnessRampDecreaseMaxMillis=" + mBrightnessRampDecreaseMaxMillis
                 + ", mBrightnessRampIncreaseMaxMillis=" + mBrightnessRampIncreaseMaxMillis
                 + "\n"
@@ -1845,6 +1859,8 @@
         mBrightnessRampFastIncrease = PowerManager.BRIGHTNESS_MAX;
         mBrightnessRampSlowDecrease = PowerManager.BRIGHTNESS_MAX;
         mBrightnessRampSlowIncrease = PowerManager.BRIGHTNESS_MAX;
+        mBrightnessRampSlowDecreaseIdle = PowerManager.BRIGHTNESS_MAX;
+        mBrightnessRampSlowIncreaseIdle = PowerManager.BRIGHTNESS_MAX;
         mBrightnessRampDecreaseMaxMillis = 0;
         mBrightnessRampIncreaseMaxMillis = 0;
         setSimpleMappingStrategyValues();
@@ -2665,6 +2681,12 @@
     }
 
     private void loadBrightnessRamps(DisplayConfiguration config) {
+        // Interactive must come first, since idle falls back to it when values are unspecified.
+        loadBrightnessRampsInteractive(config);
+        loadBrightnessRampsIdle(config);
+    }
+
+    private void loadBrightnessRampsInteractive(DisplayConfiguration config) {
         // Priority 1: Value in the display device config (float)
         // Priority 2: Value in the config.xml (int)
         final BigDecimal fastDownDecimal = config.getScreenBrightnessRampFastDecrease();
@@ -2697,6 +2719,27 @@
         }
     }
 
+    private void loadBrightnessRampsIdle(DisplayConfiguration config) {
+        // Priority 1: Idle value in the display device config (float)
+        // Priority 2: Fallback - Interactive value from wherever.
+        final BigDecimal slowDownDecimalIdle = config.getScreenBrightnessRampSlowDecreaseIdle();
+        final BigDecimal slowUpDecimalIdle = config.getScreenBrightnessRampSlowIncreaseIdle();
+
+        if (slowDownDecimalIdle != null && slowUpDecimalIdle != null) {
+            mBrightnessRampSlowDecreaseIdle = slowDownDecimalIdle.floatValue();
+            mBrightnessRampSlowIncreaseIdle = slowUpDecimalIdle.floatValue();
+        } else {
+            if (slowDownDecimalIdle != null || slowUpDecimalIdle != null) {
+                Slog.w(TAG, "Per display idle brightness ramp values ignored because not all "
+                        + "values are present in display device config");
+            }
+            // If these values don't exist, fall back to interactive mode values, since
+            // there are no idle ramp values in config.xml
+            mBrightnessRampSlowDecreaseIdle = mBrightnessRampSlowDecrease;
+            mBrightnessRampSlowIncreaseIdle = mBrightnessRampSlowIncrease;
+        }
+    }
+
     private void loadBrightnessRampsFromConfigXml() {
         mBrightnessRampFastIncrease = BrightnessSynchronizer.brightnessIntToFloat(
                 mContext.getResources().getInteger(R.integer.config_brightness_ramp_rate_fast));
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 79b7343..e6b5057 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -430,6 +430,8 @@
     private float mBrightnessRampRateFastIncrease;
     private float mBrightnessRampRateSlowDecrease;
     private float mBrightnessRampRateSlowIncrease;
+    private float mBrightnessRampRateSlowDecreaseIdle;
+    private float mBrightnessRampRateSlowIncreaseIdle;
 
     // Report HBM brightness change to StatsD
     private int mDisplayStatsId;
@@ -1312,6 +1314,10 @@
         mBrightnessRampRateFastIncrease = mDisplayDeviceConfig.getBrightnessRampFastIncrease();
         mBrightnessRampRateSlowDecrease = mDisplayDeviceConfig.getBrightnessRampSlowDecrease();
         mBrightnessRampRateSlowIncrease = mDisplayDeviceConfig.getBrightnessRampSlowIncrease();
+        mBrightnessRampRateSlowDecreaseIdle =
+                mDisplayDeviceConfig.getBrightnessRampSlowDecreaseIdle();
+        mBrightnessRampRateSlowIncreaseIdle =
+                mDisplayDeviceConfig.getBrightnessRampSlowIncreaseIdle();
         mBrightnessRampDecreaseMaxTimeMillis =
                 mDisplayDeviceConfig.getBrightnessRampDecreaseMaxMillis();
         mBrightnessRampIncreaseMaxTimeMillis =
@@ -1922,12 +1928,16 @@
                 } else {
                     boolean isIncreasing = animateValue > currentBrightness;
                     final float rampSpeed;
+                    final boolean idle = mAutomaticBrightnessController != null
+                            && mAutomaticBrightnessController.isInIdleMode();
                     if (isIncreasing && slowChange) {
-                        rampSpeed = mBrightnessRampRateSlowIncrease;
+                        rampSpeed = idle ? mBrightnessRampRateSlowIncreaseIdle
+                                : mBrightnessRampRateSlowIncrease;
                     } else if (isIncreasing && !slowChange) {
                         rampSpeed = mBrightnessRampRateFastIncrease;
                     } else if (!isIncreasing && slowChange) {
-                        rampSpeed = mBrightnessRampRateSlowDecrease;
+                        rampSpeed = idle ? mBrightnessRampRateSlowDecreaseIdle
+                                : mBrightnessRampRateSlowDecrease;
                     } else {
                         rampSpeed = mBrightnessRampRateFastDecrease;
                     }
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java
index 6c2240b..252c29d 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController2.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController2.java
@@ -357,6 +357,8 @@
     private float mBrightnessRampRateFastIncrease;
     private float mBrightnessRampRateSlowDecrease;
     private float mBrightnessRampRateSlowIncrease;
+    private float mBrightnessRampRateSlowDecreaseIdle;
+    private float mBrightnessRampRateSlowIncreaseIdle;
 
     // Report HBM brightness change to StatsD
     private int mDisplayStatsId;
@@ -1127,6 +1129,10 @@
         mBrightnessRampRateFastIncrease = mDisplayDeviceConfig.getBrightnessRampFastIncrease();
         mBrightnessRampRateSlowDecrease = mDisplayDeviceConfig.getBrightnessRampSlowDecrease();
         mBrightnessRampRateSlowIncrease = mDisplayDeviceConfig.getBrightnessRampSlowIncrease();
+        mBrightnessRampRateSlowDecreaseIdle =
+                mDisplayDeviceConfig.getBrightnessRampSlowDecreaseIdle();
+        mBrightnessRampRateSlowIncreaseIdle =
+                mDisplayDeviceConfig.getBrightnessRampSlowIncreaseIdle();
         mBrightnessRampDecreaseMaxTimeMillis =
                 mDisplayDeviceConfig.getBrightnessRampDecreaseMaxMillis();
         mBrightnessRampIncreaseMaxTimeMillis =
@@ -1535,12 +1541,16 @@
                 } else {
                     boolean isIncreasing = animateValue > currentBrightness;
                     final float rampSpeed;
+                    final boolean idle = mAutomaticBrightnessController != null
+                            && mAutomaticBrightnessController.isInIdleMode();
                     if (isIncreasing && slowChange) {
-                        rampSpeed = mBrightnessRampRateSlowIncrease;
+                        rampSpeed = idle ? mBrightnessRampRateSlowIncreaseIdle
+                                : mBrightnessRampRateSlowIncrease;
                     } else if (isIncreasing && !slowChange) {
                         rampSpeed = mBrightnessRampRateFastIncrease;
                     } else if (!isIncreasing && slowChange) {
-                        rampSpeed = mBrightnessRampRateSlowDecrease;
+                        rampSpeed = idle ? mBrightnessRampRateSlowDecreaseIdle
+                                : mBrightnessRampRateSlowDecrease;
                     } else {
                         rampSpeed = mBrightnessRampRateFastDecrease;
                     }
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index f8313e7..dd04340 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -1144,8 +1144,16 @@
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
         final ParsedPackage parsedPackage;
         try (PackageParser2 pp = mPm.mInjector.getPreparingPackageParser()) {
-            parsedPackage = pp.parsePackage(tmpPackageFile, parseFlags, false);
-            AndroidPackageUtils.validatePackageDexMetadata(parsedPackage);
+            if (request.getPackageLite() == null || !PackageInstallerSession.isArchivedInstallation(
+                    request.getInstallFlags())) {
+                // TODO: pass packageLite from install request instead of reparsing the package
+                parsedPackage = pp.parsePackage(tmpPackageFile, parseFlags, false);
+                AndroidPackageUtils.validatePackageDexMetadata(parsedPackage);
+            } else {
+                // Archived install mode, no APK.
+                parsedPackage = pp.parsePackageFromPackageLite(request.getPackageLite(),
+                        parseFlags);
+            }
         } catch (PackageManagerException e) {
             throw new PrepareFailure("Failed parse during installPackageLI", e);
         } finally {
@@ -1547,6 +1555,7 @@
                     // TODO: Are these system flags actually set properly at this stage?
                     boolean isUpdatedSystemAppInferred =
                             pkgSetting != null && pkgSetting.isSystem();
+                    // derivePackageAbi works OK for archived packages despite logging some errors.
                     final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths>
                             derivedAbi = mPackageAbiHelper.derivePackageAbi(parsedPackage,
                             systemApp, (isUpdatedSystemAppFromExistingSetting
diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java
index 6c26531..fe7c086 100644
--- a/services/core/java/com/android/server/pm/InstallRequest.java
+++ b/services/core/java/com/android/server/pm/InstallRequest.java
@@ -35,6 +35,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.SharedLibraryInfo;
 import android.content.pm.SigningDetails;
+import android.content.pm.parsing.PackageLite;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Process;
@@ -93,6 +94,8 @@
     private int[] mNewUsers;
     @Nullable
     private AndroidPackage mPkg;
+    @Nullable
+    private PackageLite mPackageLite;
     private int mReturnCode;
     private int mInternalErrorCode;
     @Nullable
@@ -142,6 +145,7 @@
                 params.mInstallReason, params.mInstallScenario, params.mForceQueryableOverride,
                 params.mDataLoaderType, params.mPackageSource,
                 params.mApplicationEnabledSettingPersistent);
+        mPackageLite = params.mPackageLite;
         mPackageMetrics = new PackageMetrics(this);
         mIsInstallInherit = params.mIsInherit;
         mSessionId = params.mSessionId;
@@ -306,6 +310,11 @@
     }
 
     @Nullable
+    public PackageLite getPackageLite() {
+        return mPackageLite;
+    }
+
+    @Nullable
     public String getTraceMethod() {
         return mInstallArgs == null ? null : mInstallArgs.mTraceMethod;
     }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 923bbab..1554072 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -31,6 +31,7 @@
 import static android.content.pm.PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
 import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SPLIT;
 import static android.content.pm.PackageManager.INSTALL_FAILED_PRE_APPROVAL_NOT_AVAILABLE;
+import static android.content.pm.PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
 import static android.content.pm.PackageManager.INSTALL_STAGED;
 import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
@@ -52,6 +53,7 @@
 import static com.android.server.pm.PackageInstallerService.prepareStageDir;
 import static com.android.server.pm.PackageManagerService.APP_METADATA_FILE_NAME;
 import static com.android.server.pm.PackageManagerServiceUtils.isInstalledByAdb;
+import static com.android.server.pm.PackageManagerShellCommandDataLoader.Metadata;
 
 import android.Manifest;
 import android.annotation.AnyThread;
@@ -838,6 +840,10 @@
                 params.dataLoaderParams.getComponentName().getPackageName());
     }
 
+    static boolean isArchivedInstallation(int installFlags) {
+        return (installFlags & PackageManager.INSTALL_ARCHIVED) != 0;
+    }
+
     private final Handler.Callback mHandlerCallback = new Handler.Callback() {
         @Override
         public boolean handleMessage(Message msg) {
@@ -896,6 +902,10 @@
         return isSystemDataLoaderInstallation(this.params);
     }
 
+    private boolean isArchivedInstallation() {
+        return isArchivedInstallation(this.params.installFlags);
+    }
+
     /**
      * @return {@code true} iff the installing is app an device owner or affiliated profile owner.
      */
@@ -1146,6 +1156,17 @@
         if (isIncrementalInstallation() && !IncrementalManager.isAllowed()) {
             throw new IllegalArgumentException("Incremental installation not allowed.");
         }
+
+        if (isArchivedInstallation()) {
+            if (params.mode != SessionParams.MODE_FULL_INSTALL) {
+                throw new IllegalArgumentException(
+                        "Archived installation can only be full install.");
+            }
+            if (!isStreamingInstallation() || !isSystemDataLoaderInstallation()) {
+                throw new IllegalArgumentException(
+                        "Archived installation can only use Streaming System DataLoader.");
+            }
+        }
     }
 
     /**
@@ -1462,6 +1483,58 @@
     }
 
     @GuardedBy("mLock")
+    private List<ApkLite> getAddedApkLitesLocked() throws PackageManagerException {
+        if (!isArchivedInstallation()) {
+            List<File> files = getAddedApksLocked();
+            final List<ApkLite> result = new ArrayList<>(files.size());
+
+            final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
+            for (int i = 0, size = files.size(); i < size; ++i) {
+                final ParseResult<ApkLite> parseResult = ApkLiteParseUtils.parseApkLite(
+                        input.reset(), files.get(i),
+                        ParsingPackageUtils.PARSE_COLLECT_CERTIFICATES);
+                if (parseResult.isError()) {
+                    throw new PackageManagerException(parseResult.getErrorCode(),
+                            parseResult.getErrorMessage(), parseResult.getException());
+                }
+                result.add(parseResult.getResult());
+            }
+
+            return result;
+        }
+
+        InstallationFile[] files = getInstallationFilesLocked();
+        final List<ApkLite> result = new ArrayList<>(files.length);
+
+        for (int i = 0, size = files.length; i < size; ++i) {
+            File file = new File(stageDir, files[i].getName());
+            if (!sAddedApkFilter.accept(file)) {
+                continue;
+            }
+
+            final Metadata metadata;
+            try {
+                metadata = Metadata.fromByteArray(files[i].getMetadata());
+            } catch (IOException e) {
+                throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+                        "Failed to ", e);
+            }
+            if (metadata.getMode() != Metadata.ARCHIVED) {
+                throw new PackageManagerException(INSTALL_FAILED_VERIFICATION_FAILURE,
+                        "File metadata is not for ARCHIVED package: " + file);
+            }
+
+            var archPkg = metadata.getArchivedPackage();
+            if (archPkg.packageName == null || archPkg.signingDetails == null) {
+                throw new PackageManagerException(INSTALL_FAILED_VERIFICATION_FAILURE,
+                        "ArchivedPackage does not contain required info: " + file);
+            }
+            result.add(new ApkLite(file.getAbsolutePath(), archPkg));
+        }
+        return result;
+    }
+
+    @GuardedBy("mLock")
     private List<File> getRemovedFilesLocked() {
         String[] names = getNamesLocked();
         return filterFiles(stageDir, names, sRemovedFilter);
@@ -2732,9 +2805,18 @@
                 throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
                         "Session not sealed");
             }
-            Objects.requireNonNull(mPackageName);
-            Objects.requireNonNull(mSigningDetails);
-            Objects.requireNonNull(mResolvedBaseFile);
+            if (mPackageName == null) {
+                throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+                        "Session no package name");
+            }
+            if (mSigningDetails == null) {
+                throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+                        "Session no signing data");
+            }
+            if (mResolvedBaseFile == null) {
+                throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
+                        "Session no resolved base file");
+            }
             final PackageLite result;
             if (!isApexSession()) {
                 // For mode inherit existing, it would link/copy existing files to stage dir in
@@ -3176,7 +3258,7 @@
             }
         }
 
-        final List<File> addedFiles = getAddedApksLocked();
+        final List<ApkLite> addedFiles = getAddedApkLitesLocked();
         if (addedFiles.isEmpty()
                 && (removeSplitList.size() == 0 || getStagedAppMetadataFile() != null)) {
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
@@ -3190,15 +3272,7 @@
         final ArraySet<String> requiredSplitTypes = new ArraySet<>();
         final ArrayMap<String, ApkLite> splitApks = new ArrayMap<>();
         final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
-        for (File addedFile : addedFiles) {
-            final ParseResult<ApkLite> result = ApkLiteParseUtils.parseApkLite(input.reset(),
-                    addedFile, ParsingPackageUtils.PARSE_COLLECT_CERTIFICATES);
-            if (result.isError()) {
-                throw new PackageManagerException(result.getErrorCode(),
-                        result.getErrorMessage(), result.getException());
-            }
-
-            final ApkLite apk = result.getResult();
+        for (ApkLite apk : addedFiles) {
             if (!stagedSplits.add(apk.getSplitName())) {
                 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                         "Split " + apk.getSplitName() + " was defined multiple times");
@@ -3214,7 +3288,7 @@
             }
             mHasDeviceAdminReceiver = apk.isHasDeviceAdminReceiver();
 
-            assertApkConsistentLocked(String.valueOf(addedFile), apk);
+            assertApkConsistentLocked(String.valueOf(apk), apk);
 
             // Take this opportunity to enforce uniform naming
             final String targetName = ApkLiteParseUtils.splitNameToFileName(apk);
@@ -3235,7 +3309,10 @@
             }
 
             final File targetFile = new File(stageDir, targetName);
-            resolveAndStageFileLocked(addedFile, targetFile, apk.getSplitName());
+            if (!isArchivedInstallation()) {
+                final File sourceFile = new File(apk.getPath());
+                resolveAndStageFileLocked(sourceFile, targetFile, apk.getSplitName());
+            }
 
             // Base is coming from session
             if (apk.getSplitName() == null) {
@@ -4005,6 +4082,11 @@
             NativeLibraryHelper.removeNativeBinariesFromDirLI(libDir, true);
         }
 
+        // Skip native libraries processing for archival installation.
+        if (isArchivedInstallation()) {
+            return;
+        }
+
         NativeLibraryHelper.Handle handle = null;
         try {
             handle = NativeLibraryHelper.Handle.create(packageLite);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c0c3ec4..8faadba 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -77,6 +77,7 @@
 import android.content.IntentSender.SendIntentException;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.ArchivedPackageParcel;
 import android.content.pm.AuxiliaryResolveInfo;
 import android.content.pm.ChangedPackages;
 import android.content.pm.Checksum;
@@ -115,7 +116,11 @@
 import android.content.pm.VerifierDeviceIdentity;
 import android.content.pm.VersionedPackage;
 import android.content.pm.overlay.OverlayPaths;
+import android.content.pm.parsing.ApkLite;
+import android.content.pm.parsing.ApkLiteParseUtils;
 import android.content.pm.parsing.PackageLite;
+import android.content.pm.parsing.result.ParseResult;
+import android.content.pm.parsing.result.ParseTypeImpl;
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
@@ -6298,6 +6303,38 @@
             }
         }
 
+        @Override
+        public ArchivedPackageParcel getArchivedPackage(String apkPath) {
+            ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
+            ParseResult<ApkLite> result = ApkLiteParseUtils.parseApkLite(input.reset(),
+                    new File(apkPath), ParsingPackageUtils.PARSE_COLLECT_CERTIFICATES);
+            if (result.isError()) {
+                throw new IllegalArgumentException(result.getErrorMessage(), result.getException());
+            }
+            final ApkLite apk = result.getResult();
+
+            ArchivedPackageParcel archPkg = new ArchivedPackageParcel();
+            archPkg.packageName = apk.getPackageName();
+            archPkg.signingDetails = apk.getSigningDetails();
+
+            archPkg.versionCodeMajor = apk.getVersionCodeMajor();
+            archPkg.versionCode = apk.getVersionCode();
+
+            archPkg.targetSdkVersion = apk.getTargetSdkVersion();
+
+            // These get translated in flags important for user data management.
+            archPkg.clearUserDataAllowed = apk.isClearUserDataAllowed();
+            archPkg.backupAllowed = apk.isBackupAllowed();
+            archPkg.defaultToDeviceProtectedStorage =
+                    apk.isDefaultToDeviceProtectedStorage();
+            archPkg.requestLegacyExternalStorage = apk.isRequestLegacyExternalStorage();
+            archPkg.userDataFragile = apk.isUserDataFragile();
+            archPkg.clearUserDataOnFailedRestoreAllowed =
+                    apk.isClearUserDataOnFailedRestoreAllowed();
+
+            return archPkg;
+        }
+
         /**
          * Wait for the handler to finish handling all pending messages.
          * @param timeoutMillis Maximum time in milliseconds to wait.
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index db997d8..2028231 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -919,16 +919,22 @@
 
         final File packageFile = new File(packagePath);
         final long sizeBytes;
-        try {
-            sizeBytes = InstallLocationUtils.calculateInstalledSize(pkg, abiOverride);
-        } catch (IOException e) {
-            if (!packageFile.exists()) {
-                ret.recommendedInstallLocation = InstallLocationUtils.RECOMMEND_FAILED_INVALID_URI;
-            } else {
-                ret.recommendedInstallLocation = InstallLocationUtils.RECOMMEND_FAILED_INVALID_APK;
-            }
+        if (!PackageInstallerSession.isArchivedInstallation(flags)) {
+            try {
+                sizeBytes = InstallLocationUtils.calculateInstalledSize(pkg, abiOverride);
+            } catch (IOException e) {
+                if (!packageFile.exists()) {
+                    ret.recommendedInstallLocation =
+                            InstallLocationUtils.RECOMMEND_FAILED_INVALID_URI;
+                } else {
+                    ret.recommendedInstallLocation =
+                            InstallLocationUtils.RECOMMEND_FAILED_INVALID_APK;
+                }
 
-            return ret;
+                return ret;
+            }
+        } else {
+            sizeBytes = 0;
         }
 
         final PackageInstaller.SessionParams sessionParams = new PackageInstaller.SessionParams(
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 2304a23..d9f1df5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -43,6 +43,7 @@
 import android.content.Intent;
 import android.content.IntentSender;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.ArchivedPackageParcel;
 import android.content.pm.FeatureInfo;
 import android.content.pm.IPackageDataObserver;
 import android.content.pm.IPackageInstaller;
@@ -82,6 +83,7 @@
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.Environment;
 import android.os.IBinder;
 import android.os.IUserManager;
 import android.os.ParcelFileDescriptor;
@@ -105,6 +107,7 @@
 import android.text.format.DateUtils;
 import android.util.ArrayMap;
 import android.util.IntArray;
+import android.util.Pair;
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -246,6 +249,8 @@
                     return runStreamingInstall();
                 case "install-incremental":
                     return runIncrementalInstall();
+                case "install-archived":
+                    return runArchivedInstall();
                 case "install-abandon":
                 case "install-destroy":
                     return runInstallAbandon();
@@ -1549,6 +1554,16 @@
         return doRunInstall(params);
     }
 
+    private int runArchivedInstall() throws RemoteException {
+        final InstallParams params = makeInstallParams(UNSUPPORTED_INSTALL_CMD_OPTS);
+        params.sessionParams.installFlags |= PackageManager.INSTALL_ARCHIVED;
+        if (params.sessionParams.dataLoaderParams == null) {
+            params.sessionParams.setDataLoaderParams(
+                    PackageManagerShellCommandDataLoader.getStreamingDataLoaderParams(this));
+        }
+        return doRunInstall(params);
+    }
+
     private int runIncrementalInstall() throws RemoteException {
         final InstallParams params = makeInstallParams(UNSUPPORTED_INSTALL_CMD_OPTS);
         if (params.sessionParams.dataLoaderParams == null) {
@@ -1579,6 +1594,8 @@
         final boolean isStreaming = params.sessionParams.dataLoaderParams != null;
         final boolean isApex =
                 (params.sessionParams.installFlags & PackageManager.INSTALL_APEX) != 0;
+        final boolean installArchived =
+                (params.sessionParams.installFlags & PackageManager.INSTALL_ARCHIVED) != 0;
 
         ArrayList<String> args = getRemainingArgs();
 
@@ -1595,6 +1612,13 @@
             return 1;
         }
 
+        if (installArchived) {
+            if (hasSplits) {
+                pw.println("Error: can't have SPLIT(s) for Archival install");
+                return 1;
+            }
+        }
+
         if (!isStreaming) {
             if (fromStdIn && hasSplits) {
                 pw.println("Error: can't specify SPLIT(s) along with STDIN");
@@ -1613,8 +1637,8 @@
         boolean abandonSession = true;
         try {
             if (isStreaming) {
-                if (doAddFiles(sessionId, args, params.sessionParams.sizeBytes, isApex)
-                        != PackageInstaller.STATUS_SUCCESS) {
+                if (doAddFiles(sessionId, args, params.sessionParams.sizeBytes, isApex,
+                        installArchived) != PackageInstaller.STATUS_SUCCESS) {
                     return 1;
                 }
             } else {
@@ -3856,7 +3880,7 @@
     }
 
     private int doAddFiles(int sessionId, ArrayList<String> args, long sessionSizeBytes,
-            boolean isApex) throws RemoteException {
+            boolean isApex, boolean installArchived) throws RemoteException {
         PackageInstaller.Session session = null;
         try {
             session = new PackageInstaller.Session(
@@ -3865,9 +3889,17 @@
             // 1. Single file from stdin.
             if (args.isEmpty() || STDIN_PATH.equals(args.get(0))) {
                 final String name = "base" + RANDOM.nextInt() + "." + (isApex ? "apex" : "apk");
-                final Metadata metadata = Metadata.forStdIn(name);
-                session.addFile(LOCATION_DATA_APP, name, sessionSizeBytes,
-                        metadata.toByteArray(), null);
+                final long size;
+                final Metadata metadata;
+                if (!installArchived) {
+                    metadata = Metadata.forStdIn(name);
+                    size = sessionSizeBytes;
+                } else {
+                    metadata = Metadata.forArchived(
+                            getArchivedPackage(STDIN_PATH, sessionSizeBytes));
+                    size = -1;
+                }
+                session.addFile(LOCATION_DATA_APP, name, size, metadata.toByteArray(), null);
                 return 0;
             }
 
@@ -3876,16 +3908,21 @@
 
                 if (delimLocation != -1) {
                     // 2. File with specified size read from stdin.
+                    if (installArchived) {
+                        getOutPrintWriter().println(
+                                "Error: can't install with size from STDIN for Archival install");
+                        return 1;
+                    }
                     if (processArgForStdin(arg, session) != 0) {
                         return 1;
                     }
                 } else {
                     // 3. Local file.
-                    processArgForLocalFile(arg, session);
+                    processArgForLocalFile(arg, session, installArchived);
                 }
             }
             return 0;
-        } catch (IllegalArgumentException e) {
+        } catch (IOException | IllegalArgumentException e) {
             getErrPrintWriter().println("Failed to add file(s), reason: " + e);
             getOutPrintWriter().println("Failure [failed to add file(s)]");
             return 1;
@@ -3974,26 +4011,67 @@
         }
     }
 
-    private void processArgForLocalFile(String arg, PackageInstaller.Session session) {
+    private ArchivedPackageParcel getArchivedPackage(String inPath, long sizeBytes)
+            throws RemoteException, IOException {
+        final var fdWithSize = openInFile(inPath, sizeBytes);
+        if (fdWithSize.first == null) {
+            throw new IllegalArgumentException("Error: Can't open file: " + inPath);
+        }
+
+        File tmpFile = null;
+        final ParcelFileDescriptor fd = fdWithSize.first;
+        try (InputStream inStream = new AutoCloseInputStream(fd)) {
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                File tmpStagingDir = Environment.getDataAppDirectory(null);
+                tmpFile = new File(tmpStagingDir, "tmdl" + RANDOM.nextInt() + ".tmp");
+
+                try (OutputStream outStream = new FileOutputStream(tmpFile)) {
+                    Streams.copy(inStream, outStream);
+                }
+
+                return mInterface.getArchivedPackage(tmpFile.getAbsolutePath());
+            } finally {
+                if (tmpFile != null) {
+                    tmpFile.delete();
+                }
+                Binder.restoreCallingIdentity(identity);
+            }
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Error: Can't stage file: " + inPath, e);
+        }
+    }
+
+    private void processArgForLocalFile(String arg, PackageInstaller.Session session,
+            boolean installArchived) throws IOException, RemoteException {
         final String inPath = arg;
 
         final File file = new File(inPath);
         final String name = file.getName();
-        final long size = getFileStatSize(file);
-        final Metadata metadata = Metadata.forLocalFile(inPath);
+        final long size;
+        final Metadata metadata;
+        if (installArchived) {
+            metadata = Metadata.forArchived(getArchivedPackage(inPath, -1));
+            size = 0;
+        } else {
+            metadata = Metadata.forLocalFile(inPath);
+            size = getFileStatSize(file);
+        }
 
         byte[] v4signatureBytes = null;
-        // Try to load the v4 signature file for the APK; it might not exist.
-        final String v4SignaturePath = inPath + V4Signature.EXT;
-        final ParcelFileDescriptor pfd = openFileForSystem(v4SignaturePath, "r");
-        if (pfd != null) {
-            try {
-                final V4Signature v4signature = V4Signature.readFrom(pfd);
-                v4signatureBytes = v4signature.toByteArray();
-            } catch (IOException ex) {
-                Slog.e(TAG, "V4 signature file exists but failed to be parsed.", ex);
-            } finally {
-                IoUtils.closeQuietly(pfd);
+        if (!installArchived) {
+            // Try to load the v4 signature file for the APK; it might not exist.
+            final String v4SignaturePath = inPath + V4Signature.EXT;
+            final ParcelFileDescriptor pfd = openFileForSystem(v4SignaturePath, "r");
+            if (pfd != null) {
+                try {
+                    final V4Signature v4signature = V4Signature.readFrom(pfd);
+                    v4signatureBytes = v4signature.toByteArray();
+                } catch (IOException ex) {
+                    Slog.e(TAG, "V4 signature file exists but failed to be parsed.", ex);
+                } finally {
+                    IoUtils.closeQuietly(pfd);
+                }
             }
         }
 
@@ -4015,6 +4093,32 @@
         return 0;
     }
 
+    private Pair<ParcelFileDescriptor, Long> openInFile(String inPath, long sizeBytes)
+            throws IOException {
+        final ParcelFileDescriptor fd;
+        if (STDIN_PATH.equals(inPath)) {
+            fd = ParcelFileDescriptor.dup(getInFileDescriptor());
+        } else if (inPath != null) {
+            fd = openFileForSystem(inPath, "r");
+            if (fd == null) {
+                return Pair.create(null, -1L);
+            }
+            sizeBytes = fd.getStatSize();
+            if (sizeBytes < 0) {
+                fd.close();
+                getErrPrintWriter().println("Unable to get size of: " + inPath);
+                return Pair.create(null, -1L);
+            }
+        } else {
+            fd = ParcelFileDescriptor.dup(getInFileDescriptor());
+        }
+        if (sizeBytes <= 0) {
+            getErrPrintWriter().println("Error: must specify an APK size");
+            return Pair.create(null, 1L);
+        }
+        return Pair.create(fd, sizeBytes);
+    }
+
     private int doWriteSplit(int sessionId, String inPath, long sizeBytes, String splitName,
             boolean logSuccess) throws RemoteException {
         PackageInstaller.Session session = null;
@@ -4024,26 +4128,13 @@
 
             final PrintWriter pw = getOutPrintWriter();
 
-            final ParcelFileDescriptor fd;
-            if (STDIN_PATH.equals(inPath)) {
-                fd = ParcelFileDescriptor.dup(getInFileDescriptor());
-            } else if (inPath != null) {
-                fd = openFileForSystem(inPath, "r");
-                if (fd == null) {
-                    return -1;
-                }
-                sizeBytes = fd.getStatSize();
-                if (sizeBytes < 0) {
-                    getErrPrintWriter().println("Unable to get size of: " + inPath);
-                    return -1;
-                }
-            } else {
-                fd = ParcelFileDescriptor.dup(getInFileDescriptor());
+            final var fdWithSize = openInFile(inPath, sizeBytes);
+            if (fdWithSize.first == null) {
+                long resultCode = fdWithSize.second;
+                return (int) resultCode;
             }
-            if (sizeBytes <= 0) {
-                getErrPrintWriter().println("Error: must specify an APK size");
-                return 1;
-            }
+            final ParcelFileDescriptor fd = fdWithSize.first;
+            sizeBytes = fdWithSize.second;
 
             session.write(splitName, 0, sizeBytes, fd);
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java b/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java
index a1e5153..fbe5a51 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommandDataLoader.java
@@ -18,9 +18,11 @@
 
 import android.annotation.NonNull;
 import android.content.ComponentName;
+import android.content.pm.ArchivedPackageParcel;
 import android.content.pm.DataLoaderParams;
 import android.content.pm.InstallationFile;
 import android.content.pm.PackageInstaller;
+import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.ShellCommand;
 import android.service.dataloader.DataLoaderService;
@@ -37,6 +39,7 @@
 import java.nio.ByteOrder;
 import java.nio.charset.StandardCharsets;
 import java.security.SecureRandom;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.concurrent.atomic.AtomicLong;
 
@@ -136,9 +139,13 @@
          * Everything streamed.
          */
         static final byte STREAMING = 3;
+        /**
+         * Archived install.
+         */
+        static final byte ARCHIVED = 4;
 
         private final byte mMode;
-        private final String mData;
+        private final byte[] mData;
         private final String mSalt;
 
         private static AtomicLong sGlobalSalt = new AtomicLong((new SecureRandom()).nextLong());
@@ -156,6 +163,21 @@
             return new Metadata(LOCAL_FILE, filePath, nextGlobalSalt().toString());
         }
 
+        /** @hide */
+        @VisibleForTesting
+        public static Metadata forArchived(ArchivedPackageParcel archivedPackage) {
+            Parcel parcel = Parcel.obtain();
+            byte[] bytes;
+            try {
+                parcel.writeParcelable(archivedPackage, 0);
+                bytes = parcel.marshall();
+            } finally {
+                parcel.recycle();
+            }
+
+            return new Metadata(ARCHIVED, bytes, null);
+        }
+
         static Metadata forDataOnlyStreaming(String fileId) {
             return new Metadata(DATA_ONLY_STREAMING, fileId);
         }
@@ -169,8 +191,12 @@
         }
 
         private Metadata(byte mode, String data, String salt) {
+            this(mode, (data != null ? data : "").getBytes(StandardCharsets.UTF_8), salt);
+        }
+
+        private Metadata(byte mode, byte[] data, String salt) {
             this.mMode = mode;
-            this.mData = (data == null) ? "" : data;
+            this.mData = data;
             this.mSalt = salt;
         }
 
@@ -181,22 +207,21 @@
             int offset = 0;
             final byte mode = bytes[offset];
             offset += 1;
-            final String data;
+            final byte[] data;
             final String salt;
             switch (mode) {
                 case LOCAL_FILE: {
                     int dataSize = ByteBuffer.wrap(bytes, offset, 4).order(
                             ByteOrder.LITTLE_ENDIAN).getInt();
                     offset += 4;
-                    data = new String(bytes, offset, dataSize, StandardCharsets.UTF_8);
+                    data = Arrays.copyOfRange(bytes, offset, offset + dataSize);
                     offset += dataSize;
                     salt = new String(bytes, offset, bytes.length - offset,
                             StandardCharsets.UTF_8);
                     break;
                 }
                 default:
-                    data = new String(bytes, offset, bytes.length - offset,
-                            StandardCharsets.UTF_8);
+                    data = Arrays.copyOfRange(bytes, offset, bytes.length);
                     salt = null;
                     break;
             }
@@ -207,7 +232,7 @@
         @VisibleForTesting
         public byte[] toByteArray() {
             final byte[] result;
-            final byte[] dataBytes = this.mData.getBytes(StandardCharsets.UTF_8);
+            final byte[] dataBytes = this.mData;
             switch (this.mMode) {
                 case LOCAL_FILE: {
                     int dataSize = dataBytes.length;
@@ -237,9 +262,26 @@
             return this.mMode;
         }
 
-        String getData() {
+        byte[] getData() {
             return this.mData;
         }
+
+        ArchivedPackageParcel getArchivedPackage() {
+            if (getMode() != ARCHIVED) {
+                throw new IllegalStateException("Not an archived package metadata.");
+            }
+
+            Parcel parcel = Parcel.obtain();
+            ArchivedPackageParcel result;
+            try {
+                parcel.unmarshall(this.mData, 0, this.mData.length);
+                parcel.setDataPosition(0);
+                result = parcel.readParcelable(ArchivedPackageParcel.class.getClassLoader());
+            } finally {
+                parcel.recycle();
+            }
+            return result;
+        }
     }
 
     private static class DataLoader implements DataLoaderService.DataLoader {
@@ -278,7 +320,9 @@
                         case Metadata.LOCAL_FILE: {
                             ParcelFileDescriptor incomingFd = null;
                             try {
-                                incomingFd = getLocalFilePFD(shellCommand, metadata.getData());
+                                final String filePath = new String(metadata.getData(),
+                                        StandardCharsets.UTF_8);
+                                incomingFd = getLocalFilePFD(shellCommand, filePath);
                                 mConnector.writeData(file.getName(), 0, incomingFd.getStatSize(),
                                         incomingFd);
                             } finally {
@@ -286,6 +330,10 @@
                             }
                             break;
                         }
+                        case Metadata.ARCHIVED: {
+                            // Do nothing, metadata already contains everything needed for install.
+                            break;
+                        }
                         default:
                             Slog.e(TAG, "Unsupported metadata mode: " + metadata.getMode());
                             return false;
diff --git a/services/core/java/com/android/server/pm/PrepareFailure.java b/services/core/java/com/android/server/pm/PrepareFailure.java
index 3180bac..09cb6b9 100644
--- a/services/core/java/com/android/server/pm/PrepareFailure.java
+++ b/services/core/java/com/android/server/pm/PrepareFailure.java
@@ -42,7 +42,8 @@
     }
 
     PrepareFailure(String message, Exception e) {
-        super(((PackageManagerException) e).error,
+        super(e instanceof PackageManagerException ? ((PackageManagerException) e).error
+                        : PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
                 ExceptionUtils.getCompleteMessage(message, e));
     }
 
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index d2adfdd..f740cf4 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -2916,11 +2916,7 @@
 
             StringBuilder sb = new StringBuilder();
             for (final PackageSetting ps : mPackages.values()) {
-                // TODO(b/135203078): This doesn't handle multiple users
-                final String dataPath = PackageInfoUtils.getDataDir(ps, UserHandle.USER_SYSTEM)
-                        .getAbsolutePath();
-
-                if (ps.getPkg() == null || dataPath == null) {
+                if (ps.getPkg() == null) {
                     if (!"android".equals(ps.getPackageName())) {
                         Slog.w(TAG, "Skipping " + ps + " due to missing metadata");
                     }
@@ -2932,6 +2928,10 @@
                     continue;
                 }
 
+                // TODO(b/135203078): This doesn't handle multiple users
+                final File dataDir = PackageInfoUtils.getDataDir(ps, UserHandle.USER_SYSTEM);
+                final String dataPath = dataDir == null ? "null" : dataDir.getAbsolutePath();
+
                 final boolean isDebug = ps.getPkg().isDebuggable();
                 final IntArray gids = new IntArray();
                 for (final int userId : userIds) {
@@ -2973,7 +2973,7 @@
                 sb.append(ps.getSeInfo());
                 sb.append(" ");
                 final int gidsSize = gids.size();
-                if (gids != null && gids.size() > 0) {
+                if (gids.size() > 0) {
                     sb.append(gids.get(0));
                     for (int i = 1; i < gidsSize; i++) {
                         sb.append(",");
@@ -4893,6 +4893,8 @@
             pw.print("]");
         }
         pw.println();
+        File dataDir = PackageInfoUtils.getDataDir(ps, UserHandle.myUserId());
+        pw.print(prefix); pw.print("  dataDir="); pw.println(dataDir.getAbsolutePath());
         if (pkg != null) {
             pw.print(prefix); pw.print("  versionName="); pw.println(pkg.getVersionName());
             pw.print(prefix); pw.print("  usesNonSdkApi="); pw.println(pkg.isNonSdkApiRequested());
@@ -5193,10 +5195,6 @@
             pw.print("      installReason=");
             pw.println(userState.getInstallReason());
 
-            final File dataDir = PackageInfoUtils.getDataDir(ps, user.id);
-            pw.print("      dataDir=");
-            pw.println(dataDir == null ? "null" : dataDir.getAbsolutePath());
-
             final PackageUserStateInternal pus = ps.readUserState(user.id);
             pw.print("      firstInstallTime=");
             date.setTime(pus.getFirstInstallTimeMillis());
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index f2797eb..259b207 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -4787,11 +4787,14 @@
         // default check is for DISALLOW_ADD_USER
         // If new user is of type CLONE, check if creation of clone profile is allowed
         // If new user is of type MANAGED, check if creation of managed profile is allowed
+        // If new user is of type PRIVATE, check if creation of private profile is allowed
         String restriction = UserManager.DISALLOW_ADD_USER;
         if (UserManager.isUserTypeCloneProfile(userType)) {
             restriction = UserManager.DISALLOW_ADD_CLONE_PROFILE;
         } else if (UserManager.isUserTypeManagedProfile(userType)) {
             restriction = UserManager.DISALLOW_ADD_MANAGED_PROFILE;
+        } else if (UserManager.isUserTypePrivateProfile(userType)) {
+            restriction = UserManager.DISALLOW_ADD_PRIVATE_PROFILE;
         }
 
         enforceUserRestriction(restriction, UserHandle.getCallingUserId(),
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 4e2ceab..35861d7 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -103,6 +103,7 @@
             UserManager.DISALLOW_ADD_USER,
             UserManager.DISALLOW_ADD_MANAGED_PROFILE,
             UserManager.DISALLOW_ADD_CLONE_PROFILE,
+            UserManager.DISALLOW_ADD_PRIVATE_PROFILE,
             UserManager.ENSURE_VERIFY_APPS,
             UserManager.DISALLOW_CONFIG_CELL_BROADCASTS,
             UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS,
@@ -212,7 +213,8 @@
     private static final Set<String> IMMUTABLE_BY_OWNERS = Sets.newArraySet(
             UserManager.DISALLOW_RECORD_AUDIO,
             UserManager.DISALLOW_WALLPAPER,
-            UserManager.DISALLOW_OEM_UNLOCK
+            UserManager.DISALLOW_OEM_UNLOCK,
+            UserManager.DISALLOW_ADD_PRIVATE_PROFILE
     );
 
     /**
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index b7f9aaf..85b60a0 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -51,6 +51,7 @@
 import android.util.ArrayMap;
 import android.util.Slog;
 
+import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.XmlUtils;
 
@@ -284,9 +285,9 @@
                 .setBadgeLabels(
                         com.android.internal.R.string.private_profile_label_badge)
                 .setBadgeColors(
-                        com.android.internal.R.color.system_accent1_900)
+                        R.color.black)
                 .setDarkThemeBadgeColors(
-                        com.android.internal.R.color.system_accent1_900)
+                        R.color.white)
                 .setDefaultRestrictions(getDefaultProfileRestrictions())
                 .setDefaultSecureSettings(getDefaultNonManagedProfileSecureSettings())
                 .setDefaultUserProperties(new UserProperties.Builder()
diff --git a/services/core/java/com/android/server/pm/VerifyingSession.java b/services/core/java/com/android/server/pm/VerifyingSession.java
index 3a1fd7c..8c73ce8 100644
--- a/services/core/java/com/android/server/pm/VerifyingSession.java
+++ b/services/core/java/com/android/server/pm/VerifyingSession.java
@@ -191,7 +191,7 @@
         // Perform package verification and enable rollback (unless we are simply moving the
         // package).
         if (!mOriginInfo.mExisting) {
-            if (!isApex()) {
+            if (!isApex() && !isArchivedInstallation()) {
                 // TODO(b/182426975): treat APEX as APK when APK verification is concerned
                 sendApkVerificationRequest(pkgLite);
             }
@@ -896,6 +896,9 @@
     public boolean isApex() {
         return (mInstallFlags & PackageManager.INSTALL_APEX) != 0;
     }
+    public boolean isArchivedInstallation() {
+        return (mInstallFlags & PackageManager.INSTALL_ARCHIVED) != 0;
+    }
     public boolean isStaged() {
         return mIsStaged;
     }
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index f4f03f4..31856f1 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -544,6 +544,11 @@
      */
     public boolean compileLayouts(@NonNull PackageStateInternal ps, @NonNull AndroidPackage pkg) {
         try {
+            final String packageName = pkg.getPackageName();
+            final String apkPath = pkg.getSplits().get(0).getPath();
+            // TODO(b/143971007): Use a cross-user directory
+            File dataDir = PackageInfoUtils.getDataDir(ps, UserHandle.myUserId());
+            final String outDexFile = dataDir.getAbsolutePath() + "/code_cache/compiled_view.dex";
             if (ps.isPrivileged() || pkg.isUseEmbeddedDex()
                     || pkg.isDefaultToDeviceProtectedStorage()) {
                 // Privileged apps prefer to load trusted code so they don't use compiled views.
@@ -553,14 +558,6 @@
                 // selinux permissions required for writing to user_de.
                 return false;
             }
-            final String packageName = pkg.getPackageName();
-            final String apkPath = pkg.getSplits().get(0).getPath();
-            final File dataDir = PackageInfoUtils.getDataDir(ps, UserHandle.myUserId());
-            if (dataDir == null) {
-                // The app is not installed on the target user and doesn't have a data dir
-                return false;
-            }
-            final String outDexFile = dataDir.getAbsolutePath() + "/code_cache/compiled_view.dex";
             Log.i("PackageManager", "Compiling layouts in " + packageName + " (" + apkPath +
                     ") to " + outDexFile);
             final long callingId = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/pm/dex/ViewCompiler.java b/services/core/java/com/android/server/pm/dex/ViewCompiler.java
index c5b65a3..6405ea5 100644
--- a/services/core/java/com/android/server/pm/dex/ViewCompiler.java
+++ b/services/core/java/com/android/server/pm/dex/ViewCompiler.java
@@ -40,11 +40,8 @@
     public boolean compileLayouts(PackageStateInternal ps, String apkPath) {
         try {
             final String packageName = ps.getPackageName();
-            final File dataDir = PackageInfoUtils.getDataDir(ps, UserHandle.myUserId());
-            if (dataDir == null) {
-                // The app is not installed on the target user and doesn't have a data dir
-                return false;
-            }
+            // TODO(b/143971007): Use a cross-user directory
+            File dataDir = PackageInfoUtils.getDataDir(ps, UserHandle.myUserId());
             final String outDexFile = dataDir.getAbsolutePath() + "/code_cache/compiled_view.dex";
             Log.i("PackageManager", "Compiling layouts in " + packageName + " (" + apkPath +
                 ") to " + outDexFile);
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index fc07909..27812df 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -443,7 +443,7 @@
 
         updateApplicationInfo(info, flags, state);
 
-        initForUser(info, pkg, userId, state);
+        initForUser(info, pkg, userId);
 
         // TODO(b/135203078): Remove PackageParser1/toAppInfoWithoutState and clean all this up
         PackageStateUnserialized pkgState = pkgSetting.getTransientState();
@@ -689,7 +689,7 @@
         info.splitDependencies = pkg.getSplitDependencies().size() == 0
                 ? null : pkg.getSplitDependencies();
 
-        initForUser(info, pkg, userId, state);
+        initForUser(info, pkg, userId);
 
         info.primaryCpuAbi = pkgSetting.getPrimaryCpuAbi();
         info.secondaryCpuAbi = pkgSetting.getSecondaryCpuAbi();
@@ -1001,7 +1001,7 @@
     }
 
     private static void initForUser(ApplicationInfo output, AndroidPackage input,
-            @UserIdInt int userId, PackageUserStateInternal state) {
+            @UserIdInt int userId) {
         PackageImpl pkg = ((PackageImpl) input);
         String packageName = input.getPackageName();
         output.uid = UserHandle.getUid(userId, UserHandle.getAppId(input.getUid()));
@@ -1011,12 +1011,6 @@
             return;
         }
 
-        if (!pkg.isSystem() && state.getCeDataInode() <= 0) {
-            // The data dir has been deleted
-            output.dataDir = null;
-            return;
-        }
-
         // For performance reasons, all these paths are built as strings
         if (userId == UserHandle.USER_SYSTEM) {
             output.credentialProtectedDataDir =
@@ -1051,7 +1045,7 @@
     // 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, PackageUserStateInternal state) {
+            @UserIdInt int userId) {
         PackageImpl pkg = ((PackageImpl) input);
         String packageName = input.getPackageName();
         if ("android".equals(packageName)) {
@@ -1059,12 +1053,6 @@
             return;
         }
 
-        if (!pkg.isSystem() && state.getCeDataInode() <= 0) {
-            // The data dir has been deleted
-            output.dataDir = null;
-            return;
-        }
-
         // For performance reasons, all these paths are built as strings
         if (userId == UserHandle.USER_SYSTEM) {
             output.credentialProtectedDataDir =
@@ -1096,21 +1084,12 @@
         }
     }
 
-    /**
-     * Returns the data dir of the app for the target user. Return null if the app isn't installed
-     * on the target user and doesn't have a data dir on the target user.
-     */
-    @Nullable
+    @NonNull
     public static File getDataDir(PackageStateInternal ps, int userId) {
         if ("android".equals(ps.getPackageName())) {
             return Environment.getDataSystemDirectory();
         }
 
-        if (!ps.isSystem() && ps.getUserStateOrDefault(userId).getCeDataInode() <= 0) {
-            // The data dir has been deleted
-            return null;
-        }
-
         if (ps.isDefaultToDeviceProtectedStorage()
                 && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) {
             return Environment.getDataUserDePackageDirectory(ps.getVolumeUuid(), userId,
diff --git a/services/core/java/com/android/server/pm/parsing/PackageParser2.java b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
index f5ba3f6..d82a500 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageParser2.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
@@ -22,6 +22,7 @@
 import android.app.ActivityThread;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.parsing.PackageLite;
 import android.content.pm.parsing.result.ParseInput;
 import android.content.pm.parsing.result.ParseResult;
 import android.content.pm.parsing.result.ParseTypeImpl;
@@ -183,6 +184,23 @@
     }
 
     /**
+     * Creates a ParsedPackage from PackageLite without any additional parsing or processing.
+     * Most fields will get reasonable default values, corresponding to "deleted-keep-data".
+     */
+    @AnyThread
+    public ParsedPackage parsePackageFromPackageLite(PackageLite packageLite, int flags)
+            throws PackageManagerException {
+        ParseInput input = mSharedResult.get().reset();
+        ParseResult<ParsingPackage> result = parsingUtils.parsePackageFromPackageLite(input,
+                packageLite, flags);
+        if (result.isError()) {
+            throw new PackageManagerException(result.getErrorCode(), result.getErrorMessage(),
+                    result.getException());
+        }
+        return result.getResult().hideAsParsed();
+    }
+
+    /**
      * Removes the cached value for the thread the parser was created on. It is assumed that
      * any threads created for parallel parsing will be created and released, so they don't
      * need an explicit close call.
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
index f1f0fa3..699ccbd 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
@@ -375,6 +375,10 @@
 
     ParsingPackage setBaseRevisionCode(int baseRevisionCode);
 
+    ParsingPackage setVersionCode(int vesionCode);
+
+    ParsingPackage setVersionCodeMajor(int vesionCodeMajor);
+
     ParsingPackage setVersionName(String versionName);
 
     ParsingPackage setCompileSdkVersion(int compileSdkVersion);
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index dc022f7..2d55b9f 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -474,15 +474,121 @@
         }
     }
 
-    private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, File apkFile,
-            String codePath, SplitAssetLoader assetLoader, int flags) {
-        final String apkPath = apkFile.getAbsolutePath();
+    /**
+     * Creates ParsingPackage using only PackageLite.
+     * Missing fields will contain reasonable defaults.
+     * Used for packageless (aka archived) package installation.
+     */
+    public ParseResult<ParsingPackage> parsePackageFromPackageLite(ParseInput input,
+            PackageLite lite, int flags) {
+        final String volumeUuid = getVolumeUuid(lite.getPath());
+        final String pkgName = lite.getPackageName();
 
+        final TypedArray manifestArray = null;
+        final ParsingPackage pkg = mCallback.startParsingPackage(pkgName,
+                lite.getBaseApkPath(), lite.getPath(), manifestArray, lite.isCoreApp());
+
+        final int targetSdk = lite.getTargetSdk();
+        final String versionName = null;
+        final int compileSdkVersion = 0;
+        final String compileSdkVersionCodeName = null;
+        final boolean isolatedSplitLoading = false;
+
+        // Normally set from manifestArray.
+        pkg.setVersionCode(lite.getVersionCode());
+        pkg.setVersionCodeMajor(lite.getVersionCodeMajor());
+        pkg.setBaseRevisionCode(lite.getBaseRevisionCode());
+        pkg.setVersionName(versionName);
+        pkg.setCompileSdkVersion(compileSdkVersion);
+        pkg.setCompileSdkVersionCodeName(compileSdkVersionCodeName);
+        pkg.setIsolatedSplitLoading(isolatedSplitLoading);
+        pkg.setTargetSdkVersion(targetSdk);
+
+        // parseBaseApkTags
+        pkg.setInstallLocation(lite.getInstallLocation())
+                .setTargetSandboxVersion(PARSE_DEFAULT_TARGET_SANDBOX)
+                /* Set the global "on SD card" flag */
+                .setExternalStorage((flags & PARSE_EXTERNAL_STORAGE) != 0);
+
+        // parseBaseAppBasicFlags
+        pkg
+                // Default true
+                .setBackupAllowed(lite.isBackupAllowed())
+                .setClearUserDataAllowed(lite.isClearUserDataAllowed())
+                .setClearUserDataOnFailedRestoreAllowed(
+                        lite.isClearUserDataOnFailedRestoreAllowed())
+                .setAllowNativeHeapPointerTagging(true)
+                .setEnabled(true)
+                .setExtractNativeLibrariesRequested(true)
+                // targetSdkVersion gated
+                .setAllowAudioPlaybackCapture(targetSdk >= Build.VERSION_CODES.Q)
+                .setHardwareAccelerated(targetSdk >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
+                .setRequestLegacyExternalStorage(lite.isRequestLegacyExternalStorage())
+                .setCleartextTrafficAllowed(targetSdk < Build.VERSION_CODES.P)
+                // Default false
+                .setDefaultToDeviceProtectedStorage(lite.isDefaultToDeviceProtectedStorage())
+                .setUserDataFragile(lite.isUserDataFragile())
+                // Ints
+                .setCategory(ApplicationInfo.CATEGORY_UNDEFINED)
+                // Floats Default 0f
+                .setMaxAspectRatio(0f)
+                .setMinAspectRatio(0f);
+
+        // No APK - no code.
+        pkg.setDeclaredHavingCode(false);
+
+        final String taskAffinity = null;
+        ParseResult<String> taskAffinityResult = ComponentParseUtils.buildTaskAffinityName(
+                pkgName, pkgName, taskAffinity, input);
+        if (taskAffinityResult.isError()) {
+            return input.error(taskAffinityResult);
+        }
+        pkg.setTaskAffinity(taskAffinityResult.getResult());
+
+        final CharSequence pname = null;
+        ParseResult<String> processNameResult = ComponentParseUtils.buildProcessName(
+                pkgName, null /*defProc*/, pname, flags, mSeparateProcesses, input);
+        if (processNameResult.isError()) {
+            return input.error(processNameResult);
+        }
+        pkg.setProcessName(processNameResult.getResult());
+
+        pkg.setGwpAsanMode(-1);
+        pkg.setMemtagMode(-1);
+
+        afterParseBaseApplication(pkg);
+
+        final ParseResult<ParsingPackage> result = validateBaseApkTags(input, pkg);
+        if (result.isError()) {
+            return result;
+        }
+
+        pkg.setVolumeUuid(volumeUuid);
+
+        if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
+            pkg.setSigningDetails(lite.getSigningDetails());
+        } else {
+            pkg.setSigningDetails(SigningDetails.UNKNOWN);
+        }
+
+        return input.success(pkg
+                .set32BitAbiPreferred(lite.isUse32bitAbi()));
+    }
+
+    private static String getVolumeUuid(final String apkPath) {
         String volumeUuid = null;
         if (apkPath.startsWith(MNT_EXPAND)) {
             final int end = apkPath.indexOf('/', MNT_EXPAND.length());
             volumeUuid = apkPath.substring(MNT_EXPAND.length(), end);
         }
+        return volumeUuid;
+    }
+
+    private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, File apkFile,
+            String codePath, SplitAssetLoader assetLoader, int flags) {
+        final String apkPath = apkFile.getAbsolutePath();
+
+        final String volumeUuid = getVolumeUuid(apkPath);
 
         if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
 
@@ -882,7 +988,7 @@
         }
 
         pkg.setInstallLocation(anInteger(PARSE_DEFAULT_INSTALL_LOCATION,
-                R.styleable.AndroidManifest_installLocation, sa))
+                        R.styleable.AndroidManifest_installLocation, sa))
                 .setTargetSandboxVersion(anInteger(PARSE_DEFAULT_TARGET_SANDBOX,
                         R.styleable.AndroidManifest_targetSandboxVersion, sa))
                 /* Set the global "on SD card" flag */
@@ -932,6 +1038,10 @@
             }
         }
 
+        return validateBaseApkTags(input, pkg);
+    }
+
+    private ParseResult<ParsingPackage> validateBaseApkTags(ParseInput input, ParsingPackage pkg) {
         if (!ParsedAttributionUtils.isCombinationValid(pkg.getAttributions())) {
             return input.error(
                     INSTALL_PARSE_FAILED_BAD_MANIFEST,
@@ -2199,15 +2309,19 @@
             pkg.sortServices();
         }
 
-        // Must be run after the entire {@link ApplicationInfo} has been fully processed and after
-        // every activity info has had a chance to set it from its attributes.
+        afterParseBaseApplication(pkg);
+
+        return input.success(pkg);
+    }
+
+    // Must be run after the entire {@link ApplicationInfo} has been fully processed and after
+    // every activity info has had a chance to set it from its attributes.
+    private void afterParseBaseApplication(ParsingPackage pkg) {
         setMaxAspectRatio(pkg);
         setMinAspectRatio(pkg);
         setSupportsSizeChanges(pkg);
 
         pkg.setHasDomainUrls(hasDomainURLs(pkg));
-
-        return input.success(pkg);
     }
 
     /**
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 234e3f4..2559b84 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -3472,6 +3472,10 @@
             final long identity = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
+                    ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
+                    if (serviceState.hardwareInputMap.containsKey(inputInfo.getId())) {
+                        return;
+                    }
                     mTvInputHardwareManager.addHardwareInput(deviceId, inputInfo);
                     addHardwareInputLocked(inputInfo);
                 }
@@ -3486,6 +3490,10 @@
             final long identity = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
+                    ServiceState serviceState = getServiceStateLocked(mComponent, mUserId);
+                    if (serviceState.hardwareInputMap.containsKey(inputInfo.getId())) {
+                        return;
+                    }
                     mTvInputHardwareManager.addHdmiInput(id, inputInfo);
                     addHardwareInputLocked(inputInfo);
                     if (mOnScreenInputId != null && mOnScreenSessionState != null) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 6085488..90e67df 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -3363,7 +3363,11 @@
         // current focused activity could be another activity in the same Task if activities are
         // displayed on adjacent TaskFragments.
         final ActivityRecord currentFocusedApp = mDisplayContent.mFocusedApp;
-        if (currentFocusedApp != null && currentFocusedApp.task == task) {
+        final int topFocusedDisplayId = mRootWindowContainer.getTopFocusedDisplayContent() != null
+                ? mRootWindowContainer.getTopFocusedDisplayContent().getDisplayId()
+                : INVALID_DISPLAY;
+        if (currentFocusedApp != null && currentFocusedApp.task == task
+                && topFocusedDisplayId == mDisplayContent.getDisplayId()) {
             final Task topFocusableTask = mDisplayContent.getTask(
                     (t) -> t.isLeafTask() && t.isFocusable(), true /*  traverseTopToBottom */);
             if (task == topFocusableTask) {
diff --git a/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java b/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java
index 4180cd2..15a0445 100644
--- a/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/DesktopModeLaunchParamsModifier.java
@@ -40,8 +40,6 @@
     private static final boolean DEBUG = false;
 
     // Desktop mode feature flags.
-    private static final boolean DESKTOP_MODE_PROTO1_SUPPORTED =
-            SystemProperties.getBoolean("persist.wm.debug.desktop_mode", false);
     private static final boolean DESKTOP_MODE_PROTO2_SUPPORTED =
             SystemProperties.getBoolean("persist.wm.debug.desktop_mode_2", false);
     // Override default freeform task width when desktop mode is enabled. In dips.
@@ -142,6 +140,6 @@
 
     /** Whether desktop mode is supported. */
     static boolean isDesktopModeSupported() {
-        return DESKTOP_MODE_PROTO1_SUPPORTED || DESKTOP_MODE_PROTO2_SUPPORTED;
+        return DESKTOP_MODE_PROTO2_SUPPORTED;
     }
 }
diff --git a/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java b/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
index 2fb9869..6b33746 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java
@@ -68,19 +68,15 @@
     }
 
     /**
-     * @see DisplayWindowPolicyController#canContainActivities(List, int)
+     * @see DisplayWindowPolicyController#canContainActivities
      */
     public boolean canContainActivities(@NonNull List<ActivityInfo> activities,
             @WindowConfiguration.WindowingMode int windowingMode) {
         if (mDisplayWindowPolicyController == null) {
-            for (int i = activities.size() - 1; i >= 0; i--) {
-                final ActivityInfo aInfo = activities.get(i);
-                if (aInfo.requiredDisplayCategory != null) {
-                    Slog.e(TAG,
-                            String.format("Activity with requiredDisplayCategory='%s' cannot be"
-                                            + " displayed on display %d because that display does"
-                                            + " not have a matching category",
-                                    aInfo.requiredDisplayCategory, mDisplayContent.mDisplayId));
+            for (int i = 0; i < activities.size(); ++i) {
+                // Missing controller means that this display has no categories for activity launch
+                // restriction.
+                if (hasDisplayCategory(activities.get(i))) {
                     return false;
                 }
             }
@@ -90,26 +86,31 @@
     }
 
     /**
-     * @see DisplayWindowPolicyController#canActivityBeLaunched(ActivityInfo, int, int, boolean)
+     * @see DisplayWindowPolicyController#canActivityBeLaunched
      */
     public boolean canActivityBeLaunched(ActivityInfo activityInfo,
             Intent intent, @WindowConfiguration.WindowingMode int windowingMode,
             int launchingFromDisplayId, boolean isNewTask) {
         if (mDisplayWindowPolicyController == null) {
-            if (activityInfo.requiredDisplayCategory != null) {
-                Slog.e(TAG,
-                        String.format("Activity with requiredDisplayCategory='%s' cannot be"
-                                + " launched on display %d because that display does"
-                                + " not have a matching category",
-                                activityInfo.requiredDisplayCategory, mDisplayContent.mDisplayId));
-                return false;
-            }
-            return true;
+            // Missing controller means that this display has no categories for activity launch
+            // restriction.
+            return !hasDisplayCategory(activityInfo);
         }
         return mDisplayWindowPolicyController.canActivityBeLaunched(activityInfo, intent,
             windowingMode, launchingFromDisplayId, isNewTask);
     }
 
+    private boolean hasDisplayCategory(ActivityInfo aInfo) {
+        if (aInfo.requiredDisplayCategory != null) {
+            Slog.d(TAG,
+                    String.format("Checking activity launch with requiredDisplayCategory='%s' on"
+                                    + " display %d, which doesn't have a matching category.",
+                            aInfo.requiredDisplayCategory, mDisplayContent.mDisplayId));
+            return true;
+        }
+        return false;
+    }
+
     /**
      * @see DisplayWindowPolicyController#keepActivityOnWindowFlagsChanged(ActivityInfo, int, int)
      */
@@ -199,7 +200,6 @@
         return mDisplayWindowPolicyController.isEnteringPipAllowed(uid);
     }
 
-
     void dump(String prefix, PrintWriter pw) {
         if (mDisplayWindowPolicyController != null) {
             pw.println();
diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd
index d833fbd..d22e02e 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -67,6 +67,18 @@
                 <xs:element type="nonNegativeDecimal" name="screenBrightnessRampSlowIncrease">
                     <xs:annotation name="final"/>
                 </xs:element>
+                <!-- Ramp speed used to decrease the screen brightness when in idle mode.
+                     In framework brightness units per second. Must exist with
+                     screenBrightnessRampSlowIncreaseIdle-->
+                <xs:element type="nonNegativeDecimal" name="screenBrightnessRampSlowDecreaseIdle">
+                    <xs:annotation name="final"/>
+                </xs:element>
+                <!-- Ramp speed used to decrease the screen brightness when in idle mode.
+                     In framework brightness units per second. Must exist with
+                     screenBrightnessRampSlowDecreaseIdle-->
+                <xs:element type="nonNegativeDecimal" name="screenBrightnessRampSlowIncreaseIdle">
+                    <xs:annotation name="final"/>
+                </xs:element>
                 <!-- Maximum time in milliseconds that a brightness increase animation
                      can take. -->
                 <xs:element type="xs:nonNegativeInteger" name="screenBrightnessRampIncreaseMaxMillis">
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index d2ac1aae..6364c1f 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -115,7 +115,9 @@
     method public final java.math.BigDecimal getScreenBrightnessRampFastIncrease();
     method public final java.math.BigInteger getScreenBrightnessRampIncreaseMaxMillis();
     method public final java.math.BigDecimal getScreenBrightnessRampSlowDecrease();
+    method public final java.math.BigDecimal getScreenBrightnessRampSlowDecreaseIdle();
     method public final java.math.BigDecimal getScreenBrightnessRampSlowIncrease();
+    method public final java.math.BigDecimal getScreenBrightnessRampSlowIncreaseIdle();
     method public final com.android.server.display.config.SensorDetails getScreenOffBrightnessSensor();
     method public final com.android.server.display.config.IntegerArray getScreenOffBrightnessSensorValueToLux();
     method @NonNull public final com.android.server.display.config.ThermalThrottling getThermalThrottling();
@@ -142,7 +144,9 @@
     method public final void setScreenBrightnessRampFastIncrease(java.math.BigDecimal);
     method public final void setScreenBrightnessRampIncreaseMaxMillis(java.math.BigInteger);
     method public final void setScreenBrightnessRampSlowDecrease(java.math.BigDecimal);
+    method public final void setScreenBrightnessRampSlowDecreaseIdle(java.math.BigDecimal);
     method public final void setScreenBrightnessRampSlowIncrease(java.math.BigDecimal);
+    method public final void setScreenBrightnessRampSlowIncreaseIdle(java.math.BigDecimal);
     method public final void setScreenOffBrightnessSensor(com.android.server.display.config.SensorDetails);
     method public final void setScreenOffBrightnessSensorValueToLux(com.android.server.display.config.IntegerArray);
     method public final void setThermalThrottling(@NonNull com.android.server.display.config.ThermalThrottling);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index af1bac8..2be2bb9 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2594,6 +2594,12 @@
                 mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_CLONE_PROFILE, true,
                         userHandle);
             }
+            // Enforcing the restriction of private profile creation in case device owner is set.
+            if (!mUserManager.hasUserRestriction(
+                    UserManager.DISALLOW_ADD_PRIVATE_PROFILE, userHandle)) {
+                mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_PRIVATE_PROFILE, true,
+                        userHandle);
+            }
             // Creation of managed profile is restricted in case device owner is set, enforcing this
             // restriction by setting user level restriction at time of device owner setup.
             if (!mUserManager.hasUserRestriction(
@@ -4036,6 +4042,15 @@
                     mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_CLONE_PROFILE,
                             false, user);
                 }
+
+                // When a device owner is set, the system automatically restricts adding a
+                // private profile.
+                // Remove this restriction when the device owner is cleared.
+                if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_PRIVATE_PROFILE,
+                        user)) {
+                    mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_PRIVATE_PROFILE,
+                            false, user);
+                }
             }
         } else {
             // ManagedProvisioning/DPC sets DISALLOW_ADD_USER. Clear to recover to the original state
@@ -4061,6 +4076,15 @@
                         false,
                         userHandle);
             }
+
+            // When a device owner is set, the system automatically restricts adding a
+            // private profile.
+            // Remove this restriction when the device owner is cleared.
+            if (mUserManager.hasUserRestriction(UserManager.DISALLOW_ADD_PRIVATE_PROFILE,
+                    userHandle)) {
+                mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_PRIVATE_PROFILE,
+                        false, userHandle);
+            }
         }
     }
 
@@ -9423,6 +9447,11 @@
                         mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_CLONE_PROFILE,
                                 true,
                                 UserHandle.of(u));
+
+                        // Restrict adding a private profile when a device owner is set.
+                        mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_PRIVATE_PROFILE,
+                                true,
+                                UserHandle.of(u));
                     }
                 } else {
                     mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_MANAGED_PROFILE,
@@ -9435,6 +9464,9 @@
                     mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_CLONE_PROFILE,
                             true,
                             UserHandle.of(userId));
+                    mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_PRIVATE_PROFILE,
+                            true,
+                            UserHandle.of(userId));
                 }
                 // TODO Send to system too?
                 sendOwnerChangedBroadcast(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED, userId);
@@ -13200,6 +13232,8 @@
         USER_RESTRICTION_PERMISSIONS.put(
                 UserManager.DISALLOW_ADD_CLONE_PROFILE, new String[]{MANAGE_DEVICE_POLICY_PROFILES});
         USER_RESTRICTION_PERMISSIONS.put(
+                UserManager.DISALLOW_ADD_PRIVATE_PROFILE, new String[]{MANAGE_DEVICE_POLICY_PROFILES});
+        USER_RESTRICTION_PERMISSIONS.put(
                 UserManager.DISALLOW_ADD_USER, new String[]{MANAGE_DEVICE_POLICY_MODIFY_USERS});
         USER_RESTRICTION_PERMISSIONS.put(
                 UserManager.DISALLOW_ADD_WIFI_CONFIG, new String[]{MANAGE_DEVICE_POLICY_WIFI});
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
index 7a877b9..0fc8c5e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
@@ -426,6 +426,7 @@
         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADD_USER, /* flags= */ 0);
         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADD_MANAGED_PROFILE, /* flags= */ 0);
         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADD_CLONE_PROFILE, /* flags= */ 0);
+        USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_ADD_PRIVATE_PROFILE, /* flags= */ 0);
         USER_RESTRICTION_FLAGS.put(UserManager.ENSURE_VERIFY_APPS, POLICY_FLAG_GLOBAL_ONLY_POLICY);
         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_CELL_BROADCASTS, /* flags= */ 0);
         USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, /* flags= */ 0);
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanTests.java
index 98c6c42..e2939c1 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanTests.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/ScanTests.java
@@ -612,9 +612,6 @@
 
         final PackageSetting pkgSetting = scanResult.mPkgSetting;
         assertBasicPackageSetting(scanResult, packageName, isInstant, pkgSetting);
-        // pretend that the data dir has been set up already, so that the generated applicationInfo
-        // includes the expected data dir string
-        pkgSetting.setCeDataInode(/* ceDataInode= */100, /* userId= */0);
 
         final ApplicationInfo applicationInfo = PackageInfoUtils.generateApplicationInfo(
                 pkgSetting.getPkg(), 0, pkgSetting.getUserStateOrDefault(0), 0, pkgSetting);
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java
index 4cbdd09..0195ff7 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java
@@ -101,6 +101,8 @@
     private static final float BRIGHTNESS_RAMP_RATE_FAST_INCREASE = 0.4f;
     private static final float BRIGHTNESS_RAMP_RATE_SLOW_DECREASE = 0.1f;
     private static final float BRIGHTNESS_RAMP_RATE_SLOW_INCREASE = 0.2f;
+    private static final float BRIGHTNESS_RAMP_RATE_SLOW_INCREASE_IDLE = 0.5f;
+    private static final float BRIGHTNESS_RAMP_RATE_SLOW_DECREASE_IDLE = 0.6f;
 
     private OffsettableClock mClock;
     private TestLooper mTestLooper;
@@ -1116,6 +1118,48 @@
         verify(mDisplayWhiteBalanceControllerMock, times(1)).setStrongModeEnabled(true);
     }
 
+    @Test
+    public void testRampRatesIdle() {
+        Settings.System.putInt(mContext.getContentResolver(),
+                Settings.System.SCREEN_BRIGHTNESS_MODE,
+                Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
+        float brightness = 0.6f;
+        when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
+        when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+        when(mHolder.automaticBrightnessController.isInIdleMode()).thenReturn(true);
+        when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness(
+                any(BrightnessEvent.class))).thenReturn(brightness);
+
+        DisplayPowerRequest dpr = new DisplayPowerRequest();
+        mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+        advanceTime(1); // Run updatePowerState
+
+        verify(mHolder.animator).animateTo(eq(brightness), anyFloat(),
+                eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+
+        when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(brightness);
+        brightness = 0.05f;
+        when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness(
+                any(BrightnessEvent.class))).thenReturn(brightness);
+
+        mHolder.dpc.updateBrightness();
+        advanceTime(1); // Run updatePowerState
+
+        // The second time, the animation rate should be slow
+        verify(mHolder.animator).animateTo(eq(brightness), anyFloat(),
+                eq(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE_IDLE));
+
+        brightness = 0.9f;
+        when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness(
+                any(BrightnessEvent.class))).thenReturn(brightness);
+
+        mHolder.dpc.updateBrightness();
+        advanceTime(1); // Run updatePowerState
+        // The third time, the animation rate should be slow
+        verify(mHolder.animator).animateTo(eq(brightness), anyFloat(),
+                eq(BRIGHTNESS_RAMP_RATE_SLOW_INCREASE_IDLE));
+    }
+
     /**
      * Creates a mock and registers it to {@link LocalServices}.
      */
@@ -1187,6 +1231,10 @@
                 .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE);
         when(displayDeviceConfigMock.getBrightnessRampSlowIncrease())
                 .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_INCREASE);
+        when(displayDeviceConfigMock.getBrightnessRampSlowIncreaseIdle())
+                .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_INCREASE_IDLE);
+        when(displayDeviceConfigMock.getBrightnessRampSlowDecreaseIdle())
+                .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE_IDLE);
     }
 
     private DisplayPowerControllerHolder createDisplayPowerController(int displayId,
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
index 68bbcbc..f499ac5 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -101,6 +101,8 @@
     private static final float BRIGHTNESS_RAMP_RATE_FAST_INCREASE = 0.4f;
     private static final float BRIGHTNESS_RAMP_RATE_SLOW_DECREASE = 0.1f;
     private static final float BRIGHTNESS_RAMP_RATE_SLOW_INCREASE = 0.2f;
+    private static final float BRIGHTNESS_RAMP_RATE_SLOW_INCREASE_IDLE = 0.5f;
+    private static final float BRIGHTNESS_RAMP_RATE_SLOW_DECREASE_IDLE = 0.6f;
 
     private OffsettableClock mClock;
     private TestLooper mTestLooper;
@@ -1123,6 +1125,48 @@
         verify(mDisplayWhiteBalanceControllerMock, times(1)).setStrongModeEnabled(true);
     }
 
+    @Test
+    public void testRampRatesIdle() {
+        Settings.System.putInt(mContext.getContentResolver(),
+                Settings.System.SCREEN_BRIGHTNESS_MODE,
+                Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
+        float brightness = 0.6f;
+        when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
+        when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+        when(mHolder.automaticBrightnessController.isInIdleMode()).thenReturn(true);
+        when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness(
+                any(BrightnessEvent.class))).thenReturn(brightness);
+
+        DisplayPowerRequest dpr = new DisplayPowerRequest();
+        mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+        advanceTime(1); // Run updatePowerState
+
+        verify(mHolder.animator).animateTo(eq(brightness), anyFloat(),
+                eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE));
+
+        when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(brightness);
+        brightness = 0.05f;
+        when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness(
+                any(BrightnessEvent.class))).thenReturn(brightness);
+
+        mHolder.dpc.updateBrightness();
+        advanceTime(1); // Run updatePowerState
+
+        // The second time, the animation rate should be slow
+        verify(mHolder.animator).animateTo(eq(brightness), anyFloat(),
+                eq(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE_IDLE));
+
+        brightness = 0.9f;
+        when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness(
+                any(BrightnessEvent.class))).thenReturn(brightness);
+
+        mHolder.dpc.updateBrightness();
+        advanceTime(1); // Run updatePowerState
+        // The third time, the animation rate should be slow
+        verify(mHolder.animator).animateTo(eq(brightness), anyFloat(),
+                eq(BRIGHTNESS_RAMP_RATE_SLOW_INCREASE_IDLE));
+    }
+
     private void advanceTime(long timeMs) {
         mClock.fastForward(timeMs);
         mTestLooper.dispatchAll();
@@ -1186,6 +1230,10 @@
                 .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE);
         when(displayDeviceConfigMock.getBrightnessRampSlowIncrease())
                 .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_INCREASE);
+        when(displayDeviceConfigMock.getBrightnessRampSlowDecreaseIdle())
+                .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE_IDLE);
+        when(displayDeviceConfigMock.getBrightnessRampSlowIncreaseIdle())
+                .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_INCREASE_IDLE);
     }
 
     private DisplayPowerControllerHolder createDisplayPowerController(int displayId,
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
index 00e35ec..41af9e3 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
@@ -129,7 +129,6 @@
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Set;
 import java.util.function.Consumer;
@@ -296,19 +295,20 @@
                 DISPLAY_ID_1);
         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
 
-        ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
+        ActivityInfo activityInfo = getActivityInfo(
                 NONBLOCKED_APP_PACKAGE_NAME,
                 NONBLOCKED_APP_PACKAGE_NAME,
                 /* displayOnRemoveDevices= */ true,
                 targetDisplayCategory);
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
-                activityInfos.get(0), mAssociationInfo.getDisplayName());
-        gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
+                activityInfo, mAssociationInfo.getDisplayName());
+        gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
         return blockedAppIntent;
     }
 
 
-    private ArrayList<ActivityInfo> getActivityInfoList(
+    private ActivityInfo getActivityInfo(
             String packageName, String name, boolean displayOnRemoveDevices,
             String requiredDisplayCategory) {
         ActivityInfo activityInfo = new ActivityInfo();
@@ -318,7 +318,7 @@
                 ? FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES : FLAG_CANNOT_DISPLAY_ON_REMOTE_DEVICES;
         activityInfo.applicationInfo = mApplicationInfoMock;
         activityInfo.requiredDisplayCategory = requiredDisplayCategory;
-        return new ArrayList<>(Arrays.asList(activityInfo));
+        return activityInfo;
     }
 
     @Before
@@ -1414,14 +1414,15 @@
                 DISPLAY_ID_1);
         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
 
-        ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
+        ActivityInfo activityInfo = getActivityInfo(
                 NONBLOCKED_APP_PACKAGE_NAME,
                 NONBLOCKED_APP_PACKAGE_NAME,
                 /* displayOnRemoveDevices */ true,
                 /* targetDisplayCategory */ null);
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
-                activityInfos.get(0), mAssociationInfo.getDisplayName());
-        gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
+                activityInfo, mAssociationInfo.getDisplayName());
+        gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
 
         verify(mContext, never()).startActivityAsUser(argThat(intent ->
                 intent.filterEquals(blockedAppIntent)), any(), any());
@@ -1434,14 +1435,15 @@
                 DISPLAY_ID_1);
         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
 
-        ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
+        ActivityInfo activityInfo = getActivityInfo(
                 PERMISSION_CONTROLLER_PACKAGE_NAME,
                 PERMISSION_CONTROLLER_PACKAGE_NAME,
                 /* displayOnRemoveDevices */  false,
                 /* targetDisplayCategory */ null);
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
-                activityInfos.get(0), mAssociationInfo.getDisplayName());
-        gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
+                activityInfo, mAssociationInfo.getDisplayName());
+        gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
 
         verify(mContext).startActivityAsUser(argThat(intent ->
                 intent.filterEquals(blockedAppIntent)), any(), any());
@@ -1454,14 +1456,15 @@
                 DISPLAY_ID_1);
         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
 
-        ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
+        ActivityInfo activityInfo = getActivityInfo(
                 SETTINGS_PACKAGE_NAME,
                 SETTINGS_PACKAGE_NAME,
                 /* displayOnRemoveDevices */ true,
                 /* targetDisplayCategory */ null);
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
-                activityInfos.get(0), mAssociationInfo.getDisplayName());
-        gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
+                activityInfo, mAssociationInfo.getDisplayName());
+        gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
 
         verify(mContext).startActivityAsUser(argThat(intent ->
                 intent.filterEquals(blockedAppIntent)), any(), any());
@@ -1474,14 +1477,15 @@
                 DISPLAY_ID_1);
         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
 
-        ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
+        ActivityInfo activityInfo = getActivityInfo(
                 VENDING_PACKAGE_NAME,
                 VENDING_PACKAGE_NAME,
                 /* displayOnRemoveDevices */ true,
                 /* targetDisplayCategory */ null);
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
-                activityInfos.get(0), mAssociationInfo.getDisplayName());
-        gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
+                activityInfo, mAssociationInfo.getDisplayName());
+        gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
 
         verify(mContext).startActivityAsUser(argThat(intent ->
                 intent.filterEquals(blockedAppIntent)), any(), any());
@@ -1494,14 +1498,15 @@
                 DISPLAY_ID_1);
         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
 
-        ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
+        ActivityInfo activityInfo = getActivityInfo(
                 GOOGLE_DIALER_PACKAGE_NAME,
                 GOOGLE_DIALER_PACKAGE_NAME,
                 /* displayOnRemoveDevices */ true,
                 /* targetDisplayCategory */ null);
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
-                activityInfos.get(0), mAssociationInfo.getDisplayName());
-        gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
+                activityInfo, mAssociationInfo.getDisplayName());
+        gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
 
         verify(mContext).startActivityAsUser(argThat(intent ->
                 intent.filterEquals(blockedAppIntent)), any(), any());
@@ -1514,14 +1519,15 @@
                 DISPLAY_ID_1);
         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
 
-        ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
+        ActivityInfo activityInfo = getActivityInfo(
                 GOOGLE_MAPS_PACKAGE_NAME,
                 GOOGLE_MAPS_PACKAGE_NAME,
                 /* displayOnRemoveDevices */ true,
                 /* targetDisplayCategory */ null);
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
-                activityInfos.get(0), mAssociationInfo.getDisplayName());
-        gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
+                activityInfo, mAssociationInfo.getDisplayName());
+        gwpc.canActivityBeLaunched(activityInfo, blockedAppIntent,
+                WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false);
 
         verify(mContext).startActivityAsUser(argThat(intent ->
                 intent.filterEquals(blockedAppIntent)), any(), any());
@@ -1561,12 +1567,12 @@
         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
         GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
                 DISPLAY_ID_1);
-        ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
+        ActivityInfo activityInfo = getActivityInfo(
                 NONBLOCKED_APP_PACKAGE_NAME,
                 NONBLOCKED_APP_PACKAGE_NAME,
                 /* displayOnRemoveDevices */ true,
                 /* targetDisplayCategory */ null);
-        assertThat(gwpc.canActivityBeLaunched(activityInfos.get(0), intent,
+        assertThat(gwpc.canActivityBeLaunched(activityInfo, intent,
                 WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false))
                 .isTrue();
     }
@@ -1585,7 +1591,7 @@
         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
         GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
                 DISPLAY_ID_1);
-        ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
+        ActivityInfo activityInfo = getActivityInfo(
                 NONBLOCKED_APP_PACKAGE_NAME,
                 NONBLOCKED_APP_PACKAGE_NAME,
                 /* displayOnRemoveDevices */ true,
@@ -1597,7 +1603,7 @@
 
         // register interceptor and intercept intent
         mDeviceImpl.registerIntentInterceptor(interceptor, intentFilter);
-        assertThat(gwpc.canActivityBeLaunched(activityInfos.get(0), intent,
+        assertThat(gwpc.canActivityBeLaunched(activityInfo, intent,
                 WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false))
                 .isFalse();
         ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
@@ -1609,7 +1615,7 @@
 
         // unregister interceptor and launch activity
         mDeviceImpl.unregisterIntentInterceptor(interceptor);
-        assertThat(gwpc.canActivityBeLaunched(activityInfos.get(0), intent,
+        assertThat(gwpc.canActivityBeLaunched(activityInfo, intent,
                 WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false))
                 .isTrue();
     }
@@ -1628,7 +1634,7 @@
         addVirtualDisplay(mDeviceImpl, DISPLAY_ID_1);
         GenericWindowPolicyController gwpc = mDeviceImpl.getDisplayWindowPolicyControllerForTest(
                 DISPLAY_ID_1);
-        ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
+        ActivityInfo activityInfo = getActivityInfo(
                 NONBLOCKED_APP_PACKAGE_NAME,
                 NONBLOCKED_APP_PACKAGE_NAME,
                 /* displayOnRemoveDevices */ true,
@@ -1640,7 +1646,7 @@
         // register interceptor with different filter
         mDeviceImpl.registerIntentInterceptor(interceptor, intentFilter);
 
-        assertThat(gwpc.canActivityBeLaunched(activityInfos.get(0), intent,
+        assertThat(gwpc.canActivityBeLaunched(activityInfo, intent,
                 WindowConfiguration.WINDOWING_MODE_FULLSCREEN, DISPLAY_ID_1, /*isNewTask=*/false))
                 .isTrue();
     }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index f408ef0..f4dac2c 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -1144,6 +1144,10 @@
                 eq(UserManager.DISALLOW_ADD_CLONE_PROFILE),
                 eq(true), eq(UserHandle.SYSTEM));
 
+        verify(getServices().userManager, times(1)).setUserRestriction(
+                eq(UserManager.DISALLOW_ADD_PRIVATE_PROFILE),
+                eq(true), eq(UserHandle.SYSTEM));
+
         verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
                 MockUtils.checkIntentAction(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED),
                 MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
@@ -1422,6 +1426,10 @@
                 .setUserRestriction(eq(UserManager.DISALLOW_ADD_CLONE_PROFILE), eq(false),
                 MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
 
+        verify(getServices().userManager)
+                .setUserRestriction(eq(UserManager.DISALLOW_ADD_PRIVATE_PROFILE), eq(false),
+                MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
+
         verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM), MockUtils.checkUserRestrictions(),
                 MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM), eq(true));
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index ecd35a5..b22798e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -1174,6 +1174,24 @@
         }
     }
 
+    // Make sure the creation of a private profile fails if DISALLOW_ADD_PRIVATE_PROFILE is true.
+    @MediumTest
+    @Test
+    public void testCreateProfileForUser_disallowAddPrivateProfile() {
+        final int mainUserId = ActivityManager.getCurrentUser();
+        final UserHandle mainUserHandle = asHandle(mainUserId);
+        mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_PRIVATE_PROFILE,
+                true, mainUserHandle);
+        try {
+            UserInfo privateProfileInfo = createProfileForUser("Private",
+                    UserManager.USER_TYPE_PROFILE_PRIVATE, mainUserId);
+            assertThat(privateProfileInfo).isNull();
+        } finally {
+            mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_PRIVATE_PROFILE, false,
+                    mainUserHandle);
+        }
+    }
+
     @MediumTest
     @Test
     public void testAddRestrictedProfile() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
index a387d4a..9907bd6 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
@@ -72,6 +72,8 @@
     public void testCanDeviceOwnerChange() {
         assertFalse(UserRestrictionsUtils.canDeviceOwnerChange(UserManager.DISALLOW_RECORD_AUDIO));
         assertFalse(UserRestrictionsUtils.canDeviceOwnerChange(UserManager.DISALLOW_WALLPAPER));
+        assertFalse(UserRestrictionsUtils.canDeviceOwnerChange(
+                UserManager.DISALLOW_ADD_PRIVATE_PROFILE));
         assertTrue(UserRestrictionsUtils.canDeviceOwnerChange(UserManager.DISALLOW_ADD_USER));
         assertTrue(UserRestrictionsUtils.canDeviceOwnerChange(UserManager.DISALLOW_USER_SWITCH));
     }
@@ -83,6 +85,8 @@
                 UserManager.DISALLOW_WALLPAPER, true));
         assertFalse(UserRestrictionsUtils.canProfileOwnerChange(
                 UserManager.DISALLOW_USER_SWITCH, true));
+        assertFalse(UserRestrictionsUtils.canProfileOwnerChange(
+                UserManager.DISALLOW_ADD_PRIVATE_PROFILE, true));
         assertTrue(UserRestrictionsUtils.canProfileOwnerChange(
                 UserManager.DISALLOW_ADD_USER, true));
         assertTrue(UserRestrictionsUtils.canProfileOwnerChange(
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
index 5dfb901..30a8941 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java
@@ -44,7 +44,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.util.List;
 import java.util.Set;
 
 /**
@@ -106,7 +105,6 @@
         assertEquals(uidAmount, mDwpc.mRunningUids.size());
         assertTrue(mDwpc.mRunningUids.contains(TEST_USER_0_ID) == expectedUid0);
         assertTrue(mDwpc.mRunningUids.contains(TEST_USER_1_ID) == expectedUid1);
-
     }
 
     private ActivityRecord launchActivityOnDisplay(DisplayContent display, int uid) {
@@ -197,6 +195,11 @@
 
     @Test
     public void testCanActivityBeLaunched_requiredDisplayCategory() {
+        doReturn(null).when(mWm.mDisplayManagerInternal)
+                .getDisplayWindowPolicyController(anyInt());
+        mSecondaryDisplay = createNewDisplay();
+        assertFalse(mSecondaryDisplay.mDwpcHelper.hasController());
+
         ActivityStarter starter = new ActivityStarter(mock(ActivityStartController.class), mAtm,
                 mSupervisor, mock(ActivityStartInterceptor.class));
         final Task task = new TaskBuilder(mSupervisor).setDisplay(mSecondaryDisplay).build();
@@ -233,20 +236,14 @@
         public boolean canActivityBeLaunched(@NonNull ActivityInfo activity, Intent intent,
                 @WindowConfiguration.WindowingMode int windowingMode, int launchingFromDisplayId,
                 boolean isNewTask) {
-            return false;
+            return canContainActivity(activity, windowingMode, launchingFromDisplayId, isNewTask);
         }
 
         @Override
-        public boolean canContainActivities(@NonNull List<ActivityInfo> activities,
-                @WindowConfiguration.WindowingMode int windowingMode) {
-            final int activityCount = activities.size();
-            for (int i = 0; i < activityCount; i++) {
-                final ActivityInfo aInfo = activities.get(i);
-                if (aInfo.getComponentName().equals(DISALLOWED_ACTIVITY)) {
-                    return false;
-                }
-            }
-            return true;
+        protected boolean canContainActivity(@NonNull ActivityInfo activity,
+                @WindowConfiguration.WindowingMode int windowingMode, int launchingFromDisplayId,
+                boolean isNewTask) {
+            return !activity.getComponentName().equals(DISALLOWED_ACTIVITY);
         }
 
         @Override
diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java
index 9994002a..75b5f55 100644
--- a/telephony/java/android/telephony/satellite/SatelliteManager.java
+++ b/telephony/java/android/telephony/satellite/SatelliteManager.java
@@ -101,26 +101,26 @@
     }
 
     /**
-     * Exception from the satellite service containing the {@link SatelliteError} error code.
+     * Exception from the satellite service containing the {@link SatelliteResult} error code.
      */
     public static class SatelliteException extends Exception {
-        @SatelliteError private final int mErrorCode;
+        @SatelliteResult private final int mErrorCode;
 
         /**
          * Create a SatelliteException with a given error code.
          *
-         * @param errorCode The {@link SatelliteError}.
+         * @param errorCode The {@link SatelliteResult}.
          */
-        public SatelliteException(@SatelliteError int errorCode) {
+        public SatelliteException(@SatelliteResult int errorCode) {
             mErrorCode = errorCode;
         }
 
         /**
          * Get the error code returned from the satellite service.
          *
-         * @return The {@link SatelliteError}.
+         * @return The {@link SatelliteResult}.
          */
-        @SatelliteError public int getErrorCode() {
+        @SatelliteResult public int getErrorCode() {
             return mErrorCode;
         }
     }
@@ -185,134 +185,134 @@
     /**
      * The request was successfully processed.
      */
-    public static final int SATELLITE_ERROR_NONE = 0;
+    public static final int SATELLITE_RESULT_SUCCESS = 0;
     /**
      * A generic error which should be used only when other specific errors cannot be used.
      */
-    public static final int SATELLITE_ERROR = 1;
+    public static final int SATELLITE_RESULT_ERROR = 1;
     /**
      * Error received from the satellite server.
      */
-    public static final int SATELLITE_SERVER_ERROR = 2;
+    public static final int SATELLITE_RESULT_SERVER_ERROR = 2;
     /**
      * Error received from the vendor service. This generic error code should be used
      * only when the error cannot be mapped to other specific service error codes.
      */
-    public static final int SATELLITE_SERVICE_ERROR = 3;
+    public static final int SATELLITE_RESULT_SERVICE_ERROR = 3;
     /**
      * Error received from satellite modem. This generic error code should be used only when
      * the error cannot be mapped to other specific modem error codes.
      */
-    public static final int SATELLITE_MODEM_ERROR = 4;
+    public static final int SATELLITE_RESULT_MODEM_ERROR = 4;
     /**
      * Error received from the satellite network. This generic error code should be used only when
      * the error cannot be mapped to other specific network error codes.
      */
-    public static final int SATELLITE_NETWORK_ERROR = 5;
+    public static final int SATELLITE_RESULT_NETWORK_ERROR = 5;
     /**
      * Telephony is not in a valid state to receive requests from clients.
      */
-    public static final int SATELLITE_INVALID_TELEPHONY_STATE = 6;
+    public static final int SATELLITE_RESULT_INVALID_TELEPHONY_STATE = 6;
     /**
      * Satellite modem is not in a valid state to receive requests from clients.
      */
-    public static final int SATELLITE_INVALID_MODEM_STATE = 7;
+    public static final int SATELLITE_RESULT_INVALID_MODEM_STATE = 7;
     /**
      * Either vendor service, or modem, or Telephony framework has received a request with
      * invalid arguments from its clients.
      */
-    public static final int SATELLITE_INVALID_ARGUMENTS = 8;
+    public static final int SATELLITE_RESULT_INVALID_ARGUMENTS = 8;
     /**
      * Telephony framework failed to send a request or receive a response from the vendor service
      * or satellite modem due to internal error.
      */
-    public static final int SATELLITE_REQUEST_FAILED = 9;
+    public static final int SATELLITE_RESULT_REQUEST_FAILED = 9;
     /**
      * Radio did not start or is resetting.
      */
-    public static final int SATELLITE_RADIO_NOT_AVAILABLE = 10;
+    public static final int SATELLITE_RESULT_RADIO_NOT_AVAILABLE = 10;
     /**
      * The request is not supported by either the satellite modem or the network.
      */
-    public static final int SATELLITE_REQUEST_NOT_SUPPORTED = 11;
+    public static final int SATELLITE_RESULT_REQUEST_NOT_SUPPORTED = 11;
     /**
      * Satellite modem or network has no resources available to handle requests from clients.
      */
-    public static final int SATELLITE_NO_RESOURCES = 12;
+    public static final int SATELLITE_RESULT_NO_RESOURCES = 12;
     /**
      * Satellite service is not provisioned yet.
      */
-    public static final int SATELLITE_SERVICE_NOT_PROVISIONED = 13;
+    public static final int SATELLITE_RESULT_SERVICE_NOT_PROVISIONED = 13;
     /**
      * Satellite service provision is already in progress.
      */
-    public static final int SATELLITE_SERVICE_PROVISION_IN_PROGRESS = 14;
+    public static final int SATELLITE_RESULT_SERVICE_PROVISION_IN_PROGRESS = 14;
     /**
      * The ongoing request was aborted by either the satellite modem or the network.
      * This error is also returned when framework decides to abort current send request as one
      * of the previous send request failed.
      */
-    public static final int SATELLITE_REQUEST_ABORTED = 15;
+    public static final int SATELLITE_RESULT_REQUEST_ABORTED = 15;
     /**
      * The device/subscriber is barred from accessing the satellite service.
      */
-    public static final int SATELLITE_ACCESS_BARRED = 16;
+    public static final int SATELLITE_RESULT_ACCESS_BARRED = 16;
     /**
      * Satellite modem timeout to receive ACK or response from the satellite network after
      * sending a request to the network.
      */
-    public static final int SATELLITE_NETWORK_TIMEOUT = 17;
+    public static final int SATELLITE_RESULT_NETWORK_TIMEOUT = 17;
     /**
      * Satellite network is not reachable from the modem.
      */
-    public static final int SATELLITE_NOT_REACHABLE = 18;
+    public static final int SATELLITE_RESULT_NOT_REACHABLE = 18;
     /**
      * The device/subscriber is not authorized to register with the satellite service provider.
      */
-    public static final int SATELLITE_NOT_AUTHORIZED = 19;
+    public static final int SATELLITE_RESULT_NOT_AUTHORIZED = 19;
     /**
      * The device does not support satellite.
      */
-    public static final int SATELLITE_NOT_SUPPORTED = 20;
+    public static final int SATELLITE_RESULT_NOT_SUPPORTED = 20;
 
     /**
      * The current request is already in-progress.
      */
-    public static final int SATELLITE_REQUEST_IN_PROGRESS = 21;
+    public static final int SATELLITE_RESULT_REQUEST_IN_PROGRESS = 21;
 
     /**
      * Satellite modem is currently busy due to which current request cannot be processed.
      */
-    public static final int SATELLITE_MODEM_BUSY = 22;
+    public static final int SATELLITE_RESULT_MODEM_BUSY = 22;
 
     /** @hide */
-    @IntDef(prefix = {"SATELLITE_"}, value = {
-            SATELLITE_ERROR_NONE,
-            SATELLITE_ERROR,
-            SATELLITE_SERVER_ERROR,
-            SATELLITE_SERVICE_ERROR,
-            SATELLITE_MODEM_ERROR,
-            SATELLITE_NETWORK_ERROR,
-            SATELLITE_INVALID_TELEPHONY_STATE,
-            SATELLITE_INVALID_MODEM_STATE,
-            SATELLITE_INVALID_ARGUMENTS,
-            SATELLITE_REQUEST_FAILED,
-            SATELLITE_RADIO_NOT_AVAILABLE,
-            SATELLITE_REQUEST_NOT_SUPPORTED,
-            SATELLITE_NO_RESOURCES,
-            SATELLITE_SERVICE_NOT_PROVISIONED,
-            SATELLITE_SERVICE_PROVISION_IN_PROGRESS,
-            SATELLITE_REQUEST_ABORTED,
-            SATELLITE_ACCESS_BARRED,
-            SATELLITE_NETWORK_TIMEOUT,
-            SATELLITE_NOT_REACHABLE,
-            SATELLITE_NOT_AUTHORIZED,
-            SATELLITE_NOT_SUPPORTED,
-            SATELLITE_REQUEST_IN_PROGRESS,
-            SATELLITE_MODEM_BUSY
+    @IntDef(prefix = {"SATELLITE_RESULT_"}, value = {
+            SATELLITE_RESULT_SUCCESS,
+            SATELLITE_RESULT_ERROR,
+            SATELLITE_RESULT_SERVER_ERROR,
+            SATELLITE_RESULT_SERVICE_ERROR,
+            SATELLITE_RESULT_MODEM_ERROR,
+            SATELLITE_RESULT_NETWORK_ERROR,
+            SATELLITE_RESULT_INVALID_TELEPHONY_STATE,
+            SATELLITE_RESULT_INVALID_MODEM_STATE,
+            SATELLITE_RESULT_INVALID_ARGUMENTS,
+            SATELLITE_RESULT_REQUEST_FAILED,
+            SATELLITE_RESULT_RADIO_NOT_AVAILABLE,
+            SATELLITE_RESULT_REQUEST_NOT_SUPPORTED,
+            SATELLITE_RESULT_NO_RESOURCES,
+            SATELLITE_RESULT_SERVICE_NOT_PROVISIONED,
+            SATELLITE_RESULT_SERVICE_PROVISION_IN_PROGRESS,
+            SATELLITE_RESULT_REQUEST_ABORTED,
+            SATELLITE_RESULT_ACCESS_BARRED,
+            SATELLITE_RESULT_NETWORK_TIMEOUT,
+            SATELLITE_RESULT_NOT_REACHABLE,
+            SATELLITE_RESULT_NOT_AUTHORIZED,
+            SATELLITE_RESULT_NOT_SUPPORTED,
+            SATELLITE_RESULT_REQUEST_IN_PROGRESS,
+            SATELLITE_RESULT_MODEM_BUSY
     })
     @Retention(RetentionPolicy.SOURCE)
-    public @interface SatelliteError {}
+    public @interface SatelliteResult {}
 
     /**
      * Unknown Non-Terrestrial radio technology. This generic radio technology should be used
@@ -403,7 +403,7 @@
      *                        {@code false} to disable.
      * @param enableDemoMode {@code true} to enable demo mode and {@code false} to disable.
      * @param executor The executor on which the error code listener will be called.
-     * @param resultListener Listener for the {@link SatelliteError} result of the operation.
+     * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
@@ -412,7 +412,7 @@
 
     public void requestSatelliteEnabled(boolean enableSatellite, boolean enableDemoMode,
             @NonNull @CallbackExecutor Executor executor,
-            @SatelliteError @NonNull Consumer<Integer> resultListener) {
+            @SatelliteResult @NonNull Consumer<Integer> resultListener) {
         Objects.requireNonNull(executor);
         Objects.requireNonNull(resultListener);
 
@@ -446,7 +446,7 @@
      *                 will return a {@code boolean} with value {@code true} if the satellite modem
      *                 is enabled and {@code false} otherwise.
      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
-     *                 will return a {@link SatelliteException} with the {@link SatelliteError}.
+     *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
@@ -464,7 +464,7 @@
                 ResultReceiver receiver = new ResultReceiver(null) {
                     @Override
                     protected void onReceiveResult(int resultCode, Bundle resultData) {
-                        if (resultCode == SATELLITE_ERROR_NONE) {
+                        if (resultCode == SATELLITE_RESULT_SUCCESS) {
                             if (resultData.containsKey(KEY_SATELLITE_ENABLED)) {
                                 boolean isSatelliteEnabled =
                                         resultData.getBoolean(KEY_SATELLITE_ENABLED);
@@ -473,8 +473,8 @@
                             } else {
                                 loge("KEY_SATELLITE_ENABLED does not exist.");
                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
-                                        callback.onError(
-                                                new SatelliteException(SATELLITE_REQUEST_FAILED))));
+                                        callback.onError(new SatelliteException(
+                                                SATELLITE_RESULT_REQUEST_FAILED))));
                             }
                         } else {
                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
@@ -501,7 +501,7 @@
      *                 will return a {@code boolean} with value {@code true} if demo mode is enabled
      *                 and {@code false} otherwise.
      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
-     *                 will return a {@link SatelliteException} with the {@link SatelliteError}.
+     *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
@@ -519,7 +519,7 @@
                 ResultReceiver receiver = new ResultReceiver(null) {
                     @Override
                     protected void onReceiveResult(int resultCode, Bundle resultData) {
-                        if (resultCode == SATELLITE_ERROR_NONE) {
+                        if (resultCode == SATELLITE_RESULT_SUCCESS) {
                             if (resultData.containsKey(KEY_DEMO_MODE_ENABLED)) {
                                 boolean isDemoModeEnabled =
                                         resultData.getBoolean(KEY_DEMO_MODE_ENABLED);
@@ -528,8 +528,8 @@
                             } else {
                                 loge("KEY_DEMO_MODE_ENABLED does not exist.");
                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
-                                        callback.onError(
-                                                new SatelliteException(SATELLITE_REQUEST_FAILED))));
+                                        callback.onError(new SatelliteException(
+                                                SATELLITE_RESULT_REQUEST_FAILED))));
                             }
                         } else {
                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
@@ -556,7 +556,7 @@
      *                 will return a {@code boolean} with value {@code true} if the satellite
      *                 service is supported on the device and {@code false} otherwise.
      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
-     *                 will return a {@link SatelliteException} with the {@link SatelliteError}.
+     *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
      *
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
@@ -572,7 +572,7 @@
                 ResultReceiver receiver = new ResultReceiver(null) {
                     @Override
                     protected void onReceiveResult(int resultCode, Bundle resultData) {
-                        if (resultCode == SATELLITE_ERROR_NONE) {
+                        if (resultCode == SATELLITE_RESULT_SUCCESS) {
                             if (resultData.containsKey(KEY_SATELLITE_SUPPORTED)) {
                                 boolean isSatelliteSupported =
                                         resultData.getBoolean(KEY_SATELLITE_SUPPORTED);
@@ -581,8 +581,8 @@
                             } else {
                                 loge("KEY_SATELLITE_SUPPORTED does not exist.");
                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
-                                        callback.onError(
-                                                new SatelliteException(SATELLITE_REQUEST_FAILED))));
+                                        callback.onError(new SatelliteException(
+                                                SATELLITE_RESULT_REQUEST_FAILED))));
                             }
                         } else {
                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
@@ -608,7 +608,7 @@
      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
      *                 will return the {@link SatelliteCapabilities} of the satellite service.
      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
-     *                 will return a {@link SatelliteException} with the {@link SatelliteError}.
+     *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
@@ -626,7 +626,7 @@
                 ResultReceiver receiver = new ResultReceiver(null) {
                     @Override
                     protected void onReceiveResult(int resultCode, Bundle resultData) {
-                        if (resultCode == SATELLITE_ERROR_NONE) {
+                        if (resultCode == SATELLITE_RESULT_SUCCESS) {
                             if (resultData.containsKey(KEY_SATELLITE_CAPABILITIES)) {
                                 SatelliteCapabilities capabilities =
                                         resultData.getParcelable(KEY_SATELLITE_CAPABILITIES,
@@ -636,8 +636,8 @@
                             } else {
                                 loge("KEY_SATELLITE_CAPABILITIES does not exist.");
                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
-                                        callback.onError(
-                                                new SatelliteException(SATELLITE_REQUEST_FAILED))));
+                                        callback.onError(new SatelliteException(
+                                                SATELLITE_RESULT_REQUEST_FAILED))));
                             }
                         } else {
                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
@@ -794,13 +794,13 @@
      * Start receiving satellite transmission updates.
      * This can be called by the pointing UI when the user starts pointing to the satellite.
      * Modem should continue to report the pointing input as the device or satellite moves.
-     * Satellite transmission updates are started only on {@link #SATELLITE_ERROR_NONE}.
+     * Satellite transmission updates are started only on {@link #SATELLITE_RESULT_SUCCESS}.
      * All other results indicate that this operation failed.
      * Once satellite transmission updates begin, position and datagram transfer state updates
      * will be sent through {@link SatelliteTransmissionUpdateCallback}.
      *
      * @param executor The executor on which the callback and error code listener will be called.
-     * @param resultListener Listener for the {@link SatelliteError} result of the operation.
+     * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
      * @param callback The callback to notify of satellite transmission updates.
      *
      * @throws SecurityException if the caller doesn't have required permission.
@@ -809,7 +809,7 @@
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
 
     public void startSatelliteTransmissionUpdates(@NonNull @CallbackExecutor Executor executor,
-            @SatelliteError @NonNull Consumer<Integer> resultListener,
+            @SatelliteResult @NonNull Consumer<Integer> resultListener,
             @NonNull SatelliteTransmissionUpdateCallback callback) {
         Objects.requireNonNull(executor);
         Objects.requireNonNull(resultListener);
@@ -866,12 +866,12 @@
      * Stop receiving satellite transmission updates.
      * This can be called by the pointing UI when the user stops pointing to the satellite.
      * Satellite transmission updates are stopped and the callback is unregistered only on
-     * {@link #SATELLITE_ERROR_NONE}. All other results that this operation failed.
+     * {@link #SATELLITE_RESULT_SUCCESS}. All other results that this operation failed.
      *
      * @param callback The callback that was passed to {@link
      * #startSatelliteTransmissionUpdates(Executor, Consumer, SatelliteTransmissionUpdateCallback)}.
      * @param executor The executor on which the error code listener will be called.
-     * @param resultListener Listener for the {@link SatelliteError} result of the operation.
+     * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
@@ -881,7 +881,7 @@
     public void stopSatelliteTransmissionUpdates(
             @NonNull SatelliteTransmissionUpdateCallback callback,
             @NonNull @CallbackExecutor Executor executor,
-            @SatelliteError @NonNull Consumer<Integer> resultListener) {
+            @SatelliteResult @NonNull Consumer<Integer> resultListener) {
         Objects.requireNonNull(callback);
         Objects.requireNonNull(executor);
         Objects.requireNonNull(resultListener);
@@ -905,7 +905,7 @@
                 } else {
                     loge("stopSatelliteTransmissionUpdates: No internal callback.");
                     executor.execute(() -> Binder.withCleanCallingIdentity(
-                            () -> resultListener.accept(SATELLITE_INVALID_ARGUMENTS)));
+                            () -> resultListener.accept(SATELLITE_RESULT_INVALID_ARGUMENTS)));
                 }
             } else {
                 throw new IllegalStateException("telephony service is null.");
@@ -927,7 +927,7 @@
      *                           request. Even when the cancellation is signaled, Telephony will
      *                           still trigger the callback to return the result of this request.
      * @param executor The executor on which the error code listener will be called.
-     * @param resultListener Listener for the {@link SatelliteError} result of the operation.
+     * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
@@ -937,7 +937,7 @@
     public void provisionSatelliteService(@NonNull String token, @NonNull byte[] provisionData,
             @Nullable CancellationSignal cancellationSignal,
             @NonNull @CallbackExecutor Executor executor,
-            @SatelliteError @NonNull Consumer<Integer> resultListener) {
+            @SatelliteResult @NonNull Consumer<Integer> resultListener) {
         Objects.requireNonNull(token);
         Objects.requireNonNull(executor);
         Objects.requireNonNull(resultListener);
@@ -980,7 +980,7 @@
      *              This should match with the token passed as input in
      *              {@link #provisionSatelliteService(String, byte[], CancellationSignal, Executor,
      *              Consumer)}
-     * @param resultListener Listener for the {@link SatelliteError} result of the operation.
+     * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
@@ -989,7 +989,7 @@
 
     public void deprovisionSatelliteService(@NonNull String token,
             @NonNull @CallbackExecutor Executor executor,
-            @SatelliteError @NonNull Consumer<Integer> resultListener) {
+            @SatelliteResult @NonNull Consumer<Integer> resultListener) {
         Objects.requireNonNull(token);
         Objects.requireNonNull(executor);
         Objects.requireNonNull(resultListener);
@@ -1020,14 +1020,14 @@
      * @param executor The executor on which the callback will be called.
      * @param callback The callback to handle the satellite provision state changed event.
      *
-     * @return The {@link SatelliteError} result of the operation.
+     * @return The {@link SatelliteResult} result of the operation.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
 
-    @SatelliteError public int registerForSatelliteProvisionStateChanged(
+    @SatelliteResult public int registerForSatelliteProvisionStateChanged(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull SatelliteProvisionStateCallback callback) {
         Objects.requireNonNull(executor);
@@ -1055,7 +1055,7 @@
             loge("registerForSatelliteProvisionStateChanged() RemoteException: " + ex);
             ex.rethrowFromSystemServer();
         }
-        return SATELLITE_REQUEST_FAILED;
+        return SATELLITE_RESULT_REQUEST_FAILED;
     }
 
     /**
@@ -1102,7 +1102,7 @@
      *                 will return a {@code boolean} with value {@code true} if the device is
      *                 provisioned with a satellite provider and {@code false} otherwise.
      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
-     *                 will return a {@link SatelliteException} with the {@link SatelliteError}.
+     *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
@@ -1120,7 +1120,7 @@
                 ResultReceiver receiver = new ResultReceiver(null) {
                     @Override
                     protected void onReceiveResult(int resultCode, Bundle resultData) {
-                        if (resultCode == SATELLITE_ERROR_NONE) {
+                        if (resultCode == SATELLITE_RESULT_SUCCESS) {
                             if (resultData.containsKey(KEY_SATELLITE_PROVISIONED)) {
                                 boolean isSatelliteProvisioned =
                                         resultData.getBoolean(KEY_SATELLITE_PROVISIONED);
@@ -1129,8 +1129,8 @@
                             } else {
                                 loge("KEY_SATELLITE_PROVISIONED does not exist.");
                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
-                                        callback.onError(
-                                                new SatelliteException(SATELLITE_REQUEST_FAILED))));
+                                        callback.onError(new SatelliteException(
+                                                SATELLITE_RESULT_REQUEST_FAILED))));
                             }
                         } else {
                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
@@ -1154,14 +1154,14 @@
      * @param executor The executor on which the callback will be called.
      * @param callback The callback to handle the satellite modem state changed event.
      *
-     * @return The {@link SatelliteError} result of the operation.
+     * @return The {@link SatelliteResult} result of the operation.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
 
-    @SatelliteError public int registerForSatelliteModemStateChanged(
+    @SatelliteResult public int registerForSatelliteModemStateChanged(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull SatelliteStateCallback callback) {
         Objects.requireNonNull(executor);
@@ -1186,7 +1186,7 @@
             loge("registerForSatelliteModemStateChanged() RemoteException:" + ex);
             ex.rethrowFromSystemServer();
         }
-        return SATELLITE_REQUEST_FAILED;
+        return SATELLITE_RESULT_REQUEST_FAILED;
     }
 
     /**
@@ -1232,14 +1232,14 @@
      * @param callback The callback to handle incoming datagrams over satellite.
      *                 This callback with be invoked when a new datagram is received from satellite.
      *
-     * @return The {@link SatelliteError} result of the operation.
+     * @return The {@link SatelliteResult} result of the operation.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
      */
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
 
-    @SatelliteError public int registerForSatelliteDatagram(
+    @SatelliteResult public int registerForSatelliteDatagram(
             @NonNull @CallbackExecutor Executor executor,
             @NonNull SatelliteDatagramCallback callback) {
         Objects.requireNonNull(executor);
@@ -1280,7 +1280,7 @@
             loge("registerForSatelliteDatagram() RemoteException:" + ex);
             ex.rethrowFromSystemServer();
         }
-        return SATELLITE_REQUEST_FAILED;
+        return SATELLITE_RESULT_REQUEST_FAILED;
     }
 
     /**
@@ -1327,7 +1327,7 @@
      * Consumer)} )}
      *
      * @param executor The executor on which the result listener will be called.
-     * @param resultListener Listener for the {@link SatelliteError} result of the operation.
+     * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
@@ -1335,7 +1335,7 @@
     @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION)
 
     public void pollPendingSatelliteDatagrams(@NonNull @CallbackExecutor Executor executor,
-            @SatelliteError @NonNull Consumer<Integer> resultListener) {
+            @SatelliteResult @NonNull Consumer<Integer> resultListener) {
         Objects.requireNonNull(executor);
         Objects.requireNonNull(resultListener);
 
@@ -1380,7 +1380,7 @@
      *                                 user activity and the application's ability to determine the
      *                                 best possible UX experience for the user.
      * @param executor The executor on which the result listener will be called.
-     * @param resultListener Listener for the {@link SatelliteError} result of the operation.
+     * @param resultListener Listener for the {@link SatelliteResult} result of the operation.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
@@ -1390,7 +1390,7 @@
     public void sendSatelliteDatagram(@DatagramType int datagramType,
             @NonNull SatelliteDatagram datagram, boolean needFullScreenPointingUI,
             @NonNull @CallbackExecutor Executor executor,
-            @SatelliteError @NonNull Consumer<Integer> resultListener) {
+            @SatelliteResult @NonNull Consumer<Integer> resultListener) {
         Objects.requireNonNull(datagram);
         Objects.requireNonNull(executor);
         Objects.requireNonNull(resultListener);
@@ -1426,7 +1426,7 @@
      *                 communication is allowed for the current location and
      *                 {@code false} otherwise.
      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
-     *                 will return a {@link SatelliteException} with the {@link SatelliteError}.
+     *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
@@ -1445,7 +1445,7 @@
                 ResultReceiver receiver = new ResultReceiver(null) {
                     @Override
                     protected void onReceiveResult(int resultCode, Bundle resultData) {
-                        if (resultCode == SATELLITE_ERROR_NONE) {
+                        if (resultCode == SATELLITE_RESULT_SUCCESS) {
                             if (resultData.containsKey(KEY_SATELLITE_COMMUNICATION_ALLOWED)) {
                                 boolean isSatelliteCommunicationAllowed =
                                         resultData.getBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED);
@@ -1454,8 +1454,8 @@
                             } else {
                                 loge("KEY_SATELLITE_COMMUNICATION_ALLOWED does not exist.");
                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
-                                        callback.onError(
-                                                new SatelliteException(SATELLITE_REQUEST_FAILED))));
+                                        callback.onError(new SatelliteException(
+                                                SATELLITE_RESULT_REQUEST_FAILED))));
                             }
                         } else {
                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
@@ -1484,7 +1484,7 @@
      *                 If the request is successful, {@link OutcomeReceiver#onResult(Object)}
      *                 will return the time after which the satellite will be visible.
      *                 If the request is not successful, {@link OutcomeReceiver#onError(Throwable)}
-     *                 will return a {@link SatelliteException} with the {@link SatelliteError}.
+     *                 will return a {@link SatelliteException} with the {@link SatelliteResult}.
      *
      * @throws SecurityException if the caller doesn't have required permission.
      * @throws IllegalStateException if the Telephony process is not currently available.
@@ -1502,7 +1502,7 @@
                 ResultReceiver receiver = new ResultReceiver(null) {
                     @Override
                     protected void onReceiveResult(int resultCode, Bundle resultData) {
-                        if (resultCode == SATELLITE_ERROR_NONE) {
+                        if (resultCode == SATELLITE_RESULT_SUCCESS) {
                             if (resultData.containsKey(KEY_SATELLITE_NEXT_VISIBILITY)) {
                                 int nextVisibilityDuration =
                                         resultData.getInt(KEY_SATELLITE_NEXT_VISIBILITY);
@@ -1512,8 +1512,8 @@
                             } else {
                                 loge("KEY_SATELLITE_NEXT_VISIBILITY does not exist.");
                                 executor.execute(() -> Binder.withCleanCallingIdentity(() ->
-                                        callback.onError(
-                                                new SatelliteException(SATELLITE_REQUEST_FAILED))));
+                                        callback.onError(new SatelliteException(
+                                                SATELLITE_RESULT_REQUEST_FAILED))));
                             }
                         } else {
                             executor.execute(() -> Binder.withCleanCallingIdentity(() ->
diff --git a/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java b/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java
index d7d892a..7ac06b0 100644
--- a/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java
+++ b/telephony/java/android/telephony/satellite/SatelliteTransmissionUpdateCallback.java
@@ -43,7 +43,7 @@
      */
     void onSendDatagramStateChanged(
             @SatelliteManager.SatelliteDatagramTransferState int state, int sendPendingCount,
-            @SatelliteManager.SatelliteError int errorCode);
+            @SatelliteManager.SatelliteResult int errorCode);
 
     /**
      * Called when satellite datagram receive state changed.
@@ -54,5 +54,5 @@
      */
     void onReceiveDatagramStateChanged(
             @SatelliteManager.SatelliteDatagramTransferState int state, int receivePendingCount,
-            @SatelliteManager.SatelliteError int errorCode);
+            @SatelliteManager.SatelliteResult int errorCode);
 }
diff --git a/telephony/java/android/telephony/satellite/stub/ISatelliteListener.aidl b/telephony/java/android/telephony/satellite/stub/ISatelliteListener.aidl
index 5e69215..d687162 100644
--- a/telephony/java/android/telephony/satellite/stub/ISatelliteListener.aidl
+++ b/telephony/java/android/telephony/satellite/stub/ISatelliteListener.aidl
@@ -19,7 +19,6 @@
 import android.telephony.satellite.stub.NTRadioTechnology;
 import android.telephony.satellite.stub.PointingInfo;
 import android.telephony.satellite.stub.SatelliteDatagram;
-import android.telephony.satellite.stub.SatelliteError;
 import android.telephony.satellite.stub.SatelliteModemState;
 
 /**
diff --git a/telephony/java/android/telephony/satellite/stub/SatelliteError.aidl b/telephony/java/android/telephony/satellite/stub/SatelliteResult.aidl
similarity index 77%
rename from telephony/java/android/telephony/satellite/stub/SatelliteError.aidl
rename to telephony/java/android/telephony/satellite/stub/SatelliteResult.aidl
index 6a110a9..639b483 100644
--- a/telephony/java/android/telephony/satellite/stub/SatelliteError.aidl
+++ b/telephony/java/android/telephony/satellite/stub/SatelliteResult.aidl
@@ -20,91 +20,87 @@
  * {@hide}
  */
 @Backing(type="int")
-enum SatelliteError {
+enum SatelliteResult {
     /**
      * The request was successfully processed.
      */
-    ERROR_NONE = 0,
+    SATELLITE_RESULT_SUCCESS = 0,
     /**
      * A generic error which should be used only when other specific errors cannot be used.
      */
-    SATELLITE_ERROR = 1,
+    SATELLITE_RESULT_ERROR = 1,
     /**
      * Error received from the satellite server.
      */
-    SERVER_ERROR = 2,
+    SATELLITE_RESULT_SERVER_ERROR = 2,
     /**
      * Error received from the vendor service. This generic error code should be used
      * only when the error cannot be mapped to other specific service error codes.
      */
-    SERVICE_ERROR = 3,
+    SATELLITE_RESULT_SERVICE_ERROR = 3,
     /**
      * Error received from satellite modem. This generic error code should be used only when
      * the error cannot be mapped to other specific modem error codes.
      */
-    MODEM_ERROR = 4,
+    SATELLITE_RESULT_MODEM_ERROR = 4,
     /**
      * Error received from the satellite network. This generic error code should be used only when
      * the error cannot be mapped to other specific network error codes.
      */
-    NETWORK_ERROR = 5,
-    /**
-     * Telephony is not in a valid state to receive requests from clients.
-     */
-    INVALID_TELEPHONY_STATE = 6,
+    SATELLITE_RESULT_NETWORK_ERROR = 5,
     /**
      * Satellite modem is not in a valid state to receive requests from clients.
      */
-    INVALID_MODEM_STATE = 7,
+    SATELLITE_RESULT_INVALID_MODEM_STATE = 6,
     /**
      * Either vendor service, or modem, or Telephony framework has received a request with
      * invalid arguments from its clients.
      */
-    INVALID_ARGUMENTS = 8,
+    SATELLITE_RESULT_INVALID_ARGUMENTS = 7,
     /**
      * Telephony framework failed to send a request or receive a response from the vendor service
      * or satellite modem due to internal error.
      */
-    REQUEST_FAILED = 9,
+    SATELLITE_RESULT_REQUEST_FAILED = 8,
     /**
      * Radio did not start or is resetting.
      */
-    RADIO_NOT_AVAILABLE = 10,
+    SATELLITE_RESULT_RADIO_NOT_AVAILABLE = 9,
     /**
      * The request is not supported by either the satellite modem or the network.
      */
-    REQUEST_NOT_SUPPORTED = 11,
+    SATELLITE_RESULT_REQUEST_NOT_SUPPORTED = 10,
     /**
      * Satellite modem or network has no resources available to handle requests from clients.
      */
-    NO_RESOURCES = 12,
+    SATELLITE_RESULT_NO_RESOURCES = 11,
     /**
      * Satellite service is not provisioned yet.
      */
-    SERVICE_NOT_PROVISIONED = 13,
+    SATELLITE_RESULT_SERVICE_NOT_PROVISIONED = 12,
     /**
      * Satellite service provision is already in progress.
      */
-    SERVICE_PROVISION_IN_PROGRESS = 14,
+    SATELLITE_RESULT_SERVICE_PROVISION_IN_PROGRESS = 13,
     /**
      * The ongoing request was aborted by either the satellite modem or the network.
      */
-    REQUEST_ABORTED = 15,
+    SATELLITE_RESULT_REQUEST_ABORTED = 14,
     /**
      * The device/subscriber is barred from accessing the satellite service.
      */
-    SATELLITE_ACCESS_BARRED = 16,
+    SATELLITE_RESULT_ACCESS_BARRED = 15,
     /**
      * Satellite modem timeout to receive ACK or response from the satellite network after
      * sending a request to the network.
      */
-    NETWORK_TIMEOUT = 17,
+    SATELLITE_RESULT_NETWORK_TIMEOUT = 16,
     /**
      * Satellite network is not reachable from the modem.
      */
-    SATELLITE_NOT_REACHABLE = 18,
+    SATELLITE_RESULT_NOT_REACHABLE = 17,
     /**
      * The device/subscriber is not authorized to register with the satellite service provider.
      */
-    NOT_AUTHORIZED = 19
+    SATELLITE_RESULT_NOT_AUTHORIZED = 18
 }